From 5ce0d9c3e04f0fb8a1adac51849e0e76cc57054a Mon Sep 17 00:00:00 2001 From: David Williams Date: Sun, 10 May 2015 19:43:09 +0200 Subject: [PATCH 01/61] Cutting down and simplifying Marching Cubes code (also now slower...). --- .../PolyVox/MarchingCubesSurfaceExtractor.h | 2 +- .../PolyVox/MarchingCubesSurfaceExtractor.inl | 265 +++--------------- 2 files changed, 33 insertions(+), 234 deletions(-) diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.h b/include/PolyVox/MarchingCubesSurfaceExtractor.h index efc6eebf..c542fd39 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.h +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.h @@ -325,7 +325,7 @@ namespace PolyVox // // 1. It leaves the user in control of memory allocation and would allow them to implement e.g. a mesh pooling system. // 2. The user-provided mesh could have a different index type (e.g. 16-bit indices) to reduce memory usage. - // 3. The user could provide a custom mesh class, e.g a thin wrapper around an openGL VBO to allow direct writing into this structure. + // 3. The user could provide a custom mesh class, e.g a thin wrapper around an OpenGL VBO to allow direct writing into this structure. // // We don't provide a default MeshType here. If the user doesn't want to provide a MeshType then it probably makes // more sense to use the other variant of this function where the mesh is a return value rather than a parameter. diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.inl b/include/PolyVox/MarchingCubesSurfaceExtractor.inl index cef3ea13..dbe9a1ea 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.inl +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.inl @@ -145,254 +145,53 @@ namespace PolyVox uint32_t uXRegSpace = iXVolSpace - m_regSizeInVoxels.getLowerX(); uint32_t uYRegSpace = iYVolSpace - m_regSizeInVoxels.getLowerY(); - - m_sampVolume.setPosition(iXVolSpace,iYVolSpace,iZVolSpace); - computeBitmaskForCell(pPreviousBitmask, pCurrentBitmask, uXRegSpace, uYRegSpace); - - //Process the edge where x is minimal. - iXVolSpace = m_regSliceCurrent.getLowerX(); - m_sampVolume.setPosition(iXVolSpace, m_regSliceCurrent.getLowerY(), iZVolSpace); - for(iYVolSpace = m_regSliceCurrent.getLowerY() + 1; iYVolSpace <= iMaxYVolSpace; iYVolSpace++) - { - uXRegSpace = iXVolSpace - m_regSizeInVoxels.getLowerX(); - uYRegSpace = iYVolSpace - m_regSizeInVoxels.getLowerY(); - - m_sampVolume.movePositiveY(); - - computeBitmaskForCell(pPreviousBitmask, pCurrentBitmask, uXRegSpace, uYRegSpace); - } - - //Process the edge where y is minimal. - iYVolSpace = m_regSliceCurrent.getLowerY(); - m_sampVolume.setPosition(m_regSliceCurrent.getLowerX(), iYVolSpace, iZVolSpace); - for(iXVolSpace = m_regSliceCurrent.getLowerX() + 1; iXVolSpace <= iMaxXVolSpace; iXVolSpace++) - { - uXRegSpace = iXVolSpace - m_regSizeInVoxels.getLowerX(); - uYRegSpace = iYVolSpace - m_regSizeInVoxels.getLowerY(); - - m_sampVolume.movePositiveX(); - - computeBitmaskForCell(pPreviousBitmask, pCurrentBitmask, uXRegSpace, uYRegSpace); - } - //Process all remaining elemnents of the slice. In this case, previous x and y values are always available - for(iYVolSpace = m_regSliceCurrent.getLowerY() + 1; iYVolSpace <= iMaxYVolSpace; iYVolSpace++) + for(iYVolSpace = m_regSliceCurrent.getLowerY(); iYVolSpace <= iMaxYVolSpace; iYVolSpace++) { m_sampVolume.setPosition(m_regSliceCurrent.getLowerX(), iYVolSpace, iZVolSpace); - for(iXVolSpace = m_regSliceCurrent.getLowerX() + 1; iXVolSpace <= iMaxXVolSpace; iXVolSpace++) + for(iXVolSpace = m_regSliceCurrent.getLowerX(); iXVolSpace <= iMaxXVolSpace; iXVolSpace++) { uXRegSpace = iXVolSpace - m_regSizeInVoxels.getLowerX(); uYRegSpace = iYVolSpace - m_regSizeInVoxels.getLowerY(); m_sampVolume.movePositiveX(); - computeBitmaskForCell(pPreviousBitmask, pCurrentBitmask, uXRegSpace, uYRegSpace); + m_sampVolume.setPosition(iXVolSpace, iYVolSpace, iZVolSpace); + + uint8_t iCubeIndex = 0; + + typename VolumeType::VoxelType v000 = m_sampVolume.getVoxel(); + typename VolumeType::VoxelType v100 = m_sampVolume.peekVoxel1px0py0pz(); + typename VolumeType::VoxelType v010 = m_sampVolume.peekVoxel0px1py0pz(); + typename VolumeType::VoxelType v110 = m_sampVolume.peekVoxel1px1py0pz(); + + typename VolumeType::VoxelType v001 = m_sampVolume.peekVoxel0px0py1pz(); + typename VolumeType::VoxelType v101 = m_sampVolume.peekVoxel1px0py1pz(); + typename VolumeType::VoxelType v011 = m_sampVolume.peekVoxel0px1py1pz(); + typename VolumeType::VoxelType v111 = m_sampVolume.peekVoxel1px1py1pz(); + + if (m_controller.convertToDensity(v000) < m_tThreshold) iCubeIndex |= 1; + if (m_controller.convertToDensity(v100) < m_tThreshold) iCubeIndex |= 2; + if (m_controller.convertToDensity(v010) < m_tThreshold) iCubeIndex |= 4; + if (m_controller.convertToDensity(v110) < m_tThreshold) iCubeIndex |= 8; + if (m_controller.convertToDensity(v001) < m_tThreshold) iCubeIndex |= 16; + if (m_controller.convertToDensity(v101) < m_tThreshold) iCubeIndex |= 32; + if (m_controller.convertToDensity(v011) < m_tThreshold) iCubeIndex |= 64; + if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128; + + //Save the bitmask + pCurrentBitmask(uXRegSpace, uYRegSpace) = iCubeIndex; + + if (edgeTable[iCubeIndex] != 0) + { + ++m_uNoOfOccupiedCells; + } } } return m_uNoOfOccupiedCells; } - template - template - void MarchingCubesSurfaceExtractor::computeBitmaskForCell(const Array2DUint8& pPreviousBitmask, Array2DUint8& pCurrentBitmask, uint32_t uXRegSpace, uint32_t uYRegSpace) - { - uint8_t iCubeIndex = 0; - - typename VolumeType::VoxelType v000; - typename VolumeType::VoxelType v100; - typename VolumeType::VoxelType v010; - typename VolumeType::VoxelType v110; - typename VolumeType::VoxelType v001; - typename VolumeType::VoxelType v101; - typename VolumeType::VoxelType v011; - typename VolumeType::VoxelType v111; - - if(isPrevZAvail) - { - if(isPrevYAvail) - { - if(isPrevXAvail) - { - v111 = m_sampVolume.peekVoxel1px1py1pz(); - - //z - uint8_t iPreviousCubeIndexZ = pPreviousBitmask(uXRegSpace, uYRegSpace); - iPreviousCubeIndexZ >>= 4; - - //y - uint8_t iPreviousCubeIndexY = pCurrentBitmask(uXRegSpace, uYRegSpace - 1); - iPreviousCubeIndexY &= 192; //192 = 128 + 64 - iPreviousCubeIndexY >>= 2; - - //x - uint8_t iPreviousCubeIndexX = pCurrentBitmask(uXRegSpace - 1, uYRegSpace); - iPreviousCubeIndexX &= 128; - iPreviousCubeIndexX >>= 1; - - iCubeIndex = iPreviousCubeIndexX | iPreviousCubeIndexY | iPreviousCubeIndexZ; - - if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128; - } - else //previous X not available - { - v011 = m_sampVolume.peekVoxel0px1py1pz(); - v111 = m_sampVolume.peekVoxel1px1py1pz(); - - //z - uint8_t iPreviousCubeIndexZ = pPreviousBitmask(uXRegSpace, uYRegSpace); - iPreviousCubeIndexZ >>= 4; - - //y - uint8_t iPreviousCubeIndexY = pCurrentBitmask(uXRegSpace, uYRegSpace - 1); - iPreviousCubeIndexY &= 192; //192 = 128 + 64 - iPreviousCubeIndexY >>= 2; - - iCubeIndex = iPreviousCubeIndexY | iPreviousCubeIndexZ; - - if (m_controller.convertToDensity(v011) < m_tThreshold) iCubeIndex |= 64; - if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128; - } - } - else //previous Y not available - { - if(isPrevXAvail) - { - v101 = m_sampVolume.peekVoxel1px0py1pz(); - v111 = m_sampVolume.peekVoxel1px1py1pz(); - - //z - uint8_t iPreviousCubeIndexZ = pPreviousBitmask(uXRegSpace, uYRegSpace); - iPreviousCubeIndexZ >>= 4; - - //x - uint8_t iPreviousCubeIndexX = pCurrentBitmask(uXRegSpace - 1, uYRegSpace); - iPreviousCubeIndexX &= 160; //160 = 128+32 - iPreviousCubeIndexX >>= 1; - - iCubeIndex = iPreviousCubeIndexX | iPreviousCubeIndexZ; - - if (m_controller.convertToDensity(v101) < m_tThreshold) iCubeIndex |= 32; - if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128; - } - else //previous X not available - { - v001 = m_sampVolume.peekVoxel0px0py1pz(); - v101 = m_sampVolume.peekVoxel1px0py1pz(); - v011 = m_sampVolume.peekVoxel0px1py1pz(); - v111 = m_sampVolume.peekVoxel1px1py1pz(); - - //z - uint8_t iPreviousCubeIndexZ = pPreviousBitmask(uXRegSpace, uYRegSpace); - iCubeIndex = iPreviousCubeIndexZ >> 4; - - if (m_controller.convertToDensity(v001) < m_tThreshold) iCubeIndex |= 16; - if (m_controller.convertToDensity(v101) < m_tThreshold) iCubeIndex |= 32; - if (m_controller.convertToDensity(v011) < m_tThreshold) iCubeIndex |= 64; - if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128; - } - } - } - else //previous Z not available - { - if(isPrevYAvail) - { - if(isPrevXAvail) - { - v110 = m_sampVolume.peekVoxel1px1py0pz(); - v111 = m_sampVolume.peekVoxel1px1py1pz(); - - //y - uint8_t iPreviousCubeIndexY = pCurrentBitmask(uXRegSpace, uYRegSpace - 1); - iPreviousCubeIndexY &= 204; //204 = 128+64+8+4 - iPreviousCubeIndexY >>= 2; - - //x - uint8_t iPreviousCubeIndexX = pCurrentBitmask(uXRegSpace - 1, uYRegSpace); - iPreviousCubeIndexX &= 170; //170 = 128+32+8+2 - iPreviousCubeIndexX >>= 1; - - iCubeIndex = iPreviousCubeIndexX | iPreviousCubeIndexY; - - if (m_controller.convertToDensity(v110) < m_tThreshold) iCubeIndex |= 8; - if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128; - } - else //previous X not available - { - v010 = m_sampVolume.peekVoxel0px1py0pz(); - v110 = m_sampVolume.peekVoxel1px1py0pz(); - - v011 = m_sampVolume.peekVoxel0px1py1pz(); - v111 = m_sampVolume.peekVoxel1px1py1pz(); - - //y - uint8_t iPreviousCubeIndexY = pCurrentBitmask(uXRegSpace, uYRegSpace - 1); - iPreviousCubeIndexY &= 204; //204 = 128+64+8+4 - iPreviousCubeIndexY >>= 2; - - iCubeIndex = iPreviousCubeIndexY; - - if (m_controller.convertToDensity(v010) < m_tThreshold) iCubeIndex |= 4; - if (m_controller.convertToDensity(v110) < m_tThreshold) iCubeIndex |= 8; - if (m_controller.convertToDensity(v011) < m_tThreshold) iCubeIndex |= 64; - if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128; - } - } - else //previous Y not available - { - if(isPrevXAvail) - { - v100 = m_sampVolume.peekVoxel1px0py0pz(); - v110 = m_sampVolume.peekVoxel1px1py0pz(); - - v101 = m_sampVolume.peekVoxel1px0py1pz(); - v111 = m_sampVolume.peekVoxel1px1py1pz(); - - //x - uint8_t iPreviousCubeIndexX = pCurrentBitmask(uXRegSpace - 1, uYRegSpace); - iPreviousCubeIndexX &= 170; //170 = 128+32+8+2 - iPreviousCubeIndexX >>= 1; - - iCubeIndex = iPreviousCubeIndexX; - - if (m_controller.convertToDensity(v100) < m_tThreshold) iCubeIndex |= 2; - if (m_controller.convertToDensity(v110) < m_tThreshold) iCubeIndex |= 8; - if (m_controller.convertToDensity(v101) < m_tThreshold) iCubeIndex |= 32; - if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128; - } - else //previous X not available - { - v000 = m_sampVolume.getVoxel(); - v100 = m_sampVolume.peekVoxel1px0py0pz(); - v010 = m_sampVolume.peekVoxel0px1py0pz(); - v110 = m_sampVolume.peekVoxel1px1py0pz(); - - v001 = m_sampVolume.peekVoxel0px0py1pz(); - v101 = m_sampVolume.peekVoxel1px0py1pz(); - v011 = m_sampVolume.peekVoxel0px1py1pz(); - v111 = m_sampVolume.peekVoxel1px1py1pz(); - - if (m_controller.convertToDensity(v000) < m_tThreshold) iCubeIndex |= 1; - if (m_controller.convertToDensity(v100) < m_tThreshold) iCubeIndex |= 2; - if (m_controller.convertToDensity(v010) < m_tThreshold) iCubeIndex |= 4; - if (m_controller.convertToDensity(v110) < m_tThreshold) iCubeIndex |= 8; - if (m_controller.convertToDensity(v001) < m_tThreshold) iCubeIndex |= 16; - if (m_controller.convertToDensity(v101) < m_tThreshold) iCubeIndex |= 32; - if (m_controller.convertToDensity(v011) < m_tThreshold) iCubeIndex |= 64; - if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128; - } - } - } - - //Save the bitmask - pCurrentBitmask(uXRegSpace, uYRegSpace) = iCubeIndex; - - if(edgeTable[iCubeIndex] != 0) - { - ++m_uNoOfOccupiedCells; - } - } - template void MarchingCubesSurfaceExtractor::generateVerticesForSlice(const Array2DUint8& pCurrentBitmask, Array2DInt32& m_pCurrentVertexIndicesX, From 2b22213becfaf96a619400f5c80bbcba0fa99a8b Mon Sep 17 00:00:00 2001 From: David Williams Date: Wed, 13 May 2015 23:05:58 +0200 Subject: [PATCH 02/61] Replaced 2D arrays with single 3D array when tracking existing vertices. --- .../PolyVox/MarchingCubesSurfaceExtractor.h | 14 ++- .../PolyVox/MarchingCubesSurfaceExtractor.inl | 90 ++++++++++--------- 2 files changed, 52 insertions(+), 52 deletions(-) diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.h b/include/PolyVox/MarchingCubesSurfaceExtractor.h index c542fd39..309614f2 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.h +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.h @@ -168,9 +168,9 @@ namespace PolyVox //Use the cell bitmasks to generate all the vertices needed for that slice void generateVerticesForSlice(const Array2DUint8& pCurrentBitmask, - Array2DInt32& m_pCurrentVertexIndicesX, - Array2DInt32& m_pCurrentVertexIndicesY, - Array2DInt32& m_pCurrentVertexIndicesZ); + Array3DInt32& pIndicesX, + Array3DInt32& pIndicesY, + Array3DInt32& pIndicesZ); //////////////////////////////////////////////////////////////////////////////// // NOTE: These two functions are in the .h file rather than the .inl due to an apparent bug in VC2010. @@ -288,11 +288,9 @@ namespace PolyVox //Use the cell bitmasks to generate all the indices needed for that slice void generateIndicesForSlice(const Array2DUint8& pPreviousBitmask, - const Array2DInt32& m_pPreviousVertexIndicesX, - const Array2DInt32& m_pPreviousVertexIndicesY, - const Array2DInt32& m_pPreviousVertexIndicesZ, - const Array2DInt32& m_pCurrentVertexIndicesX, - const Array2DInt32& m_pCurrentVertexIndicesY); + const Array3DInt32& pIndicesX, + const Array3DInt32& pIndicesY, + const Array3DInt32& pIndicesZ); //The volume data and a sampler to access it. VolumeType* m_volData; diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.inl b/include/PolyVox/MarchingCubesSurfaceExtractor.inl index dbe9a1ea..347c94fb 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.inl +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.inl @@ -48,14 +48,19 @@ namespace PolyVox const uint32_t uArrayWidth = m_regSizeInVoxels.getUpperX() - m_regSizeInVoxels.getLowerX() + 1; const uint32_t uArrayHeight = m_regSizeInVoxels.getUpperY() - m_regSizeInVoxels.getLowerY() + 1; + const uint32_t uArrayDepth = m_regSizeInVoxels.getUpperY() - m_regSizeInVoxels.getLowerZ() + 1; //For edge indices - Array2DInt32 m_pPreviousVertexIndicesX(uArrayWidth, uArrayHeight); - Array2DInt32 m_pPreviousVertexIndicesY(uArrayWidth, uArrayHeight); - Array2DInt32 m_pPreviousVertexIndicesZ(uArrayWidth, uArrayHeight); - Array2DInt32 m_pCurrentVertexIndicesX(uArrayWidth, uArrayHeight); - Array2DInt32 m_pCurrentVertexIndicesY(uArrayWidth, uArrayHeight); - Array2DInt32 m_pCurrentVertexIndicesZ(uArrayWidth, uArrayHeight); + //Array3DInt32 m_pPreviousVertexIndicesX(uArrayWidth, uArrayHeight, uArrayDepth); + //Array3DInt32 m_pPreviousVertexIndicesY(uArrayWidth, uArrayHeight, uArrayDepth); + //Array3DInt32 m_pPreviousVertexIndicesZ(uArrayWidth, uArrayHeight, uArrayDepth); + Array3DInt32 pIndicesX(uArrayWidth, uArrayHeight, uArrayDepth); + Array3DInt32 pIndicesY(uArrayWidth, uArrayHeight, uArrayDepth); + Array3DInt32 pIndicesZ(uArrayWidth, uArrayHeight, uArrayDepth); + + memset(pIndicesX.getRawData(), 0xff, pIndicesX.getNoOfElements() * 4); + memset(pIndicesY.getRawData(), 0xff, pIndicesY.getNoOfElements() * 4); + memset(pIndicesZ.getRawData(), 0xff, pIndicesZ.getNoOfElements() * 4); Array2DUint8 pPreviousBitmask(uArrayWidth, uArrayHeight); Array2DUint8 pCurrentBitmask(uArrayWidth, uArrayHeight); @@ -76,17 +81,11 @@ namespace PolyVox if(uNoOfNonEmptyCellsForSlice1 != 0) { - memset(m_pCurrentVertexIndicesX.getRawData(), 0xff, m_pCurrentVertexIndicesX.getNoOfElements() * 4); - memset(m_pCurrentVertexIndicesY.getRawData(), 0xff, m_pCurrentVertexIndicesY.getNoOfElements() * 4); - memset(m_pCurrentVertexIndicesZ.getRawData(), 0xff, m_pCurrentVertexIndicesZ.getNoOfElements() * 4); - generateVerticesForSlice(pCurrentBitmask, m_pCurrentVertexIndicesX, m_pCurrentVertexIndicesY, m_pCurrentVertexIndicesZ); + generateVerticesForSlice(pCurrentBitmask, pIndicesX, pIndicesY, pIndicesZ); } std::swap(uNoOfNonEmptyCellsForSlice0, uNoOfNonEmptyCellsForSlice1); pPreviousBitmask.swap(pCurrentBitmask); - m_pPreviousVertexIndicesX.swap(m_pCurrentVertexIndicesX); - m_pPreviousVertexIndicesY.swap(m_pCurrentVertexIndicesY); - m_pPreviousVertexIndicesZ.swap(m_pCurrentVertexIndicesZ); m_regSlicePrevious = m_regSliceCurrent; m_regSliceCurrent.shift(Vector3DInt32(0,0,1)); @@ -99,22 +98,16 @@ namespace PolyVox if(uNoOfNonEmptyCellsForSlice1 != 0) { - memset(m_pCurrentVertexIndicesX.getRawData(), 0xff, m_pCurrentVertexIndicesX.getNoOfElements() * 4); - memset(m_pCurrentVertexIndicesY.getRawData(), 0xff, m_pCurrentVertexIndicesY.getNoOfElements() * 4); - memset(m_pCurrentVertexIndicesZ.getRawData(), 0xff, m_pCurrentVertexIndicesZ.getNoOfElements() * 4); - generateVerticesForSlice(pCurrentBitmask, m_pCurrentVertexIndicesX, m_pCurrentVertexIndicesY, m_pCurrentVertexIndicesZ); + generateVerticesForSlice(pCurrentBitmask, pIndicesX, pIndicesY, pIndicesZ); } if((uNoOfNonEmptyCellsForSlice0 != 0) || (uNoOfNonEmptyCellsForSlice1 != 0)) { - generateIndicesForSlice(pPreviousBitmask, m_pPreviousVertexIndicesX, m_pPreviousVertexIndicesY, m_pPreviousVertexIndicesZ, m_pCurrentVertexIndicesX, m_pCurrentVertexIndicesY); + generateIndicesForSlice(pPreviousBitmask, pIndicesX, pIndicesY, pIndicesZ); } std::swap(uNoOfNonEmptyCellsForSlice0, uNoOfNonEmptyCellsForSlice1); pPreviousBitmask.swap(pCurrentBitmask); - m_pPreviousVertexIndicesX.swap(m_pCurrentVertexIndicesX); - m_pPreviousVertexIndicesY.swap(m_pCurrentVertexIndicesY); - m_pPreviousVertexIndicesZ.swap(m_pCurrentVertexIndicesZ); m_regSlicePrevious = m_regSliceCurrent; m_regSliceCurrent.shift(Vector3DInt32(0,0,1)); @@ -170,6 +163,16 @@ namespace PolyVox typename VolumeType::VoxelType v011 = m_sampVolume.peekVoxel0px1py1pz(); typename VolumeType::VoxelType v111 = m_sampVolume.peekVoxel1px1py1pz(); + /*typename VolumeType::VoxelType v000 = m_sampVolume.peekVoxel0px0py1nz(); + typename VolumeType::VoxelType v100 = m_sampVolume.peekVoxel1px0py1nz(); + typename VolumeType::VoxelType v010 = m_sampVolume.peekVoxel0px1py1nz(); + typename VolumeType::VoxelType v110 = m_sampVolume.peekVoxel1px1py1nz(); + + typename VolumeType::VoxelType v001 = m_sampVolume.peekVoxel0px0py0pz(); + typename VolumeType::VoxelType v101 = m_sampVolume.peekVoxel1px0py0pz(); + typename VolumeType::VoxelType v011 = m_sampVolume.peekVoxel0px1py0pz(); + typename VolumeType::VoxelType v111 = m_sampVolume.peekVoxel1px1py0pz();*/ + if (m_controller.convertToDensity(v000) < m_tThreshold) iCubeIndex |= 1; if (m_controller.convertToDensity(v100) < m_tThreshold) iCubeIndex |= 2; if (m_controller.convertToDensity(v010) < m_tThreshold) iCubeIndex |= 4; @@ -194,9 +197,9 @@ namespace PolyVox template void MarchingCubesSurfaceExtractor::generateVerticesForSlice(const Array2DUint8& pCurrentBitmask, - Array2DInt32& m_pCurrentVertexIndicesX, - Array2DInt32& m_pCurrentVertexIndicesY, - Array2DInt32& m_pCurrentVertexIndicesZ) + Array3DInt32& pIndicesX, + Array3DInt32& pIndicesY, + Array3DInt32& pIndicesZ) { const int32_t iZVolSpace = m_regSliceCurrent.getLowerZ(); @@ -257,7 +260,7 @@ namespace PolyVox surfaceVertex.data = uMaterial; const uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex); - m_pCurrentVertexIndicesX(iXVolSpace - m_regSizeInVoxels.getLowerX(), iYVolSpace - m_regSizeInVoxels.getLowerY()) = uLastVertexIndex; + pIndicesX(iXVolSpace - m_regSizeInVoxels.getLowerX(), iYVolSpace - m_regSizeInVoxels.getLowerY(), iZVolSpace - m_regSizeInVoxels.getLowerZ()) = uLastVertexIndex; m_sampVolume.moveNegativeX(); } @@ -291,7 +294,7 @@ namespace PolyVox surfaceVertex.data = uMaterial; uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex); - m_pCurrentVertexIndicesY(iXVolSpace - m_regSizeInVoxels.getLowerX(), iYVolSpace - m_regSizeInVoxels.getLowerY()) = uLastVertexIndex; + pIndicesY(iXVolSpace - m_regSizeInVoxels.getLowerX(), iYVolSpace - m_regSizeInVoxels.getLowerY(), iZVolSpace - m_regSizeInVoxels.getLowerZ()) = uLastVertexIndex; m_sampVolume.moveNegativeY(); } @@ -324,7 +327,7 @@ namespace PolyVox surfaceVertex.data = uMaterial; const uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex); - m_pCurrentVertexIndicesZ(iXVolSpace - m_regSizeInVoxels.getLowerX(), iYVolSpace - m_regSizeInVoxels.getLowerY()) = uLastVertexIndex; + pIndicesZ(iXVolSpace - m_regSizeInVoxels.getLowerX(), iYVolSpace - m_regSizeInVoxels.getLowerY(), iZVolSpace - m_regSizeInVoxels.getLowerZ()) = uLastVertexIndex; m_sampVolume.moveNegativeZ(); } @@ -334,11 +337,9 @@ namespace PolyVox template void MarchingCubesSurfaceExtractor::generateIndicesForSlice(const Array2DUint8& pPreviousBitmask, - const Array2DInt32& m_pPreviousVertexIndicesX, - const Array2DInt32& m_pPreviousVertexIndicesY, - const Array2DInt32& m_pPreviousVertexIndicesZ, - const Array2DInt32& m_pCurrentVertexIndicesX, - const Array2DInt32& m_pCurrentVertexIndicesY) + const Array3DInt32& pIndicesX, + const Array3DInt32& pIndicesY, + const Array3DInt32& pIndicesZ) { int32_t indlist[12]; for(int i = 0; i < 12; i++) @@ -357,6 +358,7 @@ namespace PolyVox //Current position const uint32_t uXRegSpace = m_sampVolume.getPosition().getX() - m_regSizeInVoxels.getLowerX(); const uint32_t uYRegSpace = m_sampVolume.getPosition().getY() - m_regSizeInVoxels.getLowerY(); + const uint32_t uZRegSpace = m_sampVolume.getPosition().getZ() - m_regSizeInVoxels.getLowerZ(); //Determine the index into the edge table which tells us which vertices are inside of the surface const uint8_t iCubeIndex = pPreviousBitmask(uXRegSpace, uYRegSpace); @@ -370,51 +372,51 @@ namespace PolyVox /* Find the vertices where the surface intersects the cube */ if (edgeTable[iCubeIndex] & 1) { - indlist[0] = m_pPreviousVertexIndicesX(uXRegSpace, uYRegSpace); + indlist[0] = pIndicesX(uXRegSpace, uYRegSpace, uZRegSpace); } if (edgeTable[iCubeIndex] & 2) { - indlist[1] = m_pPreviousVertexIndicesY(uXRegSpace + 1, uYRegSpace); + indlist[1] = pIndicesY(uXRegSpace + 1, uYRegSpace, uZRegSpace); } if (edgeTable[iCubeIndex] & 4) { - indlist[2] = m_pPreviousVertexIndicesX(uXRegSpace, uYRegSpace + 1); + indlist[2] = pIndicesX(uXRegSpace, uYRegSpace + 1, uZRegSpace); } if (edgeTable[iCubeIndex] & 8) { - indlist[3] = m_pPreviousVertexIndicesY(uXRegSpace, uYRegSpace); + indlist[3] = pIndicesY(uXRegSpace, uYRegSpace, uZRegSpace); } if (edgeTable[iCubeIndex] & 16) { - indlist[4] = m_pCurrentVertexIndicesX(uXRegSpace, uYRegSpace); + indlist[4] = pIndicesX(uXRegSpace, uYRegSpace, uZRegSpace + 1); } if (edgeTable[iCubeIndex] & 32) { - indlist[5] = m_pCurrentVertexIndicesY(uXRegSpace + 1, uYRegSpace); + indlist[5] = pIndicesY(uXRegSpace + 1, uYRegSpace, uZRegSpace + 1); } if (edgeTable[iCubeIndex] & 64) { - indlist[6] = m_pCurrentVertexIndicesX(uXRegSpace, uYRegSpace + 1); + indlist[6] = pIndicesX(uXRegSpace, uYRegSpace + 1, uZRegSpace + 1); } if (edgeTable[iCubeIndex] & 128) { - indlist[7] = m_pCurrentVertexIndicesY(uXRegSpace, uYRegSpace); + indlist[7] = pIndicesY(uXRegSpace, uYRegSpace, uZRegSpace + 1); } if (edgeTable[iCubeIndex] & 256) { - indlist[8] = m_pPreviousVertexIndicesZ(uXRegSpace, uYRegSpace); + indlist[8] = pIndicesZ(uXRegSpace, uYRegSpace, uZRegSpace); } if (edgeTable[iCubeIndex] & 512) { - indlist[9] = m_pPreviousVertexIndicesZ(uXRegSpace + 1, uYRegSpace); + indlist[9] = pIndicesZ(uXRegSpace + 1, uYRegSpace, uZRegSpace); } if (edgeTable[iCubeIndex] & 1024) { - indlist[10] = m_pPreviousVertexIndicesZ(uXRegSpace + 1, uYRegSpace + 1); + indlist[10] = pIndicesZ(uXRegSpace + 1, uYRegSpace + 1, uZRegSpace); } if (edgeTable[iCubeIndex] & 2048) { - indlist[11] = m_pPreviousVertexIndicesZ(uXRegSpace, uYRegSpace + 1); + indlist[11] = pIndicesZ(uXRegSpace, uYRegSpace + 1, uZRegSpace); } for (int i=0;triTable[iCubeIndex][i]!=-1;i+=3) From c4ce66dec5bd6512510fb08da18a7af7aebc03d8 Mon Sep 17 00:00:00 2001 From: David Williams Date: Thu, 14 May 2015 07:15:36 +0200 Subject: [PATCH 03/61] Replaced 2D pPreviousBitmask and pCurrentBitmask with 3D pBitmask. --- .../PolyVox/MarchingCubesSurfaceExtractor.h | 10 ++--- .../PolyVox/MarchingCubesSurfaceExtractor.inl | 39 ++++++++++--------- 2 files changed, 24 insertions(+), 25 deletions(-) diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.h b/include/PolyVox/MarchingCubesSurfaceExtractor.h index 309614f2..02c1a105 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.h +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.h @@ -160,14 +160,10 @@ namespace PolyVox private: //Compute the cell bitmask for a particular slice in z. template - uint32_t computeBitmaskForSlice(const Array2DUint8& pPreviousBitmask, Array2DUint8& pCurrentBitmask); - - //Compute the cell bitmask for a given cell. - template - void computeBitmaskForCell(const Array2DUint8& pPreviousBitmask, Array2DUint8& pCurrentBitmask, uint32_t uXRegSpace, uint32_t uYRegSpace); + uint32_t computeBitmaskForSlice(Array3DUint8& pBitmask); //Use the cell bitmasks to generate all the vertices needed for that slice - void generateVerticesForSlice(const Array2DUint8& pCurrentBitmask, + void generateVerticesForSlice(const Array3DUint8& pBitmask, Array3DInt32& pIndicesX, Array3DInt32& pIndicesY, Array3DInt32& pIndicesZ); @@ -287,7 +283,7 @@ namespace PolyVox //////////////////////////////////////////////////////////////////////////////// //Use the cell bitmasks to generate all the indices needed for that slice - void generateIndicesForSlice(const Array2DUint8& pPreviousBitmask, + void generateIndicesForSlice(const Array3DUint8& pBitmask, const Array3DInt32& pIndicesX, const Array3DInt32& pIndicesY, const Array3DInt32& pIndicesZ); diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.inl b/include/PolyVox/MarchingCubesSurfaceExtractor.inl index 347c94fb..40b2af8d 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.inl +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.inl @@ -48,7 +48,7 @@ namespace PolyVox const uint32_t uArrayWidth = m_regSizeInVoxels.getUpperX() - m_regSizeInVoxels.getLowerX() + 1; const uint32_t uArrayHeight = m_regSizeInVoxels.getUpperY() - m_regSizeInVoxels.getLowerY() + 1; - const uint32_t uArrayDepth = m_regSizeInVoxels.getUpperY() - m_regSizeInVoxels.getLowerZ() + 1; + const uint32_t uArrayDepth = m_regSizeInVoxels.getUpperZ() - m_regSizeInVoxels.getLowerZ() + 1; //For edge indices //Array3DInt32 m_pPreviousVertexIndicesX(uArrayWidth, uArrayHeight, uArrayDepth); @@ -62,8 +62,9 @@ namespace PolyVox memset(pIndicesY.getRawData(), 0xff, pIndicesY.getNoOfElements() * 4); memset(pIndicesZ.getRawData(), 0xff, pIndicesZ.getNoOfElements() * 4); - Array2DUint8 pPreviousBitmask(uArrayWidth, uArrayHeight); - Array2DUint8 pCurrentBitmask(uArrayWidth, uArrayHeight); + //Array2DUint8 pPreviousBitmask(uArrayWidth, uArrayHeight); + //Array2DUint8 pCurrentBitmask(uArrayWidth, uArrayHeight); + Array3DUint8 pBitmask(uArrayWidth, uArrayHeight, uArrayDepth); //Create a region corresponding to the first slice m_regSlicePrevious = m_regSizeInVoxels; @@ -76,16 +77,16 @@ namespace PolyVox uint32_t uNoOfNonEmptyCellsForSlice1 = 0; //Process the first slice (previous slice not available) - computeBitmaskForSlice(pPreviousBitmask, pCurrentBitmask); + computeBitmaskForSlice(pBitmask); uNoOfNonEmptyCellsForSlice1 = m_uNoOfOccupiedCells; if(uNoOfNonEmptyCellsForSlice1 != 0) { - generateVerticesForSlice(pCurrentBitmask, pIndicesX, pIndicesY, pIndicesZ); + generateVerticesForSlice(pBitmask, pIndicesX, pIndicesY, pIndicesZ); } std::swap(uNoOfNonEmptyCellsForSlice0, uNoOfNonEmptyCellsForSlice1); - pPreviousBitmask.swap(pCurrentBitmask); + //pPreviousBitmask.swap(pCurrentBitmask); m_regSlicePrevious = m_regSliceCurrent; m_regSliceCurrent.shift(Vector3DInt32(0,0,1)); @@ -93,21 +94,21 @@ namespace PolyVox //Process the other slices (previous slice is available) for(int32_t uSlice = 1; uSlice <= m_regSizeInVoxels.getUpperZ() - m_regSizeInVoxels.getLowerZ(); uSlice++) { - computeBitmaskForSlice(pPreviousBitmask, pCurrentBitmask); + computeBitmaskForSlice(pBitmask); uNoOfNonEmptyCellsForSlice1 = m_uNoOfOccupiedCells; if(uNoOfNonEmptyCellsForSlice1 != 0) { - generateVerticesForSlice(pCurrentBitmask, pIndicesX, pIndicesY, pIndicesZ); + generateVerticesForSlice(pBitmask, pIndicesX, pIndicesY, pIndicesZ); } if((uNoOfNonEmptyCellsForSlice0 != 0) || (uNoOfNonEmptyCellsForSlice1 != 0)) { - generateIndicesForSlice(pPreviousBitmask, pIndicesX, pIndicesY, pIndicesZ); + generateIndicesForSlice(pBitmask, pIndicesX, pIndicesY, pIndicesZ); } std::swap(uNoOfNonEmptyCellsForSlice0, uNoOfNonEmptyCellsForSlice1); - pPreviousBitmask.swap(pCurrentBitmask); + //pPreviousBitmask.swap(pCurrentBitmask); m_regSlicePrevious = m_regSliceCurrent; m_regSliceCurrent.shift(Vector3DInt32(0,0,1)); @@ -122,21 +123,21 @@ namespace PolyVox template template - uint32_t MarchingCubesSurfaceExtractor::computeBitmaskForSlice(const Array2DUint8& pPreviousBitmask, Array2DUint8& pCurrentBitmask) + uint32_t MarchingCubesSurfaceExtractor::computeBitmaskForSlice(Array3DUint8& pBitmask) { m_uNoOfOccupiedCells = 0; const int32_t iMaxXVolSpace = m_regSliceCurrent.getUpperX(); const int32_t iMaxYVolSpace = m_regSliceCurrent.getUpperY(); - const int32_t iZVolSpace = m_regSliceCurrent.getLowerZ(); - //Process the lower left corner int32_t iYVolSpace = m_regSliceCurrent.getLowerY(); int32_t iXVolSpace = m_regSliceCurrent.getLowerX(); + int32_t iZVolSpace = m_regSliceCurrent.getLowerZ(); uint32_t uXRegSpace = iXVolSpace - m_regSizeInVoxels.getLowerX(); uint32_t uYRegSpace = iYVolSpace - m_regSizeInVoxels.getLowerY(); + uint32_t uZRegSpace = iZVolSpace - m_regSizeInVoxels.getLowerZ(); //Process all remaining elemnents of the slice. In this case, previous x and y values are always available for(iYVolSpace = m_regSliceCurrent.getLowerY(); iYVolSpace <= iMaxYVolSpace; iYVolSpace++) @@ -183,7 +184,7 @@ namespace PolyVox if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128; //Save the bitmask - pCurrentBitmask(uXRegSpace, uYRegSpace) = iCubeIndex; + pBitmask(uXRegSpace, uYRegSpace, uZRegSpace) = iCubeIndex; if (edgeTable[iCubeIndex] != 0) { @@ -196,13 +197,15 @@ namespace PolyVox } template - void MarchingCubesSurfaceExtractor::generateVerticesForSlice(const Array2DUint8& pCurrentBitmask, + void MarchingCubesSurfaceExtractor::generateVerticesForSlice(const Array3DUint8& pBitmask, Array3DInt32& pIndicesX, Array3DInt32& pIndicesY, Array3DInt32& pIndicesZ) { const int32_t iZVolSpace = m_regSliceCurrent.getLowerZ(); + const uint32_t uZRegSpace = iZVolSpace - m_regSizeInVoxels.getLowerZ(); + //Iterate over each cell in the region for(int32_t iYVolSpace = m_regSliceCurrent.getLowerY(); iYVolSpace <= m_regSliceCurrent.getUpperY(); iYVolSpace++) { @@ -214,7 +217,7 @@ namespace PolyVox const uint32_t uXRegSpace = iXVolSpace - m_regSizeInVoxels.getLowerX(); //Determine the index into the edge table which tells us which vertices are inside of the surface - const uint8_t iCubeIndex = pCurrentBitmask(uXRegSpace, uYRegSpace); + const uint8_t iCubeIndex = pBitmask(uXRegSpace, uYRegSpace, uZRegSpace); /* Cube is entirely in/out of the surface */ if (edgeTable[iCubeIndex] == 0) @@ -336,7 +339,7 @@ namespace PolyVox } template - void MarchingCubesSurfaceExtractor::generateIndicesForSlice(const Array2DUint8& pPreviousBitmask, + void MarchingCubesSurfaceExtractor::generateIndicesForSlice(const Array3DUint8& pBitmask, const Array3DInt32& pIndicesX, const Array3DInt32& pIndicesY, const Array3DInt32& pIndicesZ) @@ -361,7 +364,7 @@ namespace PolyVox const uint32_t uZRegSpace = m_sampVolume.getPosition().getZ() - m_regSizeInVoxels.getLowerZ(); //Determine the index into the edge table which tells us which vertices are inside of the surface - const uint8_t iCubeIndex = pPreviousBitmask(uXRegSpace, uYRegSpace); + const uint8_t iCubeIndex = pBitmask(uXRegSpace, uYRegSpace, uZRegSpace); /* Cube is entirely in/out of the surface */ if (edgeTable[iCubeIndex] == 0) From 13fc8c5ba9b1d1dd25427925e14ca5fe6d644f86 Mon Sep 17 00:00:00 2001 From: David Williams Date: Thu, 14 May 2015 07:42:04 +0200 Subject: [PATCH 04/61] Removed unneeded variable. --- .../PolyVox/MarchingCubesSurfaceExtractor.h | 8 +--- .../PolyVox/MarchingCubesSurfaceExtractor.inl | 42 ++----------------- 2 files changed, 5 insertions(+), 45 deletions(-) diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.h b/include/PolyVox/MarchingCubesSurfaceExtractor.h index 02c1a105..2a0c800e 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.h +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.h @@ -160,7 +160,7 @@ namespace PolyVox private: //Compute the cell bitmask for a particular slice in z. template - uint32_t computeBitmaskForSlice(Array3DUint8& pBitmask); + void computeBitmaskForSlice(Array3DUint8& pBitmask); //Use the cell bitmasks to generate all the vertices needed for that slice void generateVerticesForSlice(const Array3DUint8& pBitmask, @@ -292,18 +292,12 @@ namespace PolyVox VolumeType* m_volData; typename VolumeType::Sampler m_sampVolume; - //Used to return the number of cells in a slice which contain triangles. - uint32_t m_uNoOfOccupiedCells; - //The surface patch we are currently filling. MeshType* m_meshCurrent; //Information about the region we are currently processing Region m_regSizeInVoxels; Region m_regSizeInCells; - /*Region m_regSizeInVoxelsCropped; - Region m_regSizeInVoxelsUncropped; - Region m_regVolumeCropped;*/ Region m_regSlicePrevious; Region m_regSliceCurrent; diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.inl b/include/PolyVox/MarchingCubesSurfaceExtractor.inl index 40b2af8d..ac5e31f2 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.inl +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.inl @@ -51,9 +51,6 @@ namespace PolyVox const uint32_t uArrayDepth = m_regSizeInVoxels.getUpperZ() - m_regSizeInVoxels.getLowerZ() + 1; //For edge indices - //Array3DInt32 m_pPreviousVertexIndicesX(uArrayWidth, uArrayHeight, uArrayDepth); - //Array3DInt32 m_pPreviousVertexIndicesY(uArrayWidth, uArrayHeight, uArrayDepth); - //Array3DInt32 m_pPreviousVertexIndicesZ(uArrayWidth, uArrayHeight, uArrayDepth); Array3DInt32 pIndicesX(uArrayWidth, uArrayHeight, uArrayDepth); Array3DInt32 pIndicesY(uArrayWidth, uArrayHeight, uArrayDepth); Array3DInt32 pIndicesZ(uArrayWidth, uArrayHeight, uArrayDepth); @@ -62,8 +59,6 @@ namespace PolyVox memset(pIndicesY.getRawData(), 0xff, pIndicesY.getNoOfElements() * 4); memset(pIndicesZ.getRawData(), 0xff, pIndicesZ.getNoOfElements() * 4); - //Array2DUint8 pPreviousBitmask(uArrayWidth, uArrayHeight); - //Array2DUint8 pCurrentBitmask(uArrayWidth, uArrayHeight); Array3DUint8 pBitmask(uArrayWidth, uArrayHeight, uArrayDepth); //Create a region corresponding to the first slice @@ -73,20 +68,10 @@ namespace PolyVox m_regSlicePrevious.setUpperCorner(v3dUpperCorner); m_regSliceCurrent = m_regSlicePrevious; - uint32_t uNoOfNonEmptyCellsForSlice0 = 0; - uint32_t uNoOfNonEmptyCellsForSlice1 = 0; - //Process the first slice (previous slice not available) computeBitmaskForSlice(pBitmask); - uNoOfNonEmptyCellsForSlice1 = m_uNoOfOccupiedCells; - if(uNoOfNonEmptyCellsForSlice1 != 0) - { - generateVerticesForSlice(pBitmask, pIndicesX, pIndicesY, pIndicesZ); - } - - std::swap(uNoOfNonEmptyCellsForSlice0, uNoOfNonEmptyCellsForSlice1); - //pPreviousBitmask.swap(pCurrentBitmask); + generateVerticesForSlice(pBitmask, pIndicesX, pIndicesY, pIndicesZ); m_regSlicePrevious = m_regSliceCurrent; m_regSliceCurrent.shift(Vector3DInt32(0,0,1)); @@ -95,20 +80,10 @@ namespace PolyVox for(int32_t uSlice = 1; uSlice <= m_regSizeInVoxels.getUpperZ() - m_regSizeInVoxels.getLowerZ(); uSlice++) { computeBitmaskForSlice(pBitmask); - uNoOfNonEmptyCellsForSlice1 = m_uNoOfOccupiedCells; - if(uNoOfNonEmptyCellsForSlice1 != 0) - { - generateVerticesForSlice(pBitmask, pIndicesX, pIndicesY, pIndicesZ); - } + generateVerticesForSlice(pBitmask, pIndicesX, pIndicesY, pIndicesZ); - if((uNoOfNonEmptyCellsForSlice0 != 0) || (uNoOfNonEmptyCellsForSlice1 != 0)) - { - generateIndicesForSlice(pBitmask, pIndicesX, pIndicesY, pIndicesZ); - } - - std::swap(uNoOfNonEmptyCellsForSlice0, uNoOfNonEmptyCellsForSlice1); - //pPreviousBitmask.swap(pCurrentBitmask); + generateIndicesForSlice(pBitmask, pIndicesX, pIndicesY, pIndicesZ); m_regSlicePrevious = m_regSliceCurrent; m_regSliceCurrent.shift(Vector3DInt32(0,0,1)); @@ -123,10 +98,8 @@ namespace PolyVox template template - uint32_t MarchingCubesSurfaceExtractor::computeBitmaskForSlice(Array3DUint8& pBitmask) + void MarchingCubesSurfaceExtractor::computeBitmaskForSlice(Array3DUint8& pBitmask) { - m_uNoOfOccupiedCells = 0; - const int32_t iMaxXVolSpace = m_regSliceCurrent.getUpperX(); const int32_t iMaxYVolSpace = m_regSliceCurrent.getUpperY(); @@ -185,15 +158,8 @@ namespace PolyVox //Save the bitmask pBitmask(uXRegSpace, uYRegSpace, uZRegSpace) = iCubeIndex; - - if (edgeTable[iCubeIndex] != 0) - { - ++m_uNoOfOccupiedCells; - } } } - - return m_uNoOfOccupiedCells; } template From 5974a1de9bd5093d0091b9e3cc87ecb2e43165ba Mon Sep 17 00:00:00 2001 From: David Williams Date: Thu, 14 May 2015 10:52:07 +0200 Subject: [PATCH 05/61] Restructuring loops... --- .../PolyVox/MarchingCubesSurfaceExtractor.h | 2 +- .../PolyVox/MarchingCubesSurfaceExtractor.inl | 24 ++++++++++--------- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.h b/include/PolyVox/MarchingCubesSurfaceExtractor.h index 2a0c800e..926e47df 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.h +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.h @@ -160,7 +160,7 @@ namespace PolyVox private: //Compute the cell bitmask for a particular slice in z. template - void computeBitmaskForSlice(Array3DUint8& pBitmask); + void computeBitmaskForSlice(Array3DUint8& pBitmask, uint32_t uSlice); //Use the cell bitmasks to generate all the vertices needed for that slice void generateVerticesForSlice(const Array3DUint8& pBitmask, diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.inl b/include/PolyVox/MarchingCubesSurfaceExtractor.inl index ac5e31f2..5e193744 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.inl +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.inl @@ -69,7 +69,11 @@ namespace PolyVox m_regSliceCurrent = m_regSlicePrevious; //Process the first slice (previous slice not available) - computeBitmaskForSlice(pBitmask); + computeBitmaskForSlice(pBitmask, 0); + for (int32_t uSlice = 1; uSlice <= m_regSizeInVoxels.getUpperZ() - m_regSizeInVoxels.getLowerZ(); uSlice++) + { + computeBitmaskForSlice(pBitmask, uSlice); + } generateVerticesForSlice(pBitmask, pIndicesX, pIndicesY, pIndicesZ); @@ -78,9 +82,7 @@ namespace PolyVox //Process the other slices (previous slice is available) for(int32_t uSlice = 1; uSlice <= m_regSizeInVoxels.getUpperZ() - m_regSizeInVoxels.getLowerZ(); uSlice++) - { - computeBitmaskForSlice(pBitmask); - + { generateVerticesForSlice(pBitmask, pIndicesX, pIndicesY, pIndicesZ); generateIndicesForSlice(pBitmask, pIndicesX, pIndicesY, pIndicesZ); @@ -98,19 +100,19 @@ namespace PolyVox template template - void MarchingCubesSurfaceExtractor::computeBitmaskForSlice(Array3DUint8& pBitmask) + void MarchingCubesSurfaceExtractor::computeBitmaskForSlice(Array3DUint8& pBitmask, uint32_t uSlice) { - const int32_t iMaxXVolSpace = m_regSliceCurrent.getUpperX(); - const int32_t iMaxYVolSpace = m_regSliceCurrent.getUpperY(); + const int32_t iMaxXVolSpace = m_regSizeInVoxels.getUpperX(); + const int32_t iMaxYVolSpace = m_regSizeInVoxels.getUpperY(); //Process the lower left corner - int32_t iYVolSpace = m_regSliceCurrent.getLowerY(); - int32_t iXVolSpace = m_regSliceCurrent.getLowerX(); - int32_t iZVolSpace = m_regSliceCurrent.getLowerZ(); + int32_t iYVolSpace = m_regSizeInVoxels.getLowerY(); + int32_t iXVolSpace = m_regSizeInVoxels.getLowerX(); + int32_t iZVolSpace = m_regSizeInVoxels.getLowerZ() + uSlice; uint32_t uXRegSpace = iXVolSpace - m_regSizeInVoxels.getLowerX(); uint32_t uYRegSpace = iYVolSpace - m_regSizeInVoxels.getLowerY(); - uint32_t uZRegSpace = iZVolSpace - m_regSizeInVoxels.getLowerZ(); + uint32_t uZRegSpace = uSlice; //Process all remaining elemnents of the slice. In this case, previous x and y values are always available for(iYVolSpace = m_regSliceCurrent.getLowerY(); iYVolSpace <= iMaxYVolSpace; iYVolSpace++) From 54f235e09a1f99874eeab6019d72f18fb02ce39f Mon Sep 17 00:00:00 2001 From: David Williams Date: Thu, 14 May 2015 11:14:39 +0200 Subject: [PATCH 06/61] Restructuring computeBitmask code. --- .../PolyVox/MarchingCubesSurfaceExtractor.h | 2 +- .../PolyVox/MarchingCubesSurfaceExtractor.inl | 96 +++++++++---------- 2 files changed, 45 insertions(+), 53 deletions(-) diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.h b/include/PolyVox/MarchingCubesSurfaceExtractor.h index 926e47df..2a0c800e 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.h +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.h @@ -160,7 +160,7 @@ namespace PolyVox private: //Compute the cell bitmask for a particular slice in z. template - void computeBitmaskForSlice(Array3DUint8& pBitmask, uint32_t uSlice); + void computeBitmaskForSlice(Array3DUint8& pBitmask); //Use the cell bitmasks to generate all the vertices needed for that slice void generateVerticesForSlice(const Array3DUint8& pBitmask, diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.inl b/include/PolyVox/MarchingCubesSurfaceExtractor.inl index 5e193744..3af87398 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.inl +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.inl @@ -68,12 +68,7 @@ namespace PolyVox m_regSlicePrevious.setUpperCorner(v3dUpperCorner); m_regSliceCurrent = m_regSlicePrevious; - //Process the first slice (previous slice not available) - computeBitmaskForSlice(pBitmask, 0); - for (int32_t uSlice = 1; uSlice <= m_regSizeInVoxels.getUpperZ() - m_regSizeInVoxels.getLowerZ(); uSlice++) - { - computeBitmaskForSlice(pBitmask, uSlice); - } + computeBitmaskForSlice(pBitmask); generateVerticesForSlice(pBitmask, pIndicesX, pIndicesY, pIndicesZ); @@ -100,66 +95,63 @@ namespace PolyVox template template - void MarchingCubesSurfaceExtractor::computeBitmaskForSlice(Array3DUint8& pBitmask, uint32_t uSlice) + void MarchingCubesSurfaceExtractor::computeBitmaskForSlice(Array3DUint8& pBitmask) { const int32_t iMaxXVolSpace = m_regSizeInVoxels.getUpperX(); const int32_t iMaxYVolSpace = m_regSizeInVoxels.getUpperY(); + const int32_t iMaxZVolSpace = m_regSizeInVoxels.getUpperZ(); - //Process the lower left corner - int32_t iYVolSpace = m_regSizeInVoxels.getLowerY(); - int32_t iXVolSpace = m_regSizeInVoxels.getLowerX(); - int32_t iZVolSpace = m_regSizeInVoxels.getLowerZ() + uSlice; - - uint32_t uXRegSpace = iXVolSpace - m_regSizeInVoxels.getLowerX(); - uint32_t uYRegSpace = iYVolSpace - m_regSizeInVoxels.getLowerY(); - uint32_t uZRegSpace = uSlice; - - //Process all remaining elemnents of the slice. In this case, previous x and y values are always available - for(iYVolSpace = m_regSliceCurrent.getLowerY(); iYVolSpace <= iMaxYVolSpace; iYVolSpace++) + for (int32_t iZVolSpace = m_regSliceCurrent.getLowerZ(); iZVolSpace <= iMaxZVolSpace; iZVolSpace++) { - m_sampVolume.setPosition(m_regSliceCurrent.getLowerX(), iYVolSpace, iZVolSpace); - for(iXVolSpace = m_regSliceCurrent.getLowerX(); iXVolSpace <= iMaxXVolSpace; iXVolSpace++) - { - uXRegSpace = iXVolSpace - m_regSizeInVoxels.getLowerX(); - uYRegSpace = iYVolSpace - m_regSizeInVoxels.getLowerY(); + uint32_t uZRegSpace = iZVolSpace - m_regSizeInVoxels.getLowerZ(); - m_sampVolume.movePositiveX(); + //Process all remaining elemnents of the slice. In this case, previous x and y values are always available + for (int32_t iYVolSpace = m_regSliceCurrent.getLowerY(); iYVolSpace <= iMaxYVolSpace; iYVolSpace++) + { + m_sampVolume.setPosition(m_regSliceCurrent.getLowerX(), iYVolSpace, iZVolSpace); + for (int32_t iXVolSpace = m_regSliceCurrent.getLowerX(); iXVolSpace <= iMaxXVolSpace; iXVolSpace++) + { + uint32_t uXRegSpace = iXVolSpace - m_regSizeInVoxels.getLowerX(); + uint32_t uYRegSpace = iYVolSpace - m_regSizeInVoxels.getLowerY(); - m_sampVolume.setPosition(iXVolSpace, iYVolSpace, iZVolSpace); + m_sampVolume.movePositiveX(); - uint8_t iCubeIndex = 0; + m_sampVolume.setPosition(iXVolSpace, iYVolSpace, iZVolSpace); - typename VolumeType::VoxelType v000 = m_sampVolume.getVoxel(); - typename VolumeType::VoxelType v100 = m_sampVolume.peekVoxel1px0py0pz(); - typename VolumeType::VoxelType v010 = m_sampVolume.peekVoxel0px1py0pz(); - typename VolumeType::VoxelType v110 = m_sampVolume.peekVoxel1px1py0pz(); + uint8_t iCubeIndex = 0; - typename VolumeType::VoxelType v001 = m_sampVolume.peekVoxel0px0py1pz(); - typename VolumeType::VoxelType v101 = m_sampVolume.peekVoxel1px0py1pz(); - typename VolumeType::VoxelType v011 = m_sampVolume.peekVoxel0px1py1pz(); - typename VolumeType::VoxelType v111 = m_sampVolume.peekVoxel1px1py1pz(); + typename VolumeType::VoxelType v000 = m_sampVolume.getVoxel(); + typename VolumeType::VoxelType v100 = m_sampVolume.peekVoxel1px0py0pz(); + typename VolumeType::VoxelType v010 = m_sampVolume.peekVoxel0px1py0pz(); + typename VolumeType::VoxelType v110 = m_sampVolume.peekVoxel1px1py0pz(); - /*typename VolumeType::VoxelType v000 = m_sampVolume.peekVoxel0px0py1nz(); - typename VolumeType::VoxelType v100 = m_sampVolume.peekVoxel1px0py1nz(); - typename VolumeType::VoxelType v010 = m_sampVolume.peekVoxel0px1py1nz(); - typename VolumeType::VoxelType v110 = m_sampVolume.peekVoxel1px1py1nz(); + typename VolumeType::VoxelType v001 = m_sampVolume.peekVoxel0px0py1pz(); + typename VolumeType::VoxelType v101 = m_sampVolume.peekVoxel1px0py1pz(); + typename VolumeType::VoxelType v011 = m_sampVolume.peekVoxel0px1py1pz(); + typename VolumeType::VoxelType v111 = m_sampVolume.peekVoxel1px1py1pz(); - typename VolumeType::VoxelType v001 = m_sampVolume.peekVoxel0px0py0pz(); - typename VolumeType::VoxelType v101 = m_sampVolume.peekVoxel1px0py0pz(); - typename VolumeType::VoxelType v011 = m_sampVolume.peekVoxel0px1py0pz(); - typename VolumeType::VoxelType v111 = m_sampVolume.peekVoxel1px1py0pz();*/ + /*typename VolumeType::VoxelType v000 = m_sampVolume.peekVoxel0px0py1nz(); + typename VolumeType::VoxelType v100 = m_sampVolume.peekVoxel1px0py1nz(); + typename VolumeType::VoxelType v010 = m_sampVolume.peekVoxel0px1py1nz(); + typename VolumeType::VoxelType v110 = m_sampVolume.peekVoxel1px1py1nz(); - if (m_controller.convertToDensity(v000) < m_tThreshold) iCubeIndex |= 1; - if (m_controller.convertToDensity(v100) < m_tThreshold) iCubeIndex |= 2; - if (m_controller.convertToDensity(v010) < m_tThreshold) iCubeIndex |= 4; - if (m_controller.convertToDensity(v110) < m_tThreshold) iCubeIndex |= 8; - if (m_controller.convertToDensity(v001) < m_tThreshold) iCubeIndex |= 16; - if (m_controller.convertToDensity(v101) < m_tThreshold) iCubeIndex |= 32; - if (m_controller.convertToDensity(v011) < m_tThreshold) iCubeIndex |= 64; - if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128; + typename VolumeType::VoxelType v001 = m_sampVolume.peekVoxel0px0py0pz(); + typename VolumeType::VoxelType v101 = m_sampVolume.peekVoxel1px0py0pz(); + typename VolumeType::VoxelType v011 = m_sampVolume.peekVoxel0px1py0pz(); + typename VolumeType::VoxelType v111 = m_sampVolume.peekVoxel1px1py0pz();*/ - //Save the bitmask - pBitmask(uXRegSpace, uYRegSpace, uZRegSpace) = iCubeIndex; + if (m_controller.convertToDensity(v000) < m_tThreshold) iCubeIndex |= 1; + if (m_controller.convertToDensity(v100) < m_tThreshold) iCubeIndex |= 2; + if (m_controller.convertToDensity(v010) < m_tThreshold) iCubeIndex |= 4; + if (m_controller.convertToDensity(v110) < m_tThreshold) iCubeIndex |= 8; + if (m_controller.convertToDensity(v001) < m_tThreshold) iCubeIndex |= 16; + if (m_controller.convertToDensity(v101) < m_tThreshold) iCubeIndex |= 32; + if (m_controller.convertToDensity(v011) < m_tThreshold) iCubeIndex |= 64; + if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128; + + //Save the bitmask + pBitmask(uXRegSpace, uYRegSpace, uZRegSpace) = iCubeIndex; + } } } } From 49683b4b486e4a27ea19b77d4baf03fc51e48996 Mon Sep 17 00:00:00 2001 From: David Williams Date: Thu, 14 May 2015 11:27:19 +0200 Subject: [PATCH 07/61] Fixed compile error due to logging code changing scope. --- include/PolyVox/Impl/Assertions.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/PolyVox/Impl/Assertions.h b/include/PolyVox/Impl/Assertions.h index d33669a5..a6bc486e 100644 --- a/include/PolyVox/Impl/Assertions.h +++ b/include/PolyVox/Impl/Assertions.h @@ -53,7 +53,7 @@ distribution. ss << " Message: " << (message); \ ss << " Location: " << "Line " << __LINE__ << " of " << __FILE__; \ ss << "\n"; \ - PolyVox::Impl::getLoggerInstance()->logFatalMessage(ss.str()); \ + PolyVox::getLoggerInstance()->logFatalMessage(ss.str()); \ POLYVOX_HALT(); \ } \ } while(0) \ From e91295031746a4a688842f4052002f09fc3c1cd8 Mon Sep 17 00:00:00 2001 From: David Williams Date: Thu, 14 May 2015 11:35:04 +0200 Subject: [PATCH 08/61] Restructuring code... --- include/PolyVox/MarchingCubesSurfaceExtractor.h | 3 ++- include/PolyVox/MarchingCubesSurfaceExtractor.inl | 11 ++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.h b/include/PolyVox/MarchingCubesSurfaceExtractor.h index 2a0c800e..9eca263c 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.h +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.h @@ -166,7 +166,8 @@ namespace PolyVox void generateVerticesForSlice(const Array3DUint8& pBitmask, Array3DInt32& pIndicesX, Array3DInt32& pIndicesY, - Array3DInt32& pIndicesZ); + Array3DInt32& pIndicesZ, + uint32_t uSlice); //////////////////////////////////////////////////////////////////////////////// // NOTE: These two functions are in the .h file rather than the .inl due to an apparent bug in VC2010. diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.inl b/include/PolyVox/MarchingCubesSurfaceExtractor.inl index 3af87398..8bd73f10 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.inl +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.inl @@ -70,7 +70,7 @@ namespace PolyVox computeBitmaskForSlice(pBitmask); - generateVerticesForSlice(pBitmask, pIndicesX, pIndicesY, pIndicesZ); + generateVerticesForSlice(pBitmask, pIndicesX, pIndicesY, pIndicesZ, 0); m_regSlicePrevious = m_regSliceCurrent; m_regSliceCurrent.shift(Vector3DInt32(0,0,1)); @@ -78,7 +78,7 @@ namespace PolyVox //Process the other slices (previous slice is available) for(int32_t uSlice = 1; uSlice <= m_regSizeInVoxels.getUpperZ() - m_regSizeInVoxels.getLowerZ(); uSlice++) { - generateVerticesForSlice(pBitmask, pIndicesX, pIndicesY, pIndicesZ); + generateVerticesForSlice(pBitmask, pIndicesX, pIndicesY, pIndicesZ, uSlice); generateIndicesForSlice(pBitmask, pIndicesX, pIndicesY, pIndicesZ); @@ -160,11 +160,12 @@ namespace PolyVox void MarchingCubesSurfaceExtractor::generateVerticesForSlice(const Array3DUint8& pBitmask, Array3DInt32& pIndicesX, Array3DInt32& pIndicesY, - Array3DInt32& pIndicesZ) + Array3DInt32& pIndicesZ, + uint32_t uSlice) { - const int32_t iZVolSpace = m_regSliceCurrent.getLowerZ(); + const uint32_t uZRegSpace = uSlice; - const uint32_t uZRegSpace = iZVolSpace - m_regSizeInVoxels.getLowerZ(); + const int32_t iZVolSpace = m_regSizeInVoxels.getLowerZ() + uZRegSpace; //Iterate over each cell in the region for(int32_t iYVolSpace = m_regSliceCurrent.getLowerY(); iYVolSpace <= m_regSliceCurrent.getUpperY(); iYVolSpace++) From f53efa1d64d031821a8eae2ca5c68d67763713b0 Mon Sep 17 00:00:00 2001 From: David Williams Date: Thu, 14 May 2015 11:41:16 +0200 Subject: [PATCH 09/61] Restructuring code. --- .../PolyVox/MarchingCubesSurfaceExtractor.h | 3 +- .../PolyVox/MarchingCubesSurfaceExtractor.inl | 233 +++++++++--------- 2 files changed, 116 insertions(+), 120 deletions(-) diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.h b/include/PolyVox/MarchingCubesSurfaceExtractor.h index 9eca263c..2a0c800e 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.h +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.h @@ -166,8 +166,7 @@ namespace PolyVox void generateVerticesForSlice(const Array3DUint8& pBitmask, Array3DInt32& pIndicesX, Array3DInt32& pIndicesY, - Array3DInt32& pIndicesZ, - uint32_t uSlice); + Array3DInt32& pIndicesZ); //////////////////////////////////////////////////////////////////////////////// // NOTE: These two functions are in the .h file rather than the .inl due to an apparent bug in VC2010. diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.inl b/include/PolyVox/MarchingCubesSurfaceExtractor.inl index 8bd73f10..d58d1eb9 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.inl +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.inl @@ -70,7 +70,7 @@ namespace PolyVox computeBitmaskForSlice(pBitmask); - generateVerticesForSlice(pBitmask, pIndicesX, pIndicesY, pIndicesZ, 0); + generateVerticesForSlice(pBitmask, pIndicesX, pIndicesY, pIndicesZ); m_regSlicePrevious = m_regSliceCurrent; m_regSliceCurrent.shift(Vector3DInt32(0,0,1)); @@ -78,8 +78,6 @@ namespace PolyVox //Process the other slices (previous slice is available) for(int32_t uSlice = 1; uSlice <= m_regSizeInVoxels.getUpperZ() - m_regSizeInVoxels.getLowerZ(); uSlice++) { - generateVerticesForSlice(pBitmask, pIndicesX, pIndicesY, pIndicesZ, uSlice); - generateIndicesForSlice(pBitmask, pIndicesX, pIndicesY, pIndicesZ); m_regSlicePrevious = m_regSliceCurrent; @@ -160,142 +158,141 @@ namespace PolyVox void MarchingCubesSurfaceExtractor::generateVerticesForSlice(const Array3DUint8& pBitmask, Array3DInt32& pIndicesX, Array3DInt32& pIndicesY, - Array3DInt32& pIndicesZ, - uint32_t uSlice) + Array3DInt32& pIndicesZ) { - const uint32_t uZRegSpace = uSlice; - - const int32_t iZVolSpace = m_regSizeInVoxels.getLowerZ() + uZRegSpace; - - //Iterate over each cell in the region - for(int32_t iYVolSpace = m_regSliceCurrent.getLowerY(); iYVolSpace <= m_regSliceCurrent.getUpperY(); iYVolSpace++) + for (int32_t iZVolSpace = m_regSliceCurrent.getLowerZ(); iZVolSpace <= m_regSizeInVoxels.getUpperZ(); iZVolSpace++) { - const uint32_t uYRegSpace = iYVolSpace - m_regSizeInVoxels.getLowerY(); + uint32_t uZRegSpace = iZVolSpace - m_regSizeInVoxels.getLowerZ(); - for(int32_t iXVolSpace = m_regSliceCurrent.getLowerX(); iXVolSpace <= m_regSliceCurrent.getUpperX(); iXVolSpace++) - { - //Current position - const uint32_t uXRegSpace = iXVolSpace - m_regSizeInVoxels.getLowerX(); + for (int32_t iYVolSpace = m_regSliceCurrent.getLowerY(); iYVolSpace <= m_regSizeInVoxels.getUpperY(); iYVolSpace++) + { + const uint32_t uYRegSpace = iYVolSpace - m_regSizeInVoxels.getLowerY(); - //Determine the index into the edge table which tells us which vertices are inside of the surface - const uint8_t iCubeIndex = pBitmask(uXRegSpace, uYRegSpace, uZRegSpace); - - /* Cube is entirely in/out of the surface */ - if (edgeTable[iCubeIndex] == 0) + for (int32_t iXVolSpace = m_regSliceCurrent.getLowerX(); iXVolSpace <= m_regSizeInVoxels.getUpperX(); iXVolSpace++) { - continue; - } + //Current position + const uint32_t uXRegSpace = iXVolSpace - m_regSizeInVoxels.getLowerX(); - //Check whether the generated vertex will lie on the edge of the region + //Determine the index into the edge table which tells us which vertices are inside of the surface + const uint8_t iCubeIndex = pBitmask(uXRegSpace, uYRegSpace, uZRegSpace); - - m_sampVolume.setPosition(iXVolSpace,iYVolSpace,iZVolSpace); - const typename VolumeType::VoxelType v000 = m_sampVolume.getVoxel(); - const Vector3DFloat n000 = computeCentralDifferenceGradient(m_sampVolume); - - /* Find the vertices where the surface intersects the cube */ - if (edgeTable[iCubeIndex] & 1) - { - m_sampVolume.movePositiveX(); - const typename VolumeType::VoxelType v100 = m_sampVolume.getVoxel(); - POLYVOX_ASSERT(v000 != v100, "Attempting to insert vertex between two voxels with the same value"); - const Vector3DFloat n100 = computeCentralDifferenceGradient(m_sampVolume); - - const float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v000)) / static_cast(m_controller.convertToDensity(v100) - m_controller.convertToDensity(v000)); - - const Vector3DFloat v3dPosition(static_cast(iXVolSpace - m_regSizeInVoxels.getLowerX()) + fInterp, static_cast(iYVolSpace - m_regSizeInVoxels.getLowerY()), static_cast(iZVolSpace - m_regSizeInCells.getLowerZ())); - const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); - - Vector3DFloat v3dNormal = (n100*fInterp) + (n000*(1-fInterp)); - - // The gradient for a voxel can be zero (e.g. solid voxel surrounded by empty ones) and so - // the interpolated normal can also be zero (e.g. a grid of alternating solid and empty voxels). - if(v3dNormal.lengthSquared() > 0.000001f) + /* Cube is entirely in/out of the surface */ + if (edgeTable[iCubeIndex] == 0) { - v3dNormal.normalise(); + continue; } - // Allow the controller to decide how the material should be derived from the voxels. - const typename VolumeType::VoxelType uMaterial = m_controller.blendMaterials(v000, v100, fInterp); + //Check whether the generated vertex will lie on the edge of the region - MarchingCubesVertex surfaceVertex; - surfaceVertex.encodedPosition = v3dScaledPosition; - surfaceVertex.encodedNormal = encodeNormal(v3dNormal); - surfaceVertex.data = uMaterial; - const uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex); - pIndicesX(iXVolSpace - m_regSizeInVoxels.getLowerX(), iYVolSpace - m_regSizeInVoxels.getLowerY(), iZVolSpace - m_regSizeInVoxels.getLowerZ()) = uLastVertexIndex; + m_sampVolume.setPosition(iXVolSpace, iYVolSpace, iZVolSpace); + const typename VolumeType::VoxelType v000 = m_sampVolume.getVoxel(); + const Vector3DFloat n000 = computeCentralDifferenceGradient(m_sampVolume); - m_sampVolume.moveNegativeX(); - } - if (edgeTable[iCubeIndex] & 8) - { - m_sampVolume.movePositiveY(); - const typename VolumeType::VoxelType v010 = m_sampVolume.getVoxel(); - POLYVOX_ASSERT(v000 != v010, "Attempting to insert vertex between two voxels with the same value"); - const Vector3DFloat n010 = computeCentralDifferenceGradient(m_sampVolume); - - const float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v000)) / static_cast(m_controller.convertToDensity(v010) - m_controller.convertToDensity(v000)); - - const Vector3DFloat v3dPosition(static_cast(iXVolSpace - m_regSizeInVoxels.getLowerX()), static_cast(iYVolSpace - m_regSizeInVoxels.getLowerY()) + fInterp, static_cast(iZVolSpace - m_regSizeInVoxels.getLowerZ())); - const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); - - Vector3DFloat v3dNormal = (n010*fInterp) + (n000*(1-fInterp)); - - // The gradient for a voxel can be zero (e.g. solid voxel surrounded by empty ones) and so - // the interpolated normal can also be zero (e.g. a grid of alternating solid and empty voxels). - if(v3dNormal.lengthSquared() > 0.000001f) + /* Find the vertices where the surface intersects the cube */ + if (edgeTable[iCubeIndex] & 1) { - v3dNormal.normalise(); + m_sampVolume.movePositiveX(); + const typename VolumeType::VoxelType v100 = m_sampVolume.getVoxel(); + POLYVOX_ASSERT(v000 != v100, "Attempting to insert vertex between two voxels with the same value"); + const Vector3DFloat n100 = computeCentralDifferenceGradient(m_sampVolume); + + const float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v000)) / static_cast(m_controller.convertToDensity(v100) - m_controller.convertToDensity(v000)); + + const Vector3DFloat v3dPosition(static_cast(iXVolSpace - m_regSizeInVoxels.getLowerX()) + fInterp, static_cast(iYVolSpace - m_regSizeInVoxels.getLowerY()), static_cast(iZVolSpace - m_regSizeInCells.getLowerZ())); + const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); + + Vector3DFloat v3dNormal = (n100*fInterp) + (n000*(1 - fInterp)); + + // The gradient for a voxel can be zero (e.g. solid voxel surrounded by empty ones) and so + // the interpolated normal can also be zero (e.g. a grid of alternating solid and empty voxels). + if (v3dNormal.lengthSquared() > 0.000001f) + { + v3dNormal.normalise(); + } + + // Allow the controller to decide how the material should be derived from the voxels. + const typename VolumeType::VoxelType uMaterial = m_controller.blendMaterials(v000, v100, fInterp); + + MarchingCubesVertex surfaceVertex; + surfaceVertex.encodedPosition = v3dScaledPosition; + surfaceVertex.encodedNormal = encodeNormal(v3dNormal); + surfaceVertex.data = uMaterial; + + const uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex); + pIndicesX(iXVolSpace - m_regSizeInVoxels.getLowerX(), iYVolSpace - m_regSizeInVoxels.getLowerY(), iZVolSpace - m_regSizeInVoxels.getLowerZ()) = uLastVertexIndex; + + m_sampVolume.moveNegativeX(); } - - // Allow the controller to decide how the material should be derived from the voxels. - const typename VolumeType::VoxelType uMaterial = m_controller.blendMaterials(v000, v010, fInterp); - - MarchingCubesVertex surfaceVertex; - surfaceVertex.encodedPosition = v3dScaledPosition; - surfaceVertex.encodedNormal = encodeNormal(v3dNormal); - surfaceVertex.data = uMaterial; - - uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex); - pIndicesY(iXVolSpace - m_regSizeInVoxels.getLowerX(), iYVolSpace - m_regSizeInVoxels.getLowerY(), iZVolSpace - m_regSizeInVoxels.getLowerZ()) = uLastVertexIndex; - - m_sampVolume.moveNegativeY(); - } - if (edgeTable[iCubeIndex] & 256) - { - m_sampVolume.movePositiveZ(); - const typename VolumeType::VoxelType v001 = m_sampVolume.getVoxel(); - POLYVOX_ASSERT(v000 != v001, "Attempting to insert vertex between two voxels with the same value"); - const Vector3DFloat n001 = computeCentralDifferenceGradient(m_sampVolume); - - const float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v000)) / static_cast(m_controller.convertToDensity(v001) - m_controller.convertToDensity(v000)); - - const Vector3DFloat v3dPosition(static_cast(iXVolSpace - m_regSizeInVoxels.getLowerX()), static_cast(iYVolSpace - m_regSizeInVoxels.getLowerY()), static_cast(iZVolSpace - m_regSizeInVoxels.getLowerZ()) + fInterp); - const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); - - Vector3DFloat v3dNormal = (n001*fInterp) + (n000*(1-fInterp)); - // The gradient for a voxel can be zero (e.g. solid voxel surrounded by empty ones) and so - // the interpolated normal can also be zero (e.g. a grid of alternating solid and empty voxels). - if(v3dNormal.lengthSquared() > 0.000001f) + if (edgeTable[iCubeIndex] & 8) { - v3dNormal.normalise(); + m_sampVolume.movePositiveY(); + const typename VolumeType::VoxelType v010 = m_sampVolume.getVoxel(); + POLYVOX_ASSERT(v000 != v010, "Attempting to insert vertex between two voxels with the same value"); + const Vector3DFloat n010 = computeCentralDifferenceGradient(m_sampVolume); + + const float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v000)) / static_cast(m_controller.convertToDensity(v010) - m_controller.convertToDensity(v000)); + + const Vector3DFloat v3dPosition(static_cast(iXVolSpace - m_regSizeInVoxels.getLowerX()), static_cast(iYVolSpace - m_regSizeInVoxels.getLowerY()) + fInterp, static_cast(iZVolSpace - m_regSizeInVoxels.getLowerZ())); + const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); + + Vector3DFloat v3dNormal = (n010*fInterp) + (n000*(1 - fInterp)); + + // The gradient for a voxel can be zero (e.g. solid voxel surrounded by empty ones) and so + // the interpolated normal can also be zero (e.g. a grid of alternating solid and empty voxels). + if (v3dNormal.lengthSquared() > 0.000001f) + { + v3dNormal.normalise(); + } + + // Allow the controller to decide how the material should be derived from the voxels. + const typename VolumeType::VoxelType uMaterial = m_controller.blendMaterials(v000, v010, fInterp); + + MarchingCubesVertex surfaceVertex; + surfaceVertex.encodedPosition = v3dScaledPosition; + surfaceVertex.encodedNormal = encodeNormal(v3dNormal); + surfaceVertex.data = uMaterial; + + uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex); + pIndicesY(iXVolSpace - m_regSizeInVoxels.getLowerX(), iYVolSpace - m_regSizeInVoxels.getLowerY(), iZVolSpace - m_regSizeInVoxels.getLowerZ()) = uLastVertexIndex; + + m_sampVolume.moveNegativeY(); } + if (edgeTable[iCubeIndex] & 256) + { + m_sampVolume.movePositiveZ(); + const typename VolumeType::VoxelType v001 = m_sampVolume.getVoxel(); + POLYVOX_ASSERT(v000 != v001, "Attempting to insert vertex between two voxels with the same value"); + const Vector3DFloat n001 = computeCentralDifferenceGradient(m_sampVolume); - // Allow the controller to decide how the material should be derived from the voxels. - const typename VolumeType::VoxelType uMaterial = m_controller.blendMaterials(v000, v001, fInterp); + const float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v000)) / static_cast(m_controller.convertToDensity(v001) - m_controller.convertToDensity(v000)); - MarchingCubesVertex surfaceVertex; - surfaceVertex.encodedPosition = v3dScaledPosition; - surfaceVertex.encodedNormal = encodeNormal(v3dNormal); - surfaceVertex.data = uMaterial; + const Vector3DFloat v3dPosition(static_cast(iXVolSpace - m_regSizeInVoxels.getLowerX()), static_cast(iYVolSpace - m_regSizeInVoxels.getLowerY()), static_cast(iZVolSpace - m_regSizeInVoxels.getLowerZ()) + fInterp); + const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); - const uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex); - pIndicesZ(iXVolSpace - m_regSizeInVoxels.getLowerX(), iYVolSpace - m_regSizeInVoxels.getLowerY(), iZVolSpace - m_regSizeInVoxels.getLowerZ()) = uLastVertexIndex; + Vector3DFloat v3dNormal = (n001*fInterp) + (n000*(1 - fInterp)); + // The gradient for a voxel can be zero (e.g. solid voxel surrounded by empty ones) and so + // the interpolated normal can also be zero (e.g. a grid of alternating solid and empty voxels). + if (v3dNormal.lengthSquared() > 0.000001f) + { + v3dNormal.normalise(); + } - m_sampVolume.moveNegativeZ(); - } - }//For each cell + // Allow the controller to decide how the material should be derived from the voxels. + const typename VolumeType::VoxelType uMaterial = m_controller.blendMaterials(v000, v001, fInterp); + + MarchingCubesVertex surfaceVertex; + surfaceVertex.encodedPosition = v3dScaledPosition; + surfaceVertex.encodedNormal = encodeNormal(v3dNormal); + surfaceVertex.data = uMaterial; + + const uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex); + pIndicesZ(iXVolSpace - m_regSizeInVoxels.getLowerX(), iYVolSpace - m_regSizeInVoxels.getLowerY(), iZVolSpace - m_regSizeInVoxels.getLowerZ()) = uLastVertexIndex; + + m_sampVolume.moveNegativeZ(); + } + }//For each cell + } } } From 89508f8b2b15fdcae09445e8fac1df3e6e235c29 Mon Sep 17 00:00:00 2001 From: David Williams Date: Thu, 14 May 2015 11:48:28 +0200 Subject: [PATCH 10/61] Restructuring code. --- .../PolyVox/MarchingCubesSurfaceExtractor.h | 5 +-- .../PolyVox/MarchingCubesSurfaceExtractor.inl | 41 +++---------------- 2 files changed, 7 insertions(+), 39 deletions(-) diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.h b/include/PolyVox/MarchingCubesSurfaceExtractor.h index 2a0c800e..e33f7a96 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.h +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.h @@ -160,10 +160,7 @@ namespace PolyVox private: //Compute the cell bitmask for a particular slice in z. template - void computeBitmaskForSlice(Array3DUint8& pBitmask); - - //Use the cell bitmasks to generate all the vertices needed for that slice - void generateVerticesForSlice(const Array3DUint8& pBitmask, + void computeBitmaskForSlice(Array3DUint8& pBitmask, Array3DInt32& pIndicesX, Array3DInt32& pIndicesY, Array3DInt32& pIndicesZ); diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.inl b/include/PolyVox/MarchingCubesSurfaceExtractor.inl index d58d1eb9..d02bde54 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.inl +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.inl @@ -68,9 +68,7 @@ namespace PolyVox m_regSlicePrevious.setUpperCorner(v3dUpperCorner); m_regSliceCurrent = m_regSlicePrevious; - computeBitmaskForSlice(pBitmask); - - generateVerticesForSlice(pBitmask, pIndicesX, pIndicesY, pIndicesZ); + computeBitmaskForSlice(pBitmask, pIndicesX, pIndicesY, pIndicesZ); m_regSlicePrevious = m_regSliceCurrent; m_regSliceCurrent.shift(Vector3DInt32(0,0,1)); @@ -93,7 +91,10 @@ namespace PolyVox template template - void MarchingCubesSurfaceExtractor::computeBitmaskForSlice(Array3DUint8& pBitmask) + void MarchingCubesSurfaceExtractor::computeBitmaskForSlice(Array3DUint8& pBitmask, + Array3DInt32& pIndicesX, + Array3DInt32& pIndicesY, + Array3DInt32& pIndicesZ) { const int32_t iMaxXVolSpace = m_regSizeInVoxels.getUpperX(); const int32_t iMaxYVolSpace = m_regSizeInVoxels.getUpperY(); @@ -149,32 +150,6 @@ namespace PolyVox //Save the bitmask pBitmask(uXRegSpace, uYRegSpace, uZRegSpace) = iCubeIndex; - } - } - } - } - - template - void MarchingCubesSurfaceExtractor::generateVerticesForSlice(const Array3DUint8& pBitmask, - Array3DInt32& pIndicesX, - Array3DInt32& pIndicesY, - Array3DInt32& pIndicesZ) - { - for (int32_t iZVolSpace = m_regSliceCurrent.getLowerZ(); iZVolSpace <= m_regSizeInVoxels.getUpperZ(); iZVolSpace++) - { - uint32_t uZRegSpace = iZVolSpace - m_regSizeInVoxels.getLowerZ(); - - for (int32_t iYVolSpace = m_regSliceCurrent.getLowerY(); iYVolSpace <= m_regSizeInVoxels.getUpperY(); iYVolSpace++) - { - const uint32_t uYRegSpace = iYVolSpace - m_regSizeInVoxels.getLowerY(); - - for (int32_t iXVolSpace = m_regSliceCurrent.getLowerX(); iXVolSpace <= m_regSizeInVoxels.getUpperX(); iXVolSpace++) - { - //Current position - const uint32_t uXRegSpace = iXVolSpace - m_regSizeInVoxels.getLowerX(); - - //Determine the index into the edge table which tells us which vertices are inside of the surface - const uint8_t iCubeIndex = pBitmask(uXRegSpace, uYRegSpace, uZRegSpace); /* Cube is entirely in/out of the surface */ if (edgeTable[iCubeIndex] == 0) @@ -186,14 +161,12 @@ namespace PolyVox m_sampVolume.setPosition(iXVolSpace, iYVolSpace, iZVolSpace); - const typename VolumeType::VoxelType v000 = m_sampVolume.getVoxel(); const Vector3DFloat n000 = computeCentralDifferenceGradient(m_sampVolume); /* Find the vertices where the surface intersects the cube */ if (edgeTable[iCubeIndex] & 1) { m_sampVolume.movePositiveX(); - const typename VolumeType::VoxelType v100 = m_sampVolume.getVoxel(); POLYVOX_ASSERT(v000 != v100, "Attempting to insert vertex between two voxels with the same value"); const Vector3DFloat n100 = computeCentralDifferenceGradient(m_sampVolume); @@ -227,7 +200,6 @@ namespace PolyVox if (edgeTable[iCubeIndex] & 8) { m_sampVolume.movePositiveY(); - const typename VolumeType::VoxelType v010 = m_sampVolume.getVoxel(); POLYVOX_ASSERT(v000 != v010, "Attempting to insert vertex between two voxels with the same value"); const Vector3DFloat n010 = computeCentralDifferenceGradient(m_sampVolume); @@ -261,7 +233,6 @@ namespace PolyVox if (edgeTable[iCubeIndex] & 256) { m_sampVolume.movePositiveZ(); - const typename VolumeType::VoxelType v001 = m_sampVolume.getVoxel(); POLYVOX_ASSERT(v000 != v001, "Attempting to insert vertex between two voxels with the same value"); const Vector3DFloat n001 = computeCentralDifferenceGradient(m_sampVolume); @@ -291,7 +262,7 @@ namespace PolyVox m_sampVolume.moveNegativeZ(); } - }//For each cell + } } } } From 71adc7292ce84b5f471b4ff4f694385d9b7c91d1 Mon Sep 17 00:00:00 2001 From: David Williams Date: Thu, 14 May 2015 22:10:37 +0200 Subject: [PATCH 11/61] Restructuring code. --- .../PolyVox/MarchingCubesSurfaceExtractor.h | 2 - .../PolyVox/MarchingCubesSurfaceExtractor.inl | 188 ++++++++---------- 2 files changed, 84 insertions(+), 106 deletions(-) diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.h b/include/PolyVox/MarchingCubesSurfaceExtractor.h index e33f7a96..17f47463 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.h +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.h @@ -295,8 +295,6 @@ namespace PolyVox //Information about the region we are currently processing Region m_regSizeInVoxels; Region m_regSizeInCells; - Region m_regSlicePrevious; - Region m_regSliceCurrent; //Used to convert arbitrary voxel types in densities and materials. ControllerType m_controller; diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.inl b/include/PolyVox/MarchingCubesSurfaceExtractor.inl index d02bde54..d0584272 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.inl +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.inl @@ -61,26 +61,9 @@ namespace PolyVox Array3DUint8 pBitmask(uArrayWidth, uArrayHeight, uArrayDepth); - //Create a region corresponding to the first slice - m_regSlicePrevious = m_regSizeInVoxels; - Vector3DInt32 v3dUpperCorner = m_regSlicePrevious.getUpperCorner(); - v3dUpperCorner.setZ(m_regSlicePrevious.getLowerZ()); //Set the upper z to the lower z to make it one slice thick. - m_regSlicePrevious.setUpperCorner(v3dUpperCorner); - m_regSliceCurrent = m_regSlicePrevious; - computeBitmaskForSlice(pBitmask, pIndicesX, pIndicesY, pIndicesZ); - m_regSlicePrevious = m_regSliceCurrent; - m_regSliceCurrent.shift(Vector3DInt32(0,0,1)); - - //Process the other slices (previous slice is available) - for(int32_t uSlice = 1; uSlice <= m_regSizeInVoxels.getUpperZ() - m_regSizeInVoxels.getLowerZ(); uSlice++) - { - generateIndicesForSlice(pBitmask, pIndicesX, pIndicesY, pIndicesZ); - - m_regSlicePrevious = m_regSliceCurrent; - m_regSliceCurrent.shift(Vector3DInt32(0,0,1)); - } + generateIndicesForSlice(pBitmask, pIndicesX, pIndicesY, pIndicesZ); m_meshCurrent->setOffset(m_regSizeInVoxels.getLowerCorner()); @@ -100,15 +83,15 @@ namespace PolyVox const int32_t iMaxYVolSpace = m_regSizeInVoxels.getUpperY(); const int32_t iMaxZVolSpace = m_regSizeInVoxels.getUpperZ(); - for (int32_t iZVolSpace = m_regSliceCurrent.getLowerZ(); iZVolSpace <= iMaxZVolSpace; iZVolSpace++) + for (int32_t iZVolSpace = m_regSizeInVoxels.getLowerZ(); iZVolSpace <= iMaxZVolSpace; iZVolSpace++) { uint32_t uZRegSpace = iZVolSpace - m_regSizeInVoxels.getLowerZ(); //Process all remaining elemnents of the slice. In this case, previous x and y values are always available - for (int32_t iYVolSpace = m_regSliceCurrent.getLowerY(); iYVolSpace <= iMaxYVolSpace; iYVolSpace++) + for (int32_t iYVolSpace = m_regSizeInVoxels.getLowerY(); iYVolSpace <= iMaxYVolSpace; iYVolSpace++) { - m_sampVolume.setPosition(m_regSliceCurrent.getLowerX(), iYVolSpace, iZVolSpace); - for (int32_t iXVolSpace = m_regSliceCurrent.getLowerX(); iXVolSpace <= iMaxXVolSpace; iXVolSpace++) + m_sampVolume.setPosition(m_regSizeInVoxels.getLowerX(), iYVolSpace, iZVolSpace); + for (int32_t iXVolSpace = m_regSizeInVoxels.getLowerX(); iXVolSpace <= iMaxXVolSpace; iXVolSpace++) { uint32_t uXRegSpace = iXVolSpace - m_regSizeInVoxels.getLowerX(); uint32_t uYRegSpace = iYVolSpace - m_regSizeInVoxels.getLowerY(); @@ -273,96 +256,93 @@ namespace PolyVox const Array3DInt32& pIndicesY, const Array3DInt32& pIndicesZ) { - int32_t indlist[12]; - for(int i = 0; i < 12; i++) + for (int32_t iZVolSpace = m_regSizeInVoxels.getLowerZ(); iZVolSpace <= m_regSizeInCells.getUpperZ(); iZVolSpace++) { - indlist[i] = -1; - } - - const int32_t iZVolSpace = m_regSlicePrevious.getLowerZ(); - - for(int32_t iYVolSpace = m_regSlicePrevious.getLowerY(); iYVolSpace <= m_regSizeInCells.getUpperY(); iYVolSpace++) - { - for(int32_t iXVolSpace = m_regSlicePrevious.getLowerX(); iXVolSpace <= m_regSizeInCells.getUpperX(); iXVolSpace++) + for (int32_t iYVolSpace = m_regSizeInVoxels.getLowerY(); iYVolSpace <= m_regSizeInCells.getUpperY(); iYVolSpace++) { - m_sampVolume.setPosition(iXVolSpace,iYVolSpace,iZVolSpace); + for (int32_t iXVolSpace = m_regSizeInVoxels.getLowerX(); iXVolSpace <= m_regSizeInCells.getUpperX(); iXVolSpace++) + { + int32_t indlist[12]; - //Current position - const uint32_t uXRegSpace = m_sampVolume.getPosition().getX() - m_regSizeInVoxels.getLowerX(); - const uint32_t uYRegSpace = m_sampVolume.getPosition().getY() - m_regSizeInVoxels.getLowerY(); - const uint32_t uZRegSpace = m_sampVolume.getPosition().getZ() - m_regSizeInVoxels.getLowerZ(); + m_sampVolume.setPosition(iXVolSpace, iYVolSpace, iZVolSpace); - //Determine the index into the edge table which tells us which vertices are inside of the surface - const uint8_t iCubeIndex = pBitmask(uXRegSpace, uYRegSpace, uZRegSpace); + //Current position + const uint32_t uXRegSpace = m_sampVolume.getPosition().getX() - m_regSizeInVoxels.getLowerX(); + const uint32_t uYRegSpace = m_sampVolume.getPosition().getY() - m_regSizeInVoxels.getLowerY(); + const uint32_t uZRegSpace = m_sampVolume.getPosition().getZ() - m_regSizeInVoxels.getLowerZ(); - /* Cube is entirely in/out of the surface */ - if (edgeTable[iCubeIndex] == 0) - { - continue; - } + //Determine the index into the edge table which tells us which vertices are inside of the surface + const uint8_t iCubeIndex = pBitmask(uXRegSpace, uYRegSpace, uZRegSpace); - /* Find the vertices where the surface intersects the cube */ - if (edgeTable[iCubeIndex] & 1) - { - indlist[0] = pIndicesX(uXRegSpace, uYRegSpace, uZRegSpace); - } - if (edgeTable[iCubeIndex] & 2) - { - indlist[1] = pIndicesY(uXRegSpace + 1, uYRegSpace, uZRegSpace); - } - if (edgeTable[iCubeIndex] & 4) - { - indlist[2] = pIndicesX(uXRegSpace, uYRegSpace + 1, uZRegSpace); - } - if (edgeTable[iCubeIndex] & 8) - { - indlist[3] = pIndicesY(uXRegSpace, uYRegSpace, uZRegSpace); - } - if (edgeTable[iCubeIndex] & 16) - { - indlist[4] = pIndicesX(uXRegSpace, uYRegSpace, uZRegSpace + 1); - } - if (edgeTable[iCubeIndex] & 32) - { - indlist[5] = pIndicesY(uXRegSpace + 1, uYRegSpace, uZRegSpace + 1); - } - if (edgeTable[iCubeIndex] & 64) - { - indlist[6] = pIndicesX(uXRegSpace, uYRegSpace + 1, uZRegSpace + 1); - } - if (edgeTable[iCubeIndex] & 128) - { - indlist[7] = pIndicesY(uXRegSpace, uYRegSpace, uZRegSpace + 1); - } - if (edgeTable[iCubeIndex] & 256) - { - indlist[8] = pIndicesZ(uXRegSpace, uYRegSpace, uZRegSpace); - } - if (edgeTable[iCubeIndex] & 512) - { - indlist[9] = pIndicesZ(uXRegSpace + 1, uYRegSpace, uZRegSpace); - } - if (edgeTable[iCubeIndex] & 1024) - { - indlist[10] = pIndicesZ(uXRegSpace + 1, uYRegSpace + 1, uZRegSpace); - } - if (edgeTable[iCubeIndex] & 2048) - { - indlist[11] = pIndicesZ(uXRegSpace, uYRegSpace + 1, uZRegSpace); - } - - for (int i=0;triTable[iCubeIndex][i]!=-1;i+=3) - { - const int32_t ind0 = indlist[triTable[iCubeIndex][i ]]; - const int32_t ind1 = indlist[triTable[iCubeIndex][i+1]]; - const int32_t ind2 = indlist[triTable[iCubeIndex][i+2]]; - - if((ind0 != -1) && (ind1 != -1) && (ind2 != -1)) + /* Cube is entirely in/out of the surface */ + if (edgeTable[iCubeIndex] == 0) { - m_meshCurrent->addTriangle(ind0, ind1, ind2); + continue; } - }//For each triangle - }//For each cell + + /* Find the vertices where the surface intersects the cube */ + if (edgeTable[iCubeIndex] & 1) + { + indlist[0] = pIndicesX(uXRegSpace, uYRegSpace, uZRegSpace); + } + if (edgeTable[iCubeIndex] & 2) + { + indlist[1] = pIndicesY(uXRegSpace + 1, uYRegSpace, uZRegSpace); + } + if (edgeTable[iCubeIndex] & 4) + { + indlist[2] = pIndicesX(uXRegSpace, uYRegSpace + 1, uZRegSpace); + } + if (edgeTable[iCubeIndex] & 8) + { + indlist[3] = pIndicesY(uXRegSpace, uYRegSpace, uZRegSpace); + } + if (edgeTable[iCubeIndex] & 16) + { + indlist[4] = pIndicesX(uXRegSpace, uYRegSpace, uZRegSpace + 1); + } + if (edgeTable[iCubeIndex] & 32) + { + indlist[5] = pIndicesY(uXRegSpace + 1, uYRegSpace, uZRegSpace + 1); + } + if (edgeTable[iCubeIndex] & 64) + { + indlist[6] = pIndicesX(uXRegSpace, uYRegSpace + 1, uZRegSpace + 1); + } + if (edgeTable[iCubeIndex] & 128) + { + indlist[7] = pIndicesY(uXRegSpace, uYRegSpace, uZRegSpace + 1); + } + if (edgeTable[iCubeIndex] & 256) + { + indlist[8] = pIndicesZ(uXRegSpace, uYRegSpace, uZRegSpace); + } + if (edgeTable[iCubeIndex] & 512) + { + indlist[9] = pIndicesZ(uXRegSpace + 1, uYRegSpace, uZRegSpace); + } + if (edgeTable[iCubeIndex] & 1024) + { + indlist[10] = pIndicesZ(uXRegSpace + 1, uYRegSpace + 1, uZRegSpace); + } + if (edgeTable[iCubeIndex] & 2048) + { + indlist[11] = pIndicesZ(uXRegSpace, uYRegSpace + 1, uZRegSpace); + } + + for (int i = 0; triTable[iCubeIndex][i] != -1; i += 3) + { + const int32_t ind0 = indlist[triTable[iCubeIndex][i]]; + const int32_t ind1 = indlist[triTable[iCubeIndex][i + 1]]; + const int32_t ind2 = indlist[triTable[iCubeIndex][i + 2]]; + + if ((ind0 != -1) && (ind1 != -1) && (ind2 != -1)) + { + m_meshCurrent->addTriangle(ind0, ind1, ind2); + } + }//For each triangle + }//For each cell + } } } } From b4267b11f508671b5af6c5596ff92ea0c83916a4 Mon Sep 17 00:00:00 2001 From: David Williams Date: Fri, 15 May 2015 09:57:32 +0200 Subject: [PATCH 12/61] More refactoring code. --- .../PolyVox/MarchingCubesSurfaceExtractor.h | 7 -- .../PolyVox/MarchingCubesSurfaceExtractor.inl | 116 +++++++----------- 2 files changed, 41 insertions(+), 82 deletions(-) diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.h b/include/PolyVox/MarchingCubesSurfaceExtractor.h index 17f47463..3a14afa1 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.h +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.h @@ -279,12 +279,6 @@ namespace PolyVox // End of compiler bug workaroumd. //////////////////////////////////////////////////////////////////////////////// - //Use the cell bitmasks to generate all the indices needed for that slice - void generateIndicesForSlice(const Array3DUint8& pBitmask, - const Array3DInt32& pIndicesX, - const Array3DInt32& pIndicesY, - const Array3DInt32& pIndicesZ); - //The volume data and a sampler to access it. VolumeType* m_volData; typename VolumeType::Sampler m_sampVolume; @@ -294,7 +288,6 @@ namespace PolyVox //Information about the region we are currently processing Region m_regSizeInVoxels; - Region m_regSizeInCells; //Used to convert arbitrary voxel types in densities and materials. ControllerType m_controller; diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.inl b/include/PolyVox/MarchingCubesSurfaceExtractor.inl index d0584272..5647bab6 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.inl +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.inl @@ -35,9 +35,6 @@ namespace PolyVox ,m_tThreshold(m_controller.getThreshold()) { POLYVOX_THROW_IF(m_meshCurrent == nullptr, std::invalid_argument, "Provided mesh cannot be null"); - //m_regSizeInVoxels.cropTo(m_volData->getEnclosingRegion()); - m_regSizeInCells = m_regSizeInVoxels; - m_regSizeInCells.setUpperCorner(m_regSizeInCells.getUpperCorner() - Vector3DInt32(1,1,1)); } template @@ -63,8 +60,6 @@ namespace PolyVox computeBitmaskForSlice(pBitmask, pIndicesX, pIndicesY, pIndicesZ); - generateIndicesForSlice(pBitmask, pIndicesX, pIndicesY, pIndicesZ); - m_meshCurrent->setOffset(m_regSizeInVoxels.getLowerCorner()); POLYVOX_LOG_TRACE("Marching cubes surface extraction took ", timer.elapsedTimeInMilliSeconds(), @@ -79,49 +74,31 @@ namespace PolyVox Array3DInt32& pIndicesY, Array3DInt32& pIndicesZ) { - const int32_t iMaxXVolSpace = m_regSizeInVoxels.getUpperX(); - const int32_t iMaxYVolSpace = m_regSizeInVoxels.getUpperY(); - const int32_t iMaxZVolSpace = m_regSizeInVoxels.getUpperZ(); - - for (int32_t iZVolSpace = m_regSizeInVoxels.getLowerZ(); iZVolSpace <= iMaxZVolSpace; iZVolSpace++) + for (int32_t iZVolSpace = m_regSizeInVoxels.getLowerZ() + 1; iZVolSpace <= m_regSizeInVoxels.getUpperZ(); iZVolSpace++) { - uint32_t uZRegSpace = iZVolSpace - m_regSizeInVoxels.getLowerZ(); + const uint32_t uZRegSpace = iZVolSpace - m_regSizeInVoxels.getLowerZ(); - //Process all remaining elemnents of the slice. In this case, previous x and y values are always available - for (int32_t iYVolSpace = m_regSizeInVoxels.getLowerY(); iYVolSpace <= iMaxYVolSpace; iYVolSpace++) + for (int32_t iYVolSpace = m_regSizeInVoxels.getLowerY() + 1; iYVolSpace <= m_regSizeInVoxels.getUpperY(); iYVolSpace++) { - m_sampVolume.setPosition(m_regSizeInVoxels.getLowerX(), iYVolSpace, iZVolSpace); - for (int32_t iXVolSpace = m_regSizeInVoxels.getLowerX(); iXVolSpace <= iMaxXVolSpace; iXVolSpace++) - { - uint32_t uXRegSpace = iXVolSpace - m_regSizeInVoxels.getLowerX(); - uint32_t uYRegSpace = iYVolSpace - m_regSizeInVoxels.getLowerY(); + const uint32_t uYRegSpace = iYVolSpace - m_regSizeInVoxels.getLowerY(); - m_sampVolume.movePositiveX(); + for (int32_t iXVolSpace = m_regSizeInVoxels.getLowerX() + 1; iXVolSpace <= m_regSizeInVoxels.getUpperX(); iXVolSpace++) + { + const uint32_t uXRegSpace = iXVolSpace - m_regSizeInVoxels.getLowerX(); m_sampVolume.setPosition(iXVolSpace, iYVolSpace, iZVolSpace); + typename VolumeType::VoxelType v000 = m_sampVolume.peekVoxel1nx1ny1nz(); + typename VolumeType::VoxelType v100 = m_sampVolume.peekVoxel0px1ny1nz(); + typename VolumeType::VoxelType v010 = m_sampVolume.peekVoxel1nx0py1nz(); + typename VolumeType::VoxelType v110 = m_sampVolume.peekVoxel0px0py1nz(); + + typename VolumeType::VoxelType v001 = m_sampVolume.peekVoxel1nx1ny0pz(); + typename VolumeType::VoxelType v101 = m_sampVolume.peekVoxel0px1ny0pz(); + typename VolumeType::VoxelType v011 = m_sampVolume.peekVoxel1nx0py0pz(); + typename VolumeType::VoxelType v111 = m_sampVolume.peekVoxel0px0py0pz(); + uint8_t iCubeIndex = 0; - - typename VolumeType::VoxelType v000 = m_sampVolume.getVoxel(); - typename VolumeType::VoxelType v100 = m_sampVolume.peekVoxel1px0py0pz(); - typename VolumeType::VoxelType v010 = m_sampVolume.peekVoxel0px1py0pz(); - typename VolumeType::VoxelType v110 = m_sampVolume.peekVoxel1px1py0pz(); - - typename VolumeType::VoxelType v001 = m_sampVolume.peekVoxel0px0py1pz(); - typename VolumeType::VoxelType v101 = m_sampVolume.peekVoxel1px0py1pz(); - typename VolumeType::VoxelType v011 = m_sampVolume.peekVoxel0px1py1pz(); - typename VolumeType::VoxelType v111 = m_sampVolume.peekVoxel1px1py1pz(); - - /*typename VolumeType::VoxelType v000 = m_sampVolume.peekVoxel0px0py1nz(); - typename VolumeType::VoxelType v100 = m_sampVolume.peekVoxel1px0py1nz(); - typename VolumeType::VoxelType v010 = m_sampVolume.peekVoxel0px1py1nz(); - typename VolumeType::VoxelType v110 = m_sampVolume.peekVoxel1px1py1nz(); - - typename VolumeType::VoxelType v001 = m_sampVolume.peekVoxel0px0py0pz(); - typename VolumeType::VoxelType v101 = m_sampVolume.peekVoxel1px0py0pz(); - typename VolumeType::VoxelType v011 = m_sampVolume.peekVoxel0px1py0pz(); - typename VolumeType::VoxelType v111 = m_sampVolume.peekVoxel1px1py0pz();*/ - if (m_controller.convertToDensity(v000) < m_tThreshold) iCubeIndex |= 1; if (m_controller.convertToDensity(v100) < m_tThreshold) iCubeIndex |= 2; if (m_controller.convertToDensity(v010) < m_tThreshold) iCubeIndex |= 4; @@ -132,18 +109,14 @@ namespace PolyVox if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128; //Save the bitmask - pBitmask(uXRegSpace, uYRegSpace, uZRegSpace) = iCubeIndex; + pBitmask(uXRegSpace-1, uYRegSpace-1, uZRegSpace-1) = iCubeIndex; /* Cube is entirely in/out of the surface */ if (edgeTable[iCubeIndex] == 0) { continue; } - - //Check whether the generated vertex will lie on the edge of the region - - - m_sampVolume.setPosition(iXVolSpace, iYVolSpace, iZVolSpace); + const Vector3DFloat n000 = computeCentralDifferenceGradient(m_sampVolume); /* Find the vertices where the surface intersects the cube */ @@ -155,7 +128,7 @@ namespace PolyVox const float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v000)) / static_cast(m_controller.convertToDensity(v100) - m_controller.convertToDensity(v000)); - const Vector3DFloat v3dPosition(static_cast(iXVolSpace - m_regSizeInVoxels.getLowerX()) + fInterp, static_cast(iYVolSpace - m_regSizeInVoxels.getLowerY()), static_cast(iZVolSpace - m_regSizeInCells.getLowerZ())); + const Vector3DFloat v3dPosition(static_cast(uXRegSpace - 1) + fInterp, static_cast(uYRegSpace), static_cast(uZRegSpace)); const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); Vector3DFloat v3dNormal = (n100*fInterp) + (n000*(1 - fInterp)); @@ -176,7 +149,7 @@ namespace PolyVox surfaceVertex.data = uMaterial; const uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex); - pIndicesX(iXVolSpace - m_regSizeInVoxels.getLowerX(), iYVolSpace - m_regSizeInVoxels.getLowerY(), iZVolSpace - m_regSizeInVoxels.getLowerZ()) = uLastVertexIndex; + pIndicesX(uXRegSpace - 1, uYRegSpace - 1, uZRegSpace - 1) = uLastVertexIndex; m_sampVolume.moveNegativeX(); } @@ -188,7 +161,7 @@ namespace PolyVox const float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v000)) / static_cast(m_controller.convertToDensity(v010) - m_controller.convertToDensity(v000)); - const Vector3DFloat v3dPosition(static_cast(iXVolSpace - m_regSizeInVoxels.getLowerX()), static_cast(iYVolSpace - m_regSizeInVoxels.getLowerY()) + fInterp, static_cast(iZVolSpace - m_regSizeInVoxels.getLowerZ())); + const Vector3DFloat v3dPosition(static_cast(uXRegSpace), static_cast(uYRegSpace - 1) + fInterp, static_cast(uZRegSpace)); const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); Vector3DFloat v3dNormal = (n010*fInterp) + (n000*(1 - fInterp)); @@ -209,7 +182,7 @@ namespace PolyVox surfaceVertex.data = uMaterial; uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex); - pIndicesY(iXVolSpace - m_regSizeInVoxels.getLowerX(), iYVolSpace - m_regSizeInVoxels.getLowerY(), iZVolSpace - m_regSizeInVoxels.getLowerZ()) = uLastVertexIndex; + pIndicesY(uXRegSpace - 1, uYRegSpace - 1, uZRegSpace - 1) = uLastVertexIndex; m_sampVolume.moveNegativeY(); } @@ -221,7 +194,7 @@ namespace PolyVox const float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v000)) / static_cast(m_controller.convertToDensity(v001) - m_controller.convertToDensity(v000)); - const Vector3DFloat v3dPosition(static_cast(iXVolSpace - m_regSizeInVoxels.getLowerX()), static_cast(iYVolSpace - m_regSizeInVoxels.getLowerY()), static_cast(iZVolSpace - m_regSizeInVoxels.getLowerZ()) + fInterp); + const Vector3DFloat v3dPosition(static_cast(uXRegSpace), static_cast(uYRegSpace), static_cast(uZRegSpace - 1) + fInterp); const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); Vector3DFloat v3dNormal = (n001*fInterp) + (n000*(1 - fInterp)); @@ -241,26 +214,19 @@ namespace PolyVox surfaceVertex.data = uMaterial; const uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex); - pIndicesZ(iXVolSpace - m_regSizeInVoxels.getLowerX(), iYVolSpace - m_regSizeInVoxels.getLowerY(), iZVolSpace - m_regSizeInVoxels.getLowerZ()) = uLastVertexIndex; + pIndicesZ(uXRegSpace - 1, uYRegSpace - 1, uZRegSpace - 1) = uLastVertexIndex; m_sampVolume.moveNegativeZ(); } } } } - } - template - void MarchingCubesSurfaceExtractor::generateIndicesForSlice(const Array3DUint8& pBitmask, - const Array3DInt32& pIndicesX, - const Array3DInt32& pIndicesY, - const Array3DInt32& pIndicesZ) - { - for (int32_t iZVolSpace = m_regSizeInVoxels.getLowerZ(); iZVolSpace <= m_regSizeInCells.getUpperZ(); iZVolSpace++) + for (int32_t iZVolSpace = m_regSizeInVoxels.getLowerZ() + 1; iZVolSpace <= m_regSizeInVoxels.getUpperZ(); iZVolSpace++) { - for (int32_t iYVolSpace = m_regSizeInVoxels.getLowerY(); iYVolSpace <= m_regSizeInCells.getUpperY(); iYVolSpace++) + for (int32_t iYVolSpace = m_regSizeInVoxels.getLowerY() + 1; iYVolSpace <= m_regSizeInVoxels.getUpperY(); iYVolSpace++) { - for (int32_t iXVolSpace = m_regSizeInVoxels.getLowerX(); iXVolSpace <= m_regSizeInCells.getUpperX(); iXVolSpace++) + for (int32_t iXVolSpace = m_regSizeInVoxels.getLowerX() + 1; iXVolSpace <= m_regSizeInVoxels.getUpperX(); iXVolSpace++) { int32_t indlist[12]; @@ -272,7 +238,7 @@ namespace PolyVox const uint32_t uZRegSpace = m_sampVolume.getPosition().getZ() - m_regSizeInVoxels.getLowerZ(); //Determine the index into the edge table which tells us which vertices are inside of the surface - const uint8_t iCubeIndex = pBitmask(uXRegSpace, uYRegSpace, uZRegSpace); + const uint8_t iCubeIndex = pBitmask(uXRegSpace - 1, uYRegSpace - 1, uZRegSpace - 1); /* Cube is entirely in/out of the surface */ if (edgeTable[iCubeIndex] == 0) @@ -283,51 +249,51 @@ namespace PolyVox /* Find the vertices where the surface intersects the cube */ if (edgeTable[iCubeIndex] & 1) { - indlist[0] = pIndicesX(uXRegSpace, uYRegSpace, uZRegSpace); + indlist[0] = pIndicesX(uXRegSpace - 1, uYRegSpace - 1, uZRegSpace - 1); } if (edgeTable[iCubeIndex] & 2) { - indlist[1] = pIndicesY(uXRegSpace + 1, uYRegSpace, uZRegSpace); + indlist[1] = pIndicesY(uXRegSpace, uYRegSpace - 1, uZRegSpace - 1); } if (edgeTable[iCubeIndex] & 4) { - indlist[2] = pIndicesX(uXRegSpace, uYRegSpace + 1, uZRegSpace); + indlist[2] = pIndicesX(uXRegSpace - 1, uYRegSpace, uZRegSpace - 1); } if (edgeTable[iCubeIndex] & 8) { - indlist[3] = pIndicesY(uXRegSpace, uYRegSpace, uZRegSpace); + indlist[3] = pIndicesY(uXRegSpace - 1, uYRegSpace - 1, uZRegSpace - 1); } if (edgeTable[iCubeIndex] & 16) { - indlist[4] = pIndicesX(uXRegSpace, uYRegSpace, uZRegSpace + 1); + indlist[4] = pIndicesX(uXRegSpace - 1, uYRegSpace - 1, uZRegSpace); } if (edgeTable[iCubeIndex] & 32) { - indlist[5] = pIndicesY(uXRegSpace + 1, uYRegSpace, uZRegSpace + 1); + indlist[5] = pIndicesY(uXRegSpace, uYRegSpace - 1, uZRegSpace); } if (edgeTable[iCubeIndex] & 64) { - indlist[6] = pIndicesX(uXRegSpace, uYRegSpace + 1, uZRegSpace + 1); + indlist[6] = pIndicesX(uXRegSpace - 1, uYRegSpace, uZRegSpace); } if (edgeTable[iCubeIndex] & 128) { - indlist[7] = pIndicesY(uXRegSpace, uYRegSpace, uZRegSpace + 1); + indlist[7] = pIndicesY(uXRegSpace - 1, uYRegSpace - 1, uZRegSpace); } if (edgeTable[iCubeIndex] & 256) { - indlist[8] = pIndicesZ(uXRegSpace, uYRegSpace, uZRegSpace); + indlist[8] = pIndicesZ(uXRegSpace - 1, uYRegSpace - 1, uZRegSpace - 1); } if (edgeTable[iCubeIndex] & 512) { - indlist[9] = pIndicesZ(uXRegSpace + 1, uYRegSpace, uZRegSpace); + indlist[9] = pIndicesZ(uXRegSpace, uYRegSpace - 1, uZRegSpace - 1); } if (edgeTable[iCubeIndex] & 1024) { - indlist[10] = pIndicesZ(uXRegSpace + 1, uYRegSpace + 1, uZRegSpace); + indlist[10] = pIndicesZ(uXRegSpace, uYRegSpace, uZRegSpace - 1); } if (edgeTable[iCubeIndex] & 2048) { - indlist[11] = pIndicesZ(uXRegSpace, uYRegSpace + 1, uZRegSpace); + indlist[11] = pIndicesZ(uXRegSpace - 1, uYRegSpace, uZRegSpace - 1); } for (int i = 0; triTable[iCubeIndex][i] != -1; i += 3) From 227b11a7643a6ad712eb7839e125e4083f0c3e4f Mon Sep 17 00:00:00 2001 From: David Williams Date: Fri, 15 May 2015 10:03:29 +0200 Subject: [PATCH 13/61] Cleared array. --- include/PolyVox/MarchingCubesSurfaceExtractor.inl | 1 + 1 file changed, 1 insertion(+) diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.inl b/include/PolyVox/MarchingCubesSurfaceExtractor.inl index 5647bab6..b1a5bb3e 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.inl +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.inl @@ -57,6 +57,7 @@ namespace PolyVox memset(pIndicesZ.getRawData(), 0xff, pIndicesZ.getNoOfElements() * 4); Array3DUint8 pBitmask(uArrayWidth, uArrayHeight, uArrayDepth); + memset(pBitmask.getRawData(), 0x00, pBitmask.getNoOfElements()); computeBitmaskForSlice(pBitmask, pIndicesX, pIndicesY, pIndicesZ); From 0e8c90c6ee7957d71738fae54ab0c983d585ea0a Mon Sep 17 00:00:00 2001 From: David Williams Date: Sat, 16 May 2015 09:00:04 +0200 Subject: [PATCH 14/61] More refactoring... --- .../PolyVox/MarchingCubesSurfaceExtractor.inl | 84 +++++++++++-------- 1 file changed, 47 insertions(+), 37 deletions(-) diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.inl b/include/PolyVox/MarchingCubesSurfaceExtractor.inl index b1a5bb3e..5b657736 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.inl +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.inl @@ -43,9 +43,9 @@ namespace PolyVox Timer timer; m_meshCurrent->clear(); - const uint32_t uArrayWidth = m_regSizeInVoxels.getUpperX() - m_regSizeInVoxels.getLowerX() + 1; - const uint32_t uArrayHeight = m_regSizeInVoxels.getUpperY() - m_regSizeInVoxels.getLowerY() + 1; - const uint32_t uArrayDepth = m_regSizeInVoxels.getUpperZ() - m_regSizeInVoxels.getLowerZ() + 1; + const uint32_t uArrayWidth = m_regSizeInVoxels.getUpperX() - m_regSizeInVoxels.getLowerX() + 2; + const uint32_t uArrayHeight = m_regSizeInVoxels.getUpperY() - m_regSizeInVoxels.getLowerY() + 2; + const uint32_t uArrayDepth = m_regSizeInVoxels.getUpperZ() - m_regSizeInVoxels.getLowerZ() + 2; //For edge indices Array3DInt32 pIndicesX(uArrayWidth, uArrayHeight, uArrayDepth); @@ -75,29 +75,39 @@ namespace PolyVox Array3DInt32& pIndicesY, Array3DInt32& pIndicesZ) { - for (int32_t iZVolSpace = m_regSizeInVoxels.getLowerZ() + 1; iZVolSpace <= m_regSizeInVoxels.getUpperZ(); iZVolSpace++) + for (int32_t iZVolSpace = m_regSizeInVoxels.getLowerZ() + 1; iZVolSpace <= m_regSizeInVoxels.getUpperZ() - 1; iZVolSpace++) { const uint32_t uZRegSpace = iZVolSpace - m_regSizeInVoxels.getLowerZ(); - for (int32_t iYVolSpace = m_regSizeInVoxels.getLowerY() + 1; iYVolSpace <= m_regSizeInVoxels.getUpperY(); iYVolSpace++) + for (int32_t iYVolSpace = m_regSizeInVoxels.getLowerY() + 1; iYVolSpace <= m_regSizeInVoxels.getUpperY() - 1; iYVolSpace++) { const uint32_t uYRegSpace = iYVolSpace - m_regSizeInVoxels.getLowerY(); - for (int32_t iXVolSpace = m_regSizeInVoxels.getLowerX() + 1; iXVolSpace <= m_regSizeInVoxels.getUpperX(); iXVolSpace++) + for (int32_t iXVolSpace = m_regSizeInVoxels.getLowerX() + 1; iXVolSpace <= m_regSizeInVoxels.getUpperX() - 1; iXVolSpace++) { const uint32_t uXRegSpace = iXVolSpace - m_regSizeInVoxels.getLowerX(); m_sampVolume.setPosition(iXVolSpace, iYVolSpace, iZVolSpace); - typename VolumeType::VoxelType v000 = m_sampVolume.peekVoxel1nx1ny1nz(); - typename VolumeType::VoxelType v100 = m_sampVolume.peekVoxel0px1ny1nz(); - typename VolumeType::VoxelType v010 = m_sampVolume.peekVoxel1nx0py1nz(); - typename VolumeType::VoxelType v110 = m_sampVolume.peekVoxel0px0py1nz(); + /*typename VolumeType::VoxelType v000 = m_regSizeInVoxels.containsPoint(iXVolSpace, iYVolSpace, iZVolSpace, 1) ? m_sampVolume.peekVoxel1nx1ny1nz() : VolumeType::VoxelType(); + typename VolumeType::VoxelType v100 = m_regSizeInVoxels.containsPoint(iXVolSpace, iYVolSpace, iZVolSpace, 1) ? m_sampVolume.peekVoxel0px1ny1nz() : VolumeType::VoxelType(); + typename VolumeType::VoxelType v010 = m_regSizeInVoxels.containsPoint(iXVolSpace, iYVolSpace, iZVolSpace, 1) ? m_sampVolume.peekVoxel1nx0py1nz() : VolumeType::VoxelType(); + typename VolumeType::VoxelType v110 = m_regSizeInVoxels.containsPoint(iXVolSpace, iYVolSpace, iZVolSpace, 1) ? m_sampVolume.peekVoxel0px0py1nz() : VolumeType::VoxelType(); - typename VolumeType::VoxelType v001 = m_sampVolume.peekVoxel1nx1ny0pz(); - typename VolumeType::VoxelType v101 = m_sampVolume.peekVoxel0px1ny0pz(); - typename VolumeType::VoxelType v011 = m_sampVolume.peekVoxel1nx0py0pz(); - typename VolumeType::VoxelType v111 = m_sampVolume.peekVoxel0px0py0pz(); + typename VolumeType::VoxelType v001 = m_regSizeInVoxels.containsPoint(iXVolSpace, iYVolSpace, iZVolSpace, 1) ? m_sampVolume.peekVoxel1nx1ny0pz() : VolumeType::VoxelType(); + typename VolumeType::VoxelType v101 = m_regSizeInVoxels.containsPoint(iXVolSpace, iYVolSpace, iZVolSpace, 1) ? m_sampVolume.peekVoxel0px1ny0pz() : VolumeType::VoxelType(); + typename VolumeType::VoxelType v011 = m_regSizeInVoxels.containsPoint(iXVolSpace, iYVolSpace, iZVolSpace, 1) ? m_sampVolume.peekVoxel1nx0py0pz() : VolumeType::VoxelType(); + typename VolumeType::VoxelType v111 = m_regSizeInVoxels.containsPoint(iXVolSpace, iYVolSpace, iZVolSpace, 1) ? m_sampVolume.peekVoxel0px0py0pz() : VolumeType::VoxelType();*/ + + typename VolumeType::VoxelType v000 = m_sampVolume.peekVoxel0px0py0pz(); + typename VolumeType::VoxelType v100 = m_sampVolume.peekVoxel1px0py0pz(); + typename VolumeType::VoxelType v010 = m_sampVolume.peekVoxel0px1py0pz(); + typename VolumeType::VoxelType v110 = m_sampVolume.peekVoxel1px1py0pz(); + + typename VolumeType::VoxelType v001 = m_sampVolume.peekVoxel0px0py1pz(); + typename VolumeType::VoxelType v101 = m_sampVolume.peekVoxel1px0py1pz(); + typename VolumeType::VoxelType v011 = m_sampVolume.peekVoxel0px1py1pz(); + typename VolumeType::VoxelType v111 = m_sampVolume.peekVoxel1px1py1pz(); uint8_t iCubeIndex = 0; if (m_controller.convertToDensity(v000) < m_tThreshold) iCubeIndex |= 1; @@ -110,7 +120,7 @@ namespace PolyVox if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128; //Save the bitmask - pBitmask(uXRegSpace-1, uYRegSpace-1, uZRegSpace-1) = iCubeIndex; + pBitmask(uXRegSpace, uYRegSpace, uZRegSpace) = iCubeIndex; /* Cube is entirely in/out of the surface */ if (edgeTable[iCubeIndex] == 0) @@ -129,7 +139,7 @@ namespace PolyVox const float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v000)) / static_cast(m_controller.convertToDensity(v100) - m_controller.convertToDensity(v000)); - const Vector3DFloat v3dPosition(static_cast(uXRegSpace - 1) + fInterp, static_cast(uYRegSpace), static_cast(uZRegSpace)); + const Vector3DFloat v3dPosition(static_cast(uXRegSpace ) + fInterp, static_cast(uYRegSpace), static_cast(uZRegSpace)); const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); Vector3DFloat v3dNormal = (n100*fInterp) + (n000*(1 - fInterp)); @@ -150,7 +160,7 @@ namespace PolyVox surfaceVertex.data = uMaterial; const uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex); - pIndicesX(uXRegSpace - 1, uYRegSpace - 1, uZRegSpace - 1) = uLastVertexIndex; + pIndicesX(uXRegSpace, uYRegSpace, uZRegSpace) = uLastVertexIndex; m_sampVolume.moveNegativeX(); } @@ -162,7 +172,7 @@ namespace PolyVox const float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v000)) / static_cast(m_controller.convertToDensity(v010) - m_controller.convertToDensity(v000)); - const Vector3DFloat v3dPosition(static_cast(uXRegSpace), static_cast(uYRegSpace - 1) + fInterp, static_cast(uZRegSpace)); + const Vector3DFloat v3dPosition(static_cast(uXRegSpace), static_cast(uYRegSpace ) + fInterp, static_cast(uZRegSpace)); const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); Vector3DFloat v3dNormal = (n010*fInterp) + (n000*(1 - fInterp)); @@ -183,7 +193,7 @@ namespace PolyVox surfaceVertex.data = uMaterial; uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex); - pIndicesY(uXRegSpace - 1, uYRegSpace - 1, uZRegSpace - 1) = uLastVertexIndex; + pIndicesY(uXRegSpace, uYRegSpace, uZRegSpace) = uLastVertexIndex; m_sampVolume.moveNegativeY(); } @@ -195,7 +205,7 @@ namespace PolyVox const float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v000)) / static_cast(m_controller.convertToDensity(v001) - m_controller.convertToDensity(v000)); - const Vector3DFloat v3dPosition(static_cast(uXRegSpace), static_cast(uYRegSpace), static_cast(uZRegSpace - 1) + fInterp); + const Vector3DFloat v3dPosition(static_cast(uXRegSpace), static_cast(uYRegSpace), static_cast(uZRegSpace) + fInterp); const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); Vector3DFloat v3dNormal = (n001*fInterp) + (n000*(1 - fInterp)); @@ -215,7 +225,7 @@ namespace PolyVox surfaceVertex.data = uMaterial; const uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex); - pIndicesZ(uXRegSpace - 1, uYRegSpace - 1, uZRegSpace - 1) = uLastVertexIndex; + pIndicesZ(uXRegSpace, uYRegSpace, uZRegSpace) = uLastVertexIndex; m_sampVolume.moveNegativeZ(); } @@ -223,11 +233,11 @@ namespace PolyVox } } - for (int32_t iZVolSpace = m_regSizeInVoxels.getLowerZ() + 1; iZVolSpace <= m_regSizeInVoxels.getUpperZ(); iZVolSpace++) + for (int32_t iZVolSpace = m_regSizeInVoxels.getLowerZ() + 2; iZVolSpace <= m_regSizeInVoxels.getUpperZ() - 2; iZVolSpace++) { - for (int32_t iYVolSpace = m_regSizeInVoxels.getLowerY() + 1; iYVolSpace <= m_regSizeInVoxels.getUpperY(); iYVolSpace++) + for (int32_t iYVolSpace = m_regSizeInVoxels.getLowerY() + 2; iYVolSpace <= m_regSizeInVoxels.getUpperY() - 2; iYVolSpace++) { - for (int32_t iXVolSpace = m_regSizeInVoxels.getLowerX() + 1; iXVolSpace <= m_regSizeInVoxels.getUpperX(); iXVolSpace++) + for (int32_t iXVolSpace = m_regSizeInVoxels.getLowerX() + 2; iXVolSpace <= m_regSizeInVoxels.getUpperX() - 2; iXVolSpace++) { int32_t indlist[12]; @@ -239,7 +249,7 @@ namespace PolyVox const uint32_t uZRegSpace = m_sampVolume.getPosition().getZ() - m_regSizeInVoxels.getLowerZ(); //Determine the index into the edge table which tells us which vertices are inside of the surface - const uint8_t iCubeIndex = pBitmask(uXRegSpace - 1, uYRegSpace - 1, uZRegSpace - 1); + const uint8_t iCubeIndex = pBitmask(uXRegSpace, uYRegSpace, uZRegSpace); /* Cube is entirely in/out of the surface */ if (edgeTable[iCubeIndex] == 0) @@ -250,51 +260,51 @@ namespace PolyVox /* Find the vertices where the surface intersects the cube */ if (edgeTable[iCubeIndex] & 1) { - indlist[0] = pIndicesX(uXRegSpace - 1, uYRegSpace - 1, uZRegSpace - 1); + indlist[0] = pIndicesX(uXRegSpace, uYRegSpace, uZRegSpace); } if (edgeTable[iCubeIndex] & 2) { - indlist[1] = pIndicesY(uXRegSpace, uYRegSpace - 1, uZRegSpace - 1); + indlist[1] = pIndicesY(uXRegSpace + 1, uYRegSpace, uZRegSpace); } if (edgeTable[iCubeIndex] & 4) { - indlist[2] = pIndicesX(uXRegSpace - 1, uYRegSpace, uZRegSpace - 1); + indlist[2] = pIndicesX(uXRegSpace, uYRegSpace + 1, uZRegSpace); } if (edgeTable[iCubeIndex] & 8) { - indlist[3] = pIndicesY(uXRegSpace - 1, uYRegSpace - 1, uZRegSpace - 1); + indlist[3] = pIndicesY(uXRegSpace, uYRegSpace, uZRegSpace); } if (edgeTable[iCubeIndex] & 16) { - indlist[4] = pIndicesX(uXRegSpace - 1, uYRegSpace - 1, uZRegSpace); + indlist[4] = pIndicesX(uXRegSpace, uYRegSpace, uZRegSpace + 1); } if (edgeTable[iCubeIndex] & 32) { - indlist[5] = pIndicesY(uXRegSpace, uYRegSpace - 1, uZRegSpace); + indlist[5] = pIndicesY(uXRegSpace + 1, uYRegSpace, uZRegSpace + 1); } if (edgeTable[iCubeIndex] & 64) { - indlist[6] = pIndicesX(uXRegSpace - 1, uYRegSpace, uZRegSpace); + indlist[6] = pIndicesX(uXRegSpace, uYRegSpace + 1, uZRegSpace + 1); } if (edgeTable[iCubeIndex] & 128) { - indlist[7] = pIndicesY(uXRegSpace - 1, uYRegSpace - 1, uZRegSpace); + indlist[7] = pIndicesY(uXRegSpace, uYRegSpace, uZRegSpace + 1); } if (edgeTable[iCubeIndex] & 256) { - indlist[8] = pIndicesZ(uXRegSpace - 1, uYRegSpace - 1, uZRegSpace - 1); + indlist[8] = pIndicesZ(uXRegSpace, uYRegSpace, uZRegSpace); } if (edgeTable[iCubeIndex] & 512) { - indlist[9] = pIndicesZ(uXRegSpace, uYRegSpace - 1, uZRegSpace - 1); + indlist[9] = pIndicesZ(uXRegSpace + 1, uYRegSpace, uZRegSpace); } if (edgeTable[iCubeIndex] & 1024) { - indlist[10] = pIndicesZ(uXRegSpace, uYRegSpace, uZRegSpace - 1); + indlist[10] = pIndicesZ(uXRegSpace + 1, uYRegSpace + 1, uZRegSpace); } if (edgeTable[iCubeIndex] & 2048) { - indlist[11] = pIndicesZ(uXRegSpace - 1, uYRegSpace, uZRegSpace - 1); + indlist[11] = pIndicesZ(uXRegSpace, uYRegSpace + 1, uZRegSpace); } for (int i = 0; triTable[iCubeIndex][i] != -1; i += 3) From 1a1ae75766556ee9012788d732d82fdeec8d1849 Mon Sep 17 00:00:00 2001 From: David Williams Date: Sat, 16 May 2015 15:36:39 +0200 Subject: [PATCH 15/61] More refactoring. --- .../PolyVox/MarchingCubesSurfaceExtractor.inl | 55 ++++++++++++++----- 1 file changed, 42 insertions(+), 13 deletions(-) diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.inl b/include/PolyVox/MarchingCubesSurfaceExtractor.inl index 5b657736..a6a806a5 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.inl +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.inl @@ -75,21 +75,21 @@ namespace PolyVox Array3DInt32& pIndicesY, Array3DInt32& pIndicesZ) { - for (int32_t iZVolSpace = m_regSizeInVoxels.getLowerZ() + 1; iZVolSpace <= m_regSizeInVoxels.getUpperZ() - 1; iZVolSpace++) + for (int32_t iZVolSpace = m_regSizeInVoxels.getLowerZ(); iZVolSpace <= m_regSizeInVoxels.getUpperZ(); iZVolSpace++) { const uint32_t uZRegSpace = iZVolSpace - m_regSizeInVoxels.getLowerZ(); - for (int32_t iYVolSpace = m_regSizeInVoxels.getLowerY() + 1; iYVolSpace <= m_regSizeInVoxels.getUpperY() - 1; iYVolSpace++) + for (int32_t iYVolSpace = m_regSizeInVoxels.getLowerY(); iYVolSpace <= m_regSizeInVoxels.getUpperY(); iYVolSpace++) { const uint32_t uYRegSpace = iYVolSpace - m_regSizeInVoxels.getLowerY(); - for (int32_t iXVolSpace = m_regSizeInVoxels.getLowerX() + 1; iXVolSpace <= m_regSizeInVoxels.getUpperX() - 1; iXVolSpace++) + for (int32_t iXVolSpace = m_regSizeInVoxels.getLowerX(); iXVolSpace <= m_regSizeInVoxels.getUpperX(); iXVolSpace++) { const uint32_t uXRegSpace = iXVolSpace - m_regSizeInVoxels.getLowerX(); m_sampVolume.setPosition(iXVolSpace, iYVolSpace, iZVolSpace); - /*typename VolumeType::VoxelType v000 = m_regSizeInVoxels.containsPoint(iXVolSpace, iYVolSpace, iZVolSpace, 1) ? m_sampVolume.peekVoxel1nx1ny1nz() : VolumeType::VoxelType(); + typename VolumeType::VoxelType v000 = m_regSizeInVoxels.containsPoint(iXVolSpace, iYVolSpace, iZVolSpace, 1) ? m_sampVolume.peekVoxel1nx1ny1nz() : VolumeType::VoxelType(); typename VolumeType::VoxelType v100 = m_regSizeInVoxels.containsPoint(iXVolSpace, iYVolSpace, iZVolSpace, 1) ? m_sampVolume.peekVoxel0px1ny1nz() : VolumeType::VoxelType(); typename VolumeType::VoxelType v010 = m_regSizeInVoxels.containsPoint(iXVolSpace, iYVolSpace, iZVolSpace, 1) ? m_sampVolume.peekVoxel1nx0py1nz() : VolumeType::VoxelType(); typename VolumeType::VoxelType v110 = m_regSizeInVoxels.containsPoint(iXVolSpace, iYVolSpace, iZVolSpace, 1) ? m_sampVolume.peekVoxel0px0py1nz() : VolumeType::VoxelType(); @@ -97,9 +97,9 @@ namespace PolyVox typename VolumeType::VoxelType v001 = m_regSizeInVoxels.containsPoint(iXVolSpace, iYVolSpace, iZVolSpace, 1) ? m_sampVolume.peekVoxel1nx1ny0pz() : VolumeType::VoxelType(); typename VolumeType::VoxelType v101 = m_regSizeInVoxels.containsPoint(iXVolSpace, iYVolSpace, iZVolSpace, 1) ? m_sampVolume.peekVoxel0px1ny0pz() : VolumeType::VoxelType(); typename VolumeType::VoxelType v011 = m_regSizeInVoxels.containsPoint(iXVolSpace, iYVolSpace, iZVolSpace, 1) ? m_sampVolume.peekVoxel1nx0py0pz() : VolumeType::VoxelType(); - typename VolumeType::VoxelType v111 = m_regSizeInVoxels.containsPoint(iXVolSpace, iYVolSpace, iZVolSpace, 1) ? m_sampVolume.peekVoxel0px0py0pz() : VolumeType::VoxelType();*/ + typename VolumeType::VoxelType v111 = m_regSizeInVoxels.containsPoint(iXVolSpace, iYVolSpace, iZVolSpace, 1) ? m_sampVolume.peekVoxel0px0py0pz() : VolumeType::VoxelType(); - typename VolumeType::VoxelType v000 = m_sampVolume.peekVoxel0px0py0pz(); + /*typename VolumeType::VoxelType v000 = m_sampVolume.peekVoxel0px0py0pz(); typename VolumeType::VoxelType v100 = m_sampVolume.peekVoxel1px0py0pz(); typename VolumeType::VoxelType v010 = m_sampVolume.peekVoxel0px1py0pz(); typename VolumeType::VoxelType v110 = m_sampVolume.peekVoxel1px1py0pz(); @@ -107,7 +107,7 @@ namespace PolyVox typename VolumeType::VoxelType v001 = m_sampVolume.peekVoxel0px0py1pz(); typename VolumeType::VoxelType v101 = m_sampVolume.peekVoxel1px0py1pz(); typename VolumeType::VoxelType v011 = m_sampVolume.peekVoxel0px1py1pz(); - typename VolumeType::VoxelType v111 = m_sampVolume.peekVoxel1px1py1pz(); + typename VolumeType::VoxelType v111 = m_sampVolume.peekVoxel1px1py1pz();*/ uint8_t iCubeIndex = 0; if (m_controller.convertToDensity(v000) < m_tThreshold) iCubeIndex |= 1; @@ -121,12 +121,41 @@ namespace PolyVox //Save the bitmask pBitmask(uXRegSpace, uYRegSpace, uZRegSpace) = iCubeIndex; + } + } + } + + for (int32_t iZVolSpace = m_regSizeInVoxels.getLowerZ() + 1; iZVolSpace <= m_regSizeInVoxels.getUpperZ(); iZVolSpace++) + { + const uint32_t uZRegSpace = iZVolSpace - m_regSizeInVoxels.getLowerZ(); + + for (int32_t iYVolSpace = m_regSizeInVoxels.getLowerY() + 1; iYVolSpace <= m_regSizeInVoxels.getUpperY(); iYVolSpace++) + { + const uint32_t uYRegSpace = iYVolSpace - m_regSizeInVoxels.getLowerY(); + + for (int32_t iXVolSpace = m_regSizeInVoxels.getLowerX() + 1; iXVolSpace <= m_regSizeInVoxels.getUpperX(); iXVolSpace++) + { + const uint32_t uXRegSpace = iXVolSpace - m_regSizeInVoxels.getLowerX(); + + m_sampVolume.setPosition(iXVolSpace, iYVolSpace, iZVolSpace); + + uint8_t iCubeIndex = pBitmask(uXRegSpace, uYRegSpace, uZRegSpace); /* Cube is entirely in/out of the surface */ if (edgeTable[iCubeIndex] == 0) { continue; } + + typename VolumeType::VoxelType v000 = m_sampVolume.peekVoxel1nx1ny1nz(); + typename VolumeType::VoxelType v100 = m_sampVolume.peekVoxel0px1ny1nz(); + typename VolumeType::VoxelType v010 = m_sampVolume.peekVoxel1nx0py1nz(); + typename VolumeType::VoxelType v001 = m_sampVolume.peekVoxel1nx1ny0pz(); + + /*typename VolumeType::VoxelType v000 = m_sampVolume.peekVoxel0px0py0pz(); + typename VolumeType::VoxelType v100 = m_sampVolume.peekVoxel1px0py0pz(); + typename VolumeType::VoxelType v010 = m_sampVolume.peekVoxel0px1py0pz(); + typename VolumeType::VoxelType v001 = m_sampVolume.peekVoxel0px0py1pz();*/ const Vector3DFloat n000 = computeCentralDifferenceGradient(m_sampVolume); @@ -139,7 +168,7 @@ namespace PolyVox const float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v000)) / static_cast(m_controller.convertToDensity(v100) - m_controller.convertToDensity(v000)); - const Vector3DFloat v3dPosition(static_cast(uXRegSpace ) + fInterp, static_cast(uYRegSpace), static_cast(uZRegSpace)); + const Vector3DFloat v3dPosition(static_cast(uXRegSpace - 1) + fInterp, static_cast(uYRegSpace - 1), static_cast(uZRegSpace - 1)); const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); Vector3DFloat v3dNormal = (n100*fInterp) + (n000*(1 - fInterp)); @@ -172,7 +201,7 @@ namespace PolyVox const float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v000)) / static_cast(m_controller.convertToDensity(v010) - m_controller.convertToDensity(v000)); - const Vector3DFloat v3dPosition(static_cast(uXRegSpace), static_cast(uYRegSpace ) + fInterp, static_cast(uZRegSpace)); + const Vector3DFloat v3dPosition(static_cast(uXRegSpace - 1), static_cast(uYRegSpace - 1) + fInterp, static_cast(uZRegSpace - 1)); const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); Vector3DFloat v3dNormal = (n010*fInterp) + (n000*(1 - fInterp)); @@ -205,7 +234,7 @@ namespace PolyVox const float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v000)) / static_cast(m_controller.convertToDensity(v001) - m_controller.convertToDensity(v000)); - const Vector3DFloat v3dPosition(static_cast(uXRegSpace), static_cast(uYRegSpace), static_cast(uZRegSpace) + fInterp); + const Vector3DFloat v3dPosition(static_cast(uXRegSpace - 1), static_cast(uYRegSpace - 1), static_cast(uZRegSpace - 1) + fInterp); const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); Vector3DFloat v3dNormal = (n001*fInterp) + (n000*(1 - fInterp)); @@ -233,11 +262,11 @@ namespace PolyVox } } - for (int32_t iZVolSpace = m_regSizeInVoxels.getLowerZ() + 2; iZVolSpace <= m_regSizeInVoxels.getUpperZ() - 2; iZVolSpace++) + for (int32_t iZVolSpace = m_regSizeInVoxels.getLowerZ() + 1; iZVolSpace <= m_regSizeInVoxels.getUpperZ(); iZVolSpace++) { - for (int32_t iYVolSpace = m_regSizeInVoxels.getLowerY() + 2; iYVolSpace <= m_regSizeInVoxels.getUpperY() - 2; iYVolSpace++) + for (int32_t iYVolSpace = m_regSizeInVoxels.getLowerY() + 1; iYVolSpace <= m_regSizeInVoxels.getUpperY(); iYVolSpace++) { - for (int32_t iXVolSpace = m_regSizeInVoxels.getLowerX() + 2; iXVolSpace <= m_regSizeInVoxels.getUpperX() - 2; iXVolSpace++) + for (int32_t iXVolSpace = m_regSizeInVoxels.getLowerX() + 1; iXVolSpace <= m_regSizeInVoxels.getUpperX(); iXVolSpace++) { int32_t indlist[12]; From a39b7f6a9f055d6493d3631b5d910454414113ea Mon Sep 17 00:00:00 2001 From: David Williams Date: Sat, 16 May 2015 20:48:15 +0200 Subject: [PATCH 16/61] More refactoring. --- .../PolyVox/MarchingCubesSurfaceExtractor.inl | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.inl b/include/PolyVox/MarchingCubesSurfaceExtractor.inl index a6a806a5..b7f8a362 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.inl +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.inl @@ -89,15 +89,15 @@ namespace PolyVox m_sampVolume.setPosition(iXVolSpace, iYVolSpace, iZVolSpace); - typename VolumeType::VoxelType v000 = m_regSizeInVoxels.containsPoint(iXVolSpace, iYVolSpace, iZVolSpace, 1) ? m_sampVolume.peekVoxel1nx1ny1nz() : VolumeType::VoxelType(); - typename VolumeType::VoxelType v100 = m_regSizeInVoxels.containsPoint(iXVolSpace, iYVolSpace, iZVolSpace, 1) ? m_sampVolume.peekVoxel0px1ny1nz() : VolumeType::VoxelType(); - typename VolumeType::VoxelType v010 = m_regSizeInVoxels.containsPoint(iXVolSpace, iYVolSpace, iZVolSpace, 1) ? m_sampVolume.peekVoxel1nx0py1nz() : VolumeType::VoxelType(); - typename VolumeType::VoxelType v110 = m_regSizeInVoxels.containsPoint(iXVolSpace, iYVolSpace, iZVolSpace, 1) ? m_sampVolume.peekVoxel0px0py1nz() : VolumeType::VoxelType(); + typename VolumeType::VoxelType v000 = iXVolSpace > m_regSizeInVoxels.getLowerX() && iYVolSpace > m_regSizeInVoxels.getLowerY() && iZVolSpace > m_regSizeInVoxels.getLowerZ() ? m_sampVolume.peekVoxel1nx1ny1nz() : VolumeType::VoxelType(); + typename VolumeType::VoxelType v100 = iYVolSpace > m_regSizeInVoxels.getLowerY() && iZVolSpace > m_regSizeInVoxels.getLowerZ() ? m_sampVolume.peekVoxel0px1ny1nz() : VolumeType::VoxelType(); + typename VolumeType::VoxelType v010 = iXVolSpace > m_regSizeInVoxels.getLowerX() && iZVolSpace > m_regSizeInVoxels.getLowerZ() ? m_sampVolume.peekVoxel1nx0py1nz() : VolumeType::VoxelType(); + typename VolumeType::VoxelType v110 = iZVolSpace > m_regSizeInVoxels.getLowerZ() ? m_sampVolume.peekVoxel0px0py1nz() : VolumeType::VoxelType(); - typename VolumeType::VoxelType v001 = m_regSizeInVoxels.containsPoint(iXVolSpace, iYVolSpace, iZVolSpace, 1) ? m_sampVolume.peekVoxel1nx1ny0pz() : VolumeType::VoxelType(); - typename VolumeType::VoxelType v101 = m_regSizeInVoxels.containsPoint(iXVolSpace, iYVolSpace, iZVolSpace, 1) ? m_sampVolume.peekVoxel0px1ny0pz() : VolumeType::VoxelType(); - typename VolumeType::VoxelType v011 = m_regSizeInVoxels.containsPoint(iXVolSpace, iYVolSpace, iZVolSpace, 1) ? m_sampVolume.peekVoxel1nx0py0pz() : VolumeType::VoxelType(); - typename VolumeType::VoxelType v111 = m_regSizeInVoxels.containsPoint(iXVolSpace, iYVolSpace, iZVolSpace, 1) ? m_sampVolume.peekVoxel0px0py0pz() : VolumeType::VoxelType(); + typename VolumeType::VoxelType v001 = iXVolSpace > m_regSizeInVoxels.getLowerX() && iYVolSpace > m_regSizeInVoxels.getLowerY() ? m_sampVolume.peekVoxel1nx1ny0pz() : VolumeType::VoxelType(); + typename VolumeType::VoxelType v101 = iYVolSpace > m_regSizeInVoxels.getLowerY() ? m_sampVolume.peekVoxel0px1ny0pz() : VolumeType::VoxelType(); + typename VolumeType::VoxelType v011 = iXVolSpace > m_regSizeInVoxels.getLowerX() ? m_sampVolume.peekVoxel1nx0py0pz() : VolumeType::VoxelType(); + typename VolumeType::VoxelType v111 = m_sampVolume.peekVoxel0px0py0pz(); /*typename VolumeType::VoxelType v000 = m_sampVolume.peekVoxel0px0py0pz(); typename VolumeType::VoxelType v100 = m_sampVolume.peekVoxel1px0py0pz(); @@ -125,15 +125,15 @@ namespace PolyVox } } - for (int32_t iZVolSpace = m_regSizeInVoxels.getLowerZ() + 1; iZVolSpace <= m_regSizeInVoxels.getUpperZ(); iZVolSpace++) + for (int32_t iZVolSpace = m_regSizeInVoxels.getLowerZ(); iZVolSpace <= m_regSizeInVoxels.getUpperZ(); iZVolSpace++) { const uint32_t uZRegSpace = iZVolSpace - m_regSizeInVoxels.getLowerZ(); - for (int32_t iYVolSpace = m_regSizeInVoxels.getLowerY() + 1; iYVolSpace <= m_regSizeInVoxels.getUpperY(); iYVolSpace++) + for (int32_t iYVolSpace = m_regSizeInVoxels.getLowerY(); iYVolSpace <= m_regSizeInVoxels.getUpperY(); iYVolSpace++) { const uint32_t uYRegSpace = iYVolSpace - m_regSizeInVoxels.getLowerY(); - for (int32_t iXVolSpace = m_regSizeInVoxels.getLowerX() + 1; iXVolSpace <= m_regSizeInVoxels.getUpperX(); iXVolSpace++) + for (int32_t iXVolSpace = m_regSizeInVoxels.getLowerX(); iXVolSpace <= m_regSizeInVoxels.getUpperX(); iXVolSpace++) { const uint32_t uXRegSpace = iXVolSpace - m_regSizeInVoxels.getLowerX(); From ccb76bc6d71d5683161326440657d355587d4309 Mon Sep 17 00:00:00 2001 From: David Williams Date: Sun, 17 May 2015 09:52:13 +0200 Subject: [PATCH 17/61] More work refactoring code. Examples appear to work now but tests still fail. --- .../PolyVox/MarchingCubesSurfaceExtractor.inl | 75 ++++++++++--------- 1 file changed, 40 insertions(+), 35 deletions(-) diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.inl b/include/PolyVox/MarchingCubesSurfaceExtractor.inl index b7f8a362..a071bd96 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.inl +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.inl @@ -147,28 +147,33 @@ namespace PolyVox continue; } - typename VolumeType::VoxelType v000 = m_sampVolume.peekVoxel1nx1ny1nz(); + /*typename VolumeType::VoxelType v000 = m_sampVolume.peekVoxel1nx1ny1nz(); typename VolumeType::VoxelType v100 = m_sampVolume.peekVoxel0px1ny1nz(); typename VolumeType::VoxelType v010 = m_sampVolume.peekVoxel1nx0py1nz(); - typename VolumeType::VoxelType v001 = m_sampVolume.peekVoxel1nx1ny0pz(); + typename VolumeType::VoxelType v001 = m_sampVolume.peekVoxel1nx1ny0pz();*/ /*typename VolumeType::VoxelType v000 = m_sampVolume.peekVoxel0px0py0pz(); typename VolumeType::VoxelType v100 = m_sampVolume.peekVoxel1px0py0pz(); typename VolumeType::VoxelType v010 = m_sampVolume.peekVoxel0px1py0pz(); typename VolumeType::VoxelType v001 = m_sampVolume.peekVoxel0px0py1pz();*/ + + typename VolumeType::VoxelType v110 = m_sampVolume.peekVoxel0px0py1nz(); + typename VolumeType::VoxelType v101 = m_sampVolume.peekVoxel0px1ny0pz(); + typename VolumeType::VoxelType v011 = m_sampVolume.peekVoxel1nx0py0pz(); + typename VolumeType::VoxelType v111 = m_sampVolume.peekVoxel0px0py0pz(); const Vector3DFloat n000 = computeCentralDifferenceGradient(m_sampVolume); /* Find the vertices where the surface intersects the cube */ - if (edgeTable[iCubeIndex] & 1) + if (edgeTable[iCubeIndex] & 64) { - m_sampVolume.movePositiveX(); - POLYVOX_ASSERT(v000 != v100, "Attempting to insert vertex between two voxels with the same value"); + m_sampVolume.moveNegativeX(); + POLYVOX_ASSERT(v011 != v111, "Attempting to insert vertex between two voxels with the same value"); const Vector3DFloat n100 = computeCentralDifferenceGradient(m_sampVolume); - const float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v000)) / static_cast(m_controller.convertToDensity(v100) - m_controller.convertToDensity(v000)); + const float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v011)) / static_cast(m_controller.convertToDensity(v111) - m_controller.convertToDensity(v011)); - const Vector3DFloat v3dPosition(static_cast(uXRegSpace - 1) + fInterp, static_cast(uYRegSpace - 1), static_cast(uZRegSpace - 1)); + const Vector3DFloat v3dPosition(static_cast(uXRegSpace - 1) + fInterp, static_cast(uYRegSpace), static_cast(uZRegSpace)); const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); Vector3DFloat v3dNormal = (n100*fInterp) + (n000*(1 - fInterp)); @@ -181,7 +186,7 @@ namespace PolyVox } // Allow the controller to decide how the material should be derived from the voxels. - const typename VolumeType::VoxelType uMaterial = m_controller.blendMaterials(v000, v100, fInterp); + const typename VolumeType::VoxelType uMaterial = m_controller.blendMaterials(v011, v111, fInterp); MarchingCubesVertex surfaceVertex; surfaceVertex.encodedPosition = v3dScaledPosition; @@ -191,17 +196,17 @@ namespace PolyVox const uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex); pIndicesX(uXRegSpace, uYRegSpace, uZRegSpace) = uLastVertexIndex; - m_sampVolume.moveNegativeX(); + m_sampVolume.movePositiveX(); } - if (edgeTable[iCubeIndex] & 8) + if (edgeTable[iCubeIndex] & 32) { - m_sampVolume.movePositiveY(); - POLYVOX_ASSERT(v000 != v010, "Attempting to insert vertex between two voxels with the same value"); + m_sampVolume.moveNegativeY(); + POLYVOX_ASSERT(v101 != v111, "Attempting to insert vertex between two voxels with the same value"); const Vector3DFloat n010 = computeCentralDifferenceGradient(m_sampVolume); - const float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v000)) / static_cast(m_controller.convertToDensity(v010) - m_controller.convertToDensity(v000)); + const float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v101)) / static_cast(m_controller.convertToDensity(v111) - m_controller.convertToDensity(v101)); - const Vector3DFloat v3dPosition(static_cast(uXRegSpace - 1), static_cast(uYRegSpace - 1) + fInterp, static_cast(uZRegSpace - 1)); + const Vector3DFloat v3dPosition(static_cast(uXRegSpace), static_cast(uYRegSpace - 1) + fInterp, static_cast(uZRegSpace)); const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); Vector3DFloat v3dNormal = (n010*fInterp) + (n000*(1 - fInterp)); @@ -214,7 +219,7 @@ namespace PolyVox } // Allow the controller to decide how the material should be derived from the voxels. - const typename VolumeType::VoxelType uMaterial = m_controller.blendMaterials(v000, v010, fInterp); + const typename VolumeType::VoxelType uMaterial = m_controller.blendMaterials(v101, v111, fInterp); MarchingCubesVertex surfaceVertex; surfaceVertex.encodedPosition = v3dScaledPosition; @@ -224,17 +229,17 @@ namespace PolyVox uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex); pIndicesY(uXRegSpace, uYRegSpace, uZRegSpace) = uLastVertexIndex; - m_sampVolume.moveNegativeY(); + m_sampVolume.movePositiveY(); } - if (edgeTable[iCubeIndex] & 256) + if (edgeTable[iCubeIndex] & 1024) { - m_sampVolume.movePositiveZ(); - POLYVOX_ASSERT(v000 != v001, "Attempting to insert vertex between two voxels with the same value"); + m_sampVolume.moveNegativeZ(); + POLYVOX_ASSERT(v110 != v111, "Attempting to insert vertex between two voxels with the same value"); const Vector3DFloat n001 = computeCentralDifferenceGradient(m_sampVolume); - const float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v000)) / static_cast(m_controller.convertToDensity(v001) - m_controller.convertToDensity(v000)); + const float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v110)) / static_cast(m_controller.convertToDensity(v111) - m_controller.convertToDensity(v110)); - const Vector3DFloat v3dPosition(static_cast(uXRegSpace - 1), static_cast(uYRegSpace - 1), static_cast(uZRegSpace - 1) + fInterp); + const Vector3DFloat v3dPosition(static_cast(uXRegSpace), static_cast(uYRegSpace), static_cast(uZRegSpace - 1) + fInterp); const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); Vector3DFloat v3dNormal = (n001*fInterp) + (n000*(1 - fInterp)); @@ -246,7 +251,7 @@ namespace PolyVox } // Allow the controller to decide how the material should be derived from the voxels. - const typename VolumeType::VoxelType uMaterial = m_controller.blendMaterials(v000, v001, fInterp); + const typename VolumeType::VoxelType uMaterial = m_controller.blendMaterials(v110, v111, fInterp); MarchingCubesVertex surfaceVertex; surfaceVertex.encodedPosition = v3dScaledPosition; @@ -256,7 +261,7 @@ namespace PolyVox const uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex); pIndicesZ(uXRegSpace, uYRegSpace, uZRegSpace) = uLastVertexIndex; - m_sampVolume.moveNegativeZ(); + m_sampVolume.movePositiveZ(); } } } @@ -289,51 +294,51 @@ namespace PolyVox /* Find the vertices where the surface intersects the cube */ if (edgeTable[iCubeIndex] & 1) { - indlist[0] = pIndicesX(uXRegSpace, uYRegSpace, uZRegSpace); + indlist[0] = pIndicesX(uXRegSpace, uYRegSpace - 1, uZRegSpace - 1); } if (edgeTable[iCubeIndex] & 2) { - indlist[1] = pIndicesY(uXRegSpace + 1, uYRegSpace, uZRegSpace); + indlist[1] = pIndicesY(uXRegSpace, uYRegSpace, uZRegSpace - 1); } if (edgeTable[iCubeIndex] & 4) { - indlist[2] = pIndicesX(uXRegSpace, uYRegSpace + 1, uZRegSpace); + indlist[2] = pIndicesX(uXRegSpace, uYRegSpace, uZRegSpace - 1); } if (edgeTable[iCubeIndex] & 8) { - indlist[3] = pIndicesY(uXRegSpace, uYRegSpace, uZRegSpace); + indlist[3] = pIndicesY(uXRegSpace - 1, uYRegSpace, uZRegSpace - 1); } if (edgeTable[iCubeIndex] & 16) { - indlist[4] = pIndicesX(uXRegSpace, uYRegSpace, uZRegSpace + 1); + indlist[4] = pIndicesX(uXRegSpace, uYRegSpace - 1, uZRegSpace); } if (edgeTable[iCubeIndex] & 32) { - indlist[5] = pIndicesY(uXRegSpace + 1, uYRegSpace, uZRegSpace + 1); + indlist[5] = pIndicesY(uXRegSpace, uYRegSpace, uZRegSpace); } if (edgeTable[iCubeIndex] & 64) { - indlist[6] = pIndicesX(uXRegSpace, uYRegSpace + 1, uZRegSpace + 1); + indlist[6] = pIndicesX(uXRegSpace, uYRegSpace, uZRegSpace); } if (edgeTable[iCubeIndex] & 128) { - indlist[7] = pIndicesY(uXRegSpace, uYRegSpace, uZRegSpace + 1); + indlist[7] = pIndicesY(uXRegSpace - 1, uYRegSpace, uZRegSpace); } if (edgeTable[iCubeIndex] & 256) { - indlist[8] = pIndicesZ(uXRegSpace, uYRegSpace, uZRegSpace); + indlist[8] = pIndicesZ(uXRegSpace - 1, uYRegSpace - 1, uZRegSpace); } if (edgeTable[iCubeIndex] & 512) { - indlist[9] = pIndicesZ(uXRegSpace + 1, uYRegSpace, uZRegSpace); + indlist[9] = pIndicesZ(uXRegSpace, uYRegSpace - 1, uZRegSpace); } if (edgeTable[iCubeIndex] & 1024) { - indlist[10] = pIndicesZ(uXRegSpace + 1, uYRegSpace + 1, uZRegSpace); + indlist[10] = pIndicesZ(uXRegSpace, uYRegSpace, uZRegSpace); } if (edgeTable[iCubeIndex] & 2048) { - indlist[11] = pIndicesZ(uXRegSpace, uYRegSpace + 1, uZRegSpace); + indlist[11] = pIndicesZ(uXRegSpace - 1, uYRegSpace, uZRegSpace); } for (int i = 0; triTable[iCubeIndex][i] != -1; i += 3) From 9a6858253070d5b632f1d6a45bfd56b68c191872 Mon Sep 17 00:00:00 2001 From: David Williams Date: Sun, 17 May 2015 11:47:52 +0200 Subject: [PATCH 18/61] Added bounds checks --- include/PolyVox/MarchingCubesSurfaceExtractor.inl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.inl b/include/PolyVox/MarchingCubesSurfaceExtractor.inl index a071bd96..3d21e5f8 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.inl +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.inl @@ -165,7 +165,7 @@ namespace PolyVox const Vector3DFloat n000 = computeCentralDifferenceGradient(m_sampVolume); /* Find the vertices where the surface intersects the cube */ - if (edgeTable[iCubeIndex] & 64) + if ((edgeTable[iCubeIndex] & 64) && (uXRegSpace > 0)) { m_sampVolume.moveNegativeX(); POLYVOX_ASSERT(v011 != v111, "Attempting to insert vertex between two voxels with the same value"); @@ -198,7 +198,7 @@ namespace PolyVox m_sampVolume.movePositiveX(); } - if (edgeTable[iCubeIndex] & 32) + if ((edgeTable[iCubeIndex] & 32) && (uYRegSpace > 0)) { m_sampVolume.moveNegativeY(); POLYVOX_ASSERT(v101 != v111, "Attempting to insert vertex between two voxels with the same value"); @@ -231,7 +231,7 @@ namespace PolyVox m_sampVolume.movePositiveY(); } - if (edgeTable[iCubeIndex] & 1024) + if ((edgeTable[iCubeIndex] & 1024) && (uZRegSpace > 0)) { m_sampVolume.moveNegativeZ(); POLYVOX_ASSERT(v110 != v111, "Attempting to insert vertex between two voxels with the same value"); From f178dc084bdc6bc94bde22e7ee1ccda20ee37365 Mon Sep 17 00:00:00 2001 From: David Williams Date: Tue, 19 May 2015 23:14:31 +0200 Subject: [PATCH 19/61] Updated unit tests. It seems we had a bug which was causing an excessive number of vertices to be generated. Not sure exactly what was wrong by the refactoring has fixed this. However, it still needs testing in Cubiquity to verify. --- tests/TestSurfaceExtractor.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/TestSurfaceExtractor.cpp b/tests/TestSurfaceExtractor.cpp index 3850b9cb..dd800d94 100644 --- a/tests/TestSurfaceExtractor.cpp +++ b/tests/TestSurfaceExtractor.cpp @@ -168,18 +168,18 @@ void TestSurfaceExtractor::testBehaviour() // This basic test just uses the default controller and automatically generates a mesh of the appropriate type. auto uintVol = createAndFillVolume< RawVolume >(); auto uintMesh = extractMarchingCubesMesh(uintVol, uintVol->getEnclosingRegion()); - QCOMPARE(uintMesh.getNoOfVertices(), uint32_t(12096)); // Verifies size of mesh and that we have 32-bit indices + QCOMPARE(uintMesh.getNoOfVertices(), uint32_t(6048)); // Verifies size of mesh and that we have 32-bit indices QCOMPARE(uintMesh.getNoOfIndices(), uint32_t(35157)); // Verifies size of mesh - QCOMPARE(uintMesh.getIndex(100), uint32_t(44)); // Verifies that we have 32-bit indices + QCOMPARE(uintMesh.getIndex(100), uint32_t(24)); // Verifies that we have 32-bit indices QCOMPARE(uintMesh.getVertex(100).data, uint8_t(1)); // Not really meaningful for a primative type // This test makes use of a custom controller auto floatVol = createAndFillVolume< RawVolume >(); CustomMarchingCubesController floatCustomController; auto floatMesh = extractMarchingCubesMesh(floatVol, floatVol->getEnclosingRegion(), floatCustomController); - QCOMPARE(floatMesh.getNoOfVertices(), uint32_t(16113)); // Verifies size of mesh and that we have 32-bit indices + QCOMPARE(floatMesh.getNoOfVertices(), uint32_t(3825)); // Verifies size of mesh and that we have 32-bit indices QCOMPARE(floatMesh.getNoOfIndices(), uint32_t(22053)); // Verifies size of mesh - QCOMPARE(floatMesh.getIndex(100), uint32_t(26)); // Verifies that we have 32-bit indices + QCOMPARE(floatMesh.getIndex(100), uint32_t(119)); // Verifies that we have 32-bit indices QCOMPARE(floatMesh.getVertex(100).data, float(1.0f)); // Not really meaningful for a primative type // This test makes use of a user provided mesh. It uses the default controller, but we have to explicitly provide this because C++ won't let us @@ -187,7 +187,7 @@ void TestSurfaceExtractor::testBehaviour() auto intVol = createAndFillVolume< RawVolume >(); Mesh< MarchingCubesVertex< int8_t >, uint16_t > intMesh; extractMarchingCubesMeshCustom(intVol, intVol->getEnclosingRegion(), &intMesh); - QCOMPARE(intMesh.getNoOfVertices(), uint16_t(11718)); // Verifies size of mesh and that we have 16-bit indices + QCOMPARE(intMesh.getNoOfVertices(), uint16_t(5859)); // Verifies size of mesh and that we have 16-bit indices QCOMPARE(intMesh.getNoOfIndices(), uint32_t(34041)); // Verifies size of mesh QCOMPARE(intMesh.getIndex(100), uint16_t(29)); // Verifies that we have 16-bit indices QCOMPARE(intMesh.getVertex(100).data, int8_t(1)); // Not really meaningful for a primative type @@ -197,17 +197,17 @@ void TestSurfaceExtractor::testBehaviour() CustomMarchingCubesController doubleCustomController; Mesh< MarchingCubesVertex< double >, uint16_t > doubleMesh; extractMarchingCubesMeshCustom(doubleVol, doubleVol->getEnclosingRegion(), &doubleMesh, doubleCustomController); - QCOMPARE(doubleMesh.getNoOfVertices(), uint16_t(16113)); // Verifies size of mesh and that we have 32-bit indices + QCOMPARE(doubleMesh.getNoOfVertices(), uint16_t(3825)); // Verifies size of mesh and that we have 32-bit indices QCOMPARE(doubleMesh.getNoOfIndices(), uint32_t(22053)); // Verifies size of mesh - QCOMPARE(doubleMesh.getIndex(100), uint16_t(26)); // Verifies that we have 32-bit indices + QCOMPARE(doubleMesh.getIndex(100), uint16_t(119)); // Verifies that we have 32-bit indices QCOMPARE(doubleMesh.getVertex(100).data, double(1.0f)); // Not really meaningful for a primative type // This test ensures the extractor works on a non-primitive voxel type. auto materialVol = createAndFillVolume< RawVolume >(); auto materialMesh = extractMarchingCubesMesh(materialVol, materialVol->getEnclosingRegion()); - QCOMPARE(materialMesh.getNoOfVertices(), uint32_t(12096)); // Verifies size of mesh and that we have 32-bit indices + QCOMPARE(materialMesh.getNoOfVertices(), uint32_t(6048)); // Verifies size of mesh and that we have 32-bit indices QCOMPARE(materialMesh.getNoOfIndices(), uint32_t(35157)); // Verifies size of mesh - QCOMPARE(materialMesh.getIndex(100), uint32_t(44)); // Verifies that we have 32-bit indices + QCOMPARE(materialMesh.getIndex(100), uint32_t(24)); // Verifies that we have 32-bit indices QCOMPARE(materialMesh.getVertex(100).data.getMaterial(), uint16_t(79)); // Verify the data attached to the vertex } @@ -224,7 +224,7 @@ void TestSurfaceExtractor::testNoiseVolumePerformance() auto noiseVol = createAndFillVolumeWithNoise< PagedVolume >(128, 128, -1.0f, 1.0f); Mesh< MarchingCubesVertex< float >, uint16_t > noiseMesh; QBENCHMARK{ extractMarchingCubesMeshCustom(noiseVol, Region(32, 32, 32, 63, 63, 63), &noiseMesh); } - QCOMPARE(noiseMesh.getNoOfVertices(), uint16_t(36755)); + QCOMPARE(noiseMesh.getNoOfVertices(), uint16_t(35672)); } QTEST_MAIN(TestSurfaceExtractor) From 797689acea4d9a7e99faf9263ecf858cb475b84f Mon Sep 17 00:00:00 2001 From: David Williams Date: Wed, 20 May 2015 23:45:22 +0200 Subject: [PATCH 20/61] Trying to re-apply some previous optimizations to get old speed back. --- .../PolyVox/MarchingCubesSurfaceExtractor.inl | 227 ++++++++++++++++-- 1 file changed, 201 insertions(+), 26 deletions(-) diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.inl b/include/PolyVox/MarchingCubesSurfaceExtractor.inl index 3d21e5f8..d078582c 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.inl +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.inl @@ -89,38 +89,213 @@ namespace PolyVox m_sampVolume.setPosition(iXVolSpace, iYVolSpace, iZVolSpace); - typename VolumeType::VoxelType v000 = iXVolSpace > m_regSizeInVoxels.getLowerX() && iYVolSpace > m_regSizeInVoxels.getLowerY() && iZVolSpace > m_regSizeInVoxels.getLowerZ() ? m_sampVolume.peekVoxel1nx1ny1nz() : VolumeType::VoxelType(); - typename VolumeType::VoxelType v100 = iYVolSpace > m_regSizeInVoxels.getLowerY() && iZVolSpace > m_regSizeInVoxels.getLowerZ() ? m_sampVolume.peekVoxel0px1ny1nz() : VolumeType::VoxelType(); - typename VolumeType::VoxelType v010 = iXVolSpace > m_regSizeInVoxels.getLowerX() && iZVolSpace > m_regSizeInVoxels.getLowerZ() ? m_sampVolume.peekVoxel1nx0py1nz() : VolumeType::VoxelType(); - typename VolumeType::VoxelType v110 = iZVolSpace > m_regSizeInVoxels.getLowerZ() ? m_sampVolume.peekVoxel0px0py1nz() : VolumeType::VoxelType(); + typename VolumeType::VoxelType v000; + typename VolumeType::VoxelType v100; + typename VolumeType::VoxelType v010; + typename VolumeType::VoxelType v110; - typename VolumeType::VoxelType v001 = iXVolSpace > m_regSizeInVoxels.getLowerX() && iYVolSpace > m_regSizeInVoxels.getLowerY() ? m_sampVolume.peekVoxel1nx1ny0pz() : VolumeType::VoxelType(); - typename VolumeType::VoxelType v101 = iYVolSpace > m_regSizeInVoxels.getLowerY() ? m_sampVolume.peekVoxel0px1ny0pz() : VolumeType::VoxelType(); - typename VolumeType::VoxelType v011 = iXVolSpace > m_regSizeInVoxels.getLowerX() ? m_sampVolume.peekVoxel1nx0py0pz() : VolumeType::VoxelType(); - typename VolumeType::VoxelType v111 = m_sampVolume.peekVoxel0px0py0pz(); + typename VolumeType::VoxelType v001; + typename VolumeType::VoxelType v101; + typename VolumeType::VoxelType v011; + typename VolumeType::VoxelType v111; - /*typename VolumeType::VoxelType v000 = m_sampVolume.peekVoxel0px0py0pz(); - typename VolumeType::VoxelType v100 = m_sampVolume.peekVoxel1px0py0pz(); - typename VolumeType::VoxelType v010 = m_sampVolume.peekVoxel0px1py0pz(); - typename VolumeType::VoxelType v110 = m_sampVolume.peekVoxel1px1py0pz(); + v000 = iXVolSpace > m_regSizeInVoxels.getLowerX() && iYVolSpace > m_regSizeInVoxels.getLowerY() && iZVolSpace > m_regSizeInVoxels.getLowerZ() ? m_sampVolume.peekVoxel1nx1ny1nz() : VolumeType::VoxelType(); + v100 = iYVolSpace > m_regSizeInVoxels.getLowerY() && iZVolSpace > m_regSizeInVoxels.getLowerZ() ? m_sampVolume.peekVoxel0px1ny1nz() : VolumeType::VoxelType(); + v010 = iXVolSpace > m_regSizeInVoxels.getLowerX() && iZVolSpace > m_regSizeInVoxels.getLowerZ() ? m_sampVolume.peekVoxel1nx0py1nz() : VolumeType::VoxelType(); + v110 = iZVolSpace > m_regSizeInVoxels.getLowerZ() ? m_sampVolume.peekVoxel0px0py1nz() : VolumeType::VoxelType(); - typename VolumeType::VoxelType v001 = m_sampVolume.peekVoxel0px0py1pz(); - typename VolumeType::VoxelType v101 = m_sampVolume.peekVoxel1px0py1pz(); - typename VolumeType::VoxelType v011 = m_sampVolume.peekVoxel0px1py1pz(); - typename VolumeType::VoxelType v111 = m_sampVolume.peekVoxel1px1py1pz();*/ + v001 = iXVolSpace > m_regSizeInVoxels.getLowerX() && iYVolSpace > m_regSizeInVoxels.getLowerY() ? m_sampVolume.peekVoxel1nx1ny0pz() : VolumeType::VoxelType(); + v101 = iYVolSpace > m_regSizeInVoxels.getLowerY() ? m_sampVolume.peekVoxel0px1ny0pz() : VolumeType::VoxelType(); + v011 = iXVolSpace > m_regSizeInVoxels.getLowerX() ? m_sampVolume.peekVoxel1nx0py0pz() : VolumeType::VoxelType(); + v111 = m_sampVolume.peekVoxel0px0py0pz(); uint8_t iCubeIndex = 0; - if (m_controller.convertToDensity(v000) < m_tThreshold) iCubeIndex |= 1; - if (m_controller.convertToDensity(v100) < m_tThreshold) iCubeIndex |= 2; - if (m_controller.convertToDensity(v010) < m_tThreshold) iCubeIndex |= 4; - if (m_controller.convertToDensity(v110) < m_tThreshold) iCubeIndex |= 8; - if (m_controller.convertToDensity(v001) < m_tThreshold) iCubeIndex |= 16; - if (m_controller.convertToDensity(v101) < m_tThreshold) iCubeIndex |= 32; - if (m_controller.convertToDensity(v011) < m_tThreshold) iCubeIndex |= 64; - if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128; - //Save the bitmask - pBitmask(uXRegSpace, uYRegSpace, uZRegSpace) = iCubeIndex; + bool isPrevXAvail = iXVolSpace > m_regSizeInVoxels.getLowerX(); + bool isPrevYAvail = iYVolSpace > m_regSizeInVoxels.getLowerY(); + bool isPrevZAvail = iZVolSpace > m_regSizeInVoxels.getLowerZ(); + + if (isPrevZAvail) + { + if (isPrevYAvail) + { + if (isPrevXAvail) + { + v111 = m_sampVolume.peekVoxel0px0py0pz(); + + //z + uint8_t iPreviousCubeIndexZ = pBitmask(uXRegSpace, uYRegSpace, uZRegSpace - 1); + iPreviousCubeIndexZ >>= 4; + + //y + uint8_t iPreviousCubeIndexY = pBitmask(uXRegSpace, uYRegSpace - 1, uZRegSpace); + iPreviousCubeIndexY &= 192; //192 = 128 + 64 + iPreviousCubeIndexY >>= 2; + + //x + uint8_t iPreviousCubeIndexX = pBitmask(uXRegSpace - 1, uYRegSpace, uZRegSpace); + iPreviousCubeIndexX &= 128; + iPreviousCubeIndexX >>= 1; + + iCubeIndex = iPreviousCubeIndexX | iPreviousCubeIndexY | iPreviousCubeIndexZ; + + if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128; + } + else //previous X not available + { + v011 = iXVolSpace > m_regSizeInVoxels.getLowerX() ? m_sampVolume.peekVoxel1nx0py0pz() : VolumeType::VoxelType(); + v111 = m_sampVolume.peekVoxel0px0py0pz(); + + //z + uint8_t iPreviousCubeIndexZ = pBitmask(uXRegSpace, uYRegSpace, uZRegSpace - 1); + iPreviousCubeIndexZ >>= 4; + + //y + uint8_t iPreviousCubeIndexY = pBitmask(uXRegSpace, uYRegSpace - 1, uZRegSpace); + iPreviousCubeIndexY &= 192; //192 = 128 + 64 + iPreviousCubeIndexY >>= 2; + + iCubeIndex = iPreviousCubeIndexY | iPreviousCubeIndexZ; + + if (m_controller.convertToDensity(v011) < m_tThreshold) iCubeIndex |= 64; + if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128; + } + } + else //previous Y not available + { + if (isPrevXAvail) + { + v101 = iYVolSpace > m_regSizeInVoxels.getLowerY() ? m_sampVolume.peekVoxel0px1ny0pz() : VolumeType::VoxelType(); + v111 = m_sampVolume.peekVoxel0px0py0pz(); + + //z + uint8_t iPreviousCubeIndexZ = pBitmask(uXRegSpace, uYRegSpace, uZRegSpace - 1); + iPreviousCubeIndexZ >>= 4; + + //x + uint8_t iPreviousCubeIndexX = pBitmask(uXRegSpace - 1, uYRegSpace, uZRegSpace); + iPreviousCubeIndexX &= 160; //160 = 128+32 + iPreviousCubeIndexX >>= 1; + + iCubeIndex = iPreviousCubeIndexX | iPreviousCubeIndexZ; + + if (m_controller.convertToDensity(v101) < m_tThreshold) iCubeIndex |= 32; + if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128; + } + else //previous X not available + { + v001 = iXVolSpace > m_regSizeInVoxels.getLowerX() && iYVolSpace > m_regSizeInVoxels.getLowerY() ? m_sampVolume.peekVoxel1nx1ny0pz() : VolumeType::VoxelType(); + v101 = iYVolSpace > m_regSizeInVoxels.getLowerY() ? m_sampVolume.peekVoxel0px1ny0pz() : VolumeType::VoxelType(); + v011 = iXVolSpace > m_regSizeInVoxels.getLowerX() ? m_sampVolume.peekVoxel1nx0py0pz() : VolumeType::VoxelType(); + v111 = m_sampVolume.peekVoxel0px0py0pz(); + + //z + uint8_t iPreviousCubeIndexZ = pBitmask(uXRegSpace, uYRegSpace, uZRegSpace - 1); + iCubeIndex = iPreviousCubeIndexZ >> 4; + + if (m_controller.convertToDensity(v001) < m_tThreshold) iCubeIndex |= 16; + if (m_controller.convertToDensity(v101) < m_tThreshold) iCubeIndex |= 32; + if (m_controller.convertToDensity(v011) < m_tThreshold) iCubeIndex |= 64; + if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128; + } + } + } + else //previous Z not available + { + if (isPrevYAvail) + { + if (isPrevXAvail) + { + v110 = iZVolSpace > m_regSizeInVoxels.getLowerZ() ? m_sampVolume.peekVoxel0px0py1nz() : VolumeType::VoxelType(); + v111 = m_sampVolume.peekVoxel0px0py0pz(); + + //y + uint8_t iPreviousCubeIndexY = pBitmask(uXRegSpace, uYRegSpace - 1, uZRegSpace); + iPreviousCubeIndexY &= 204; //204 = 128+64+8+4 + iPreviousCubeIndexY >>= 2; + + //x + uint8_t iPreviousCubeIndexX = pBitmask(uXRegSpace - 1, uYRegSpace, uZRegSpace); + iPreviousCubeIndexX &= 170; //170 = 128+32+8+2 + iPreviousCubeIndexX >>= 1; + + iCubeIndex = iPreviousCubeIndexX | iPreviousCubeIndexY; + + if (m_controller.convertToDensity(v110) < m_tThreshold) iCubeIndex |= 8; + if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128; + } + else //previous X not available + { + v010 = iXVolSpace > m_regSizeInVoxels.getLowerX() && iZVolSpace > m_regSizeInVoxels.getLowerZ() ? m_sampVolume.peekVoxel1nx0py1nz() : VolumeType::VoxelType(); + v110 = iZVolSpace > m_regSizeInVoxels.getLowerZ() ? m_sampVolume.peekVoxel0px0py1nz() : VolumeType::VoxelType(); + + v011 = iXVolSpace > m_regSizeInVoxels.getLowerX() ? m_sampVolume.peekVoxel1nx0py0pz() : VolumeType::VoxelType(); + v111 = m_sampVolume.peekVoxel0px0py0pz(); + + //y + uint8_t iPreviousCubeIndexY = pBitmask(uXRegSpace, uYRegSpace - 1, uZRegSpace); + iPreviousCubeIndexY &= 204; //204 = 128+64+8+4 + iPreviousCubeIndexY >>= 2; + + iCubeIndex = iPreviousCubeIndexY; + + if (m_controller.convertToDensity(v010) < m_tThreshold) iCubeIndex |= 4; + if (m_controller.convertToDensity(v110) < m_tThreshold) iCubeIndex |= 8; + if (m_controller.convertToDensity(v011) < m_tThreshold) iCubeIndex |= 64; + if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128; + } + } + else //previous Y not available + { + if (isPrevXAvail) + { + v100 = iYVolSpace > m_regSizeInVoxels.getLowerY() && iZVolSpace > m_regSizeInVoxels.getLowerZ() ? m_sampVolume.peekVoxel0px1ny1nz() : VolumeType::VoxelType(); + v110 = iZVolSpace > m_regSizeInVoxels.getLowerZ() ? m_sampVolume.peekVoxel0px0py1nz() : VolumeType::VoxelType(); + + v101 = iYVolSpace > m_regSizeInVoxels.getLowerY() ? m_sampVolume.peekVoxel0px1ny0pz() : VolumeType::VoxelType(); + v111 = m_sampVolume.peekVoxel0px0py0pz(); + + //x + uint8_t iPreviousCubeIndexX = pBitmask(uXRegSpace - 1, uYRegSpace, uZRegSpace); + iPreviousCubeIndexX &= 170; //170 = 128+32+8+2 + iPreviousCubeIndexX >>= 1; + + iCubeIndex = iPreviousCubeIndexX; + + if (m_controller.convertToDensity(v100) < m_tThreshold) iCubeIndex |= 2; + if (m_controller.convertToDensity(v110) < m_tThreshold) iCubeIndex |= 8; + if (m_controller.convertToDensity(v101) < m_tThreshold) iCubeIndex |= 32; + if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128; + } + else //previous X not available + { + v000 = iXVolSpace > m_regSizeInVoxels.getLowerX() && iYVolSpace > m_regSizeInVoxels.getLowerY() && iZVolSpace > m_regSizeInVoxels.getLowerZ() ? m_sampVolume.peekVoxel1nx1ny1nz() : VolumeType::VoxelType(); + v100 = iYVolSpace > m_regSizeInVoxels.getLowerY() && iZVolSpace > m_regSizeInVoxels.getLowerZ() ? m_sampVolume.peekVoxel0px1ny1nz() : VolumeType::VoxelType(); + v010 = iXVolSpace > m_regSizeInVoxels.getLowerX() && iZVolSpace > m_regSizeInVoxels.getLowerZ() ? m_sampVolume.peekVoxel1nx0py1nz() : VolumeType::VoxelType(); + v110 = iZVolSpace > m_regSizeInVoxels.getLowerZ() ? m_sampVolume.peekVoxel0px0py1nz() : VolumeType::VoxelType(); + + v001 = iXVolSpace > m_regSizeInVoxels.getLowerX() && iYVolSpace > m_regSizeInVoxels.getLowerY() ? m_sampVolume.peekVoxel1nx1ny0pz() : VolumeType::VoxelType(); + v101 = iYVolSpace > m_regSizeInVoxels.getLowerY() ? m_sampVolume.peekVoxel0px1ny0pz() : VolumeType::VoxelType(); + v011 = iXVolSpace > m_regSizeInVoxels.getLowerX() ? m_sampVolume.peekVoxel1nx0py0pz() : VolumeType::VoxelType(); + v111 = m_sampVolume.peekVoxel0px0py0pz(); + + if (m_controller.convertToDensity(v000) < m_tThreshold) iCubeIndex |= 1; + if (m_controller.convertToDensity(v100) < m_tThreshold) iCubeIndex |= 2; + if (m_controller.convertToDensity(v010) < m_tThreshold) iCubeIndex |= 4; + if (m_controller.convertToDensity(v110) < m_tThreshold) iCubeIndex |= 8; + if (m_controller.convertToDensity(v001) < m_tThreshold) iCubeIndex |= 16; + if (m_controller.convertToDensity(v101) < m_tThreshold) iCubeIndex |= 32; + if (m_controller.convertToDensity(v011) < m_tThreshold) iCubeIndex |= 64; + if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128; + } + } + } + + if (iCubeIndex != 0) + { + //Save the bitmask + pBitmask(uXRegSpace, uYRegSpace, uZRegSpace) = iCubeIndex; + } } } } From 2a7eb51653bf30a95ba6e7d9c7b624feb991d89c Mon Sep 17 00:00:00 2001 From: David Williams Date: Thu, 21 May 2015 23:12:38 +0200 Subject: [PATCH 21/61] Refactoring multiple loops into one big loop. --- .../PolyVox/MarchingCubesSurfaceExtractor.inl | 62 ++----------------- 1 file changed, 4 insertions(+), 58 deletions(-) diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.inl b/include/PolyVox/MarchingCubesSurfaceExtractor.inl index d078582c..2b8ba592 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.inl +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.inl @@ -99,16 +99,6 @@ namespace PolyVox typename VolumeType::VoxelType v011; typename VolumeType::VoxelType v111; - v000 = iXVolSpace > m_regSizeInVoxels.getLowerX() && iYVolSpace > m_regSizeInVoxels.getLowerY() && iZVolSpace > m_regSizeInVoxels.getLowerZ() ? m_sampVolume.peekVoxel1nx1ny1nz() : VolumeType::VoxelType(); - v100 = iYVolSpace > m_regSizeInVoxels.getLowerY() && iZVolSpace > m_regSizeInVoxels.getLowerZ() ? m_sampVolume.peekVoxel0px1ny1nz() : VolumeType::VoxelType(); - v010 = iXVolSpace > m_regSizeInVoxels.getLowerX() && iZVolSpace > m_regSizeInVoxels.getLowerZ() ? m_sampVolume.peekVoxel1nx0py1nz() : VolumeType::VoxelType(); - v110 = iZVolSpace > m_regSizeInVoxels.getLowerZ() ? m_sampVolume.peekVoxel0px0py1nz() : VolumeType::VoxelType(); - - v001 = iXVolSpace > m_regSizeInVoxels.getLowerX() && iYVolSpace > m_regSizeInVoxels.getLowerY() ? m_sampVolume.peekVoxel1nx1ny0pz() : VolumeType::VoxelType(); - v101 = iYVolSpace > m_regSizeInVoxels.getLowerY() ? m_sampVolume.peekVoxel0px1ny0pz() : VolumeType::VoxelType(); - v011 = iXVolSpace > m_regSizeInVoxels.getLowerX() ? m_sampVolume.peekVoxel1nx0py0pz() : VolumeType::VoxelType(); - v111 = m_sampVolume.peekVoxel0px0py0pz(); - uint8_t iCubeIndex = 0; bool isPrevXAvail = iXVolSpace > m_regSizeInVoxels.getLowerX(); @@ -296,46 +286,19 @@ namespace PolyVox //Save the bitmask pBitmask(uXRegSpace, uYRegSpace, uZRegSpace) = iCubeIndex; } - } - } - } - - for (int32_t iZVolSpace = m_regSizeInVoxels.getLowerZ(); iZVolSpace <= m_regSizeInVoxels.getUpperZ(); iZVolSpace++) - { - const uint32_t uZRegSpace = iZVolSpace - m_regSizeInVoxels.getLowerZ(); - - for (int32_t iYVolSpace = m_regSizeInVoxels.getLowerY(); iYVolSpace <= m_regSizeInVoxels.getUpperY(); iYVolSpace++) - { - const uint32_t uYRegSpace = iYVolSpace - m_regSizeInVoxels.getLowerY(); - - for (int32_t iXVolSpace = m_regSizeInVoxels.getLowerX(); iXVolSpace <= m_regSizeInVoxels.getUpperX(); iXVolSpace++) - { - const uint32_t uXRegSpace = iXVolSpace - m_regSizeInVoxels.getLowerX(); m_sampVolume.setPosition(iXVolSpace, iYVolSpace, iZVolSpace); - uint8_t iCubeIndex = pBitmask(uXRegSpace, uYRegSpace, uZRegSpace); - /* Cube is entirely in/out of the surface */ if (edgeTable[iCubeIndex] == 0) { continue; } - /*typename VolumeType::VoxelType v000 = m_sampVolume.peekVoxel1nx1ny1nz(); - typename VolumeType::VoxelType v100 = m_sampVolume.peekVoxel0px1ny1nz(); - typename VolumeType::VoxelType v010 = m_sampVolume.peekVoxel1nx0py1nz(); - typename VolumeType::VoxelType v001 = m_sampVolume.peekVoxel1nx1ny0pz();*/ - - /*typename VolumeType::VoxelType v000 = m_sampVolume.peekVoxel0px0py0pz(); - typename VolumeType::VoxelType v100 = m_sampVolume.peekVoxel1px0py0pz(); - typename VolumeType::VoxelType v010 = m_sampVolume.peekVoxel0px1py0pz(); - typename VolumeType::VoxelType v001 = m_sampVolume.peekVoxel0px0py1pz();*/ - - typename VolumeType::VoxelType v110 = m_sampVolume.peekVoxel0px0py1nz(); - typename VolumeType::VoxelType v101 = m_sampVolume.peekVoxel0px1ny0pz(); - typename VolumeType::VoxelType v011 = m_sampVolume.peekVoxel1nx0py0pz(); - typename VolumeType::VoxelType v111 = m_sampVolume.peekVoxel0px0py0pz(); + // These three might not have been sampled, as v111 is the only one we sample every iteration. + v110 = m_sampVolume.peekVoxel0px0py1nz(); + v101 = m_sampVolume.peekVoxel0px1ny0pz(); + v011 = m_sampVolume.peekVoxel1nx0py0pz(); const Vector3DFloat n000 = computeCentralDifferenceGradient(m_sampVolume); @@ -438,28 +401,11 @@ namespace PolyVox m_sampVolume.movePositiveZ(); } - } - } - } - for (int32_t iZVolSpace = m_regSizeInVoxels.getLowerZ() + 1; iZVolSpace <= m_regSizeInVoxels.getUpperZ(); iZVolSpace++) - { - for (int32_t iYVolSpace = m_regSizeInVoxels.getLowerY() + 1; iYVolSpace <= m_regSizeInVoxels.getUpperY(); iYVolSpace++) - { - for (int32_t iXVolSpace = m_regSizeInVoxels.getLowerX() + 1; iXVolSpace <= m_regSizeInVoxels.getUpperX(); iXVolSpace++) - { int32_t indlist[12]; m_sampVolume.setPosition(iXVolSpace, iYVolSpace, iZVolSpace); - //Current position - const uint32_t uXRegSpace = m_sampVolume.getPosition().getX() - m_regSizeInVoxels.getLowerX(); - const uint32_t uYRegSpace = m_sampVolume.getPosition().getY() - m_regSizeInVoxels.getLowerY(); - const uint32_t uZRegSpace = m_sampVolume.getPosition().getZ() - m_regSizeInVoxels.getLowerZ(); - - //Determine the index into the edge table which tells us which vertices are inside of the surface - const uint8_t iCubeIndex = pBitmask(uXRegSpace, uYRegSpace, uZRegSpace); - /* Cube is entirely in/out of the surface */ if (edgeTable[iCubeIndex] == 0) { From 711c262004ddb1b054d182fcd51728c58447a41c Mon Sep 17 00:00:00 2001 From: David Williams Date: Thu, 21 May 2015 23:17:49 +0200 Subject: [PATCH 22/61] Skip outputting some indices. --- include/PolyVox/MarchingCubesSurfaceExtractor.inl | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.inl b/include/PolyVox/MarchingCubesSurfaceExtractor.inl index 2b8ba592..506f9185 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.inl +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.inl @@ -402,6 +402,13 @@ namespace PolyVox m_sampVolume.movePositiveZ(); } + // Now output the indices. For the first row, column or slice there aren't + // any (the region size in cells is one less than the region size in voxels) + if ((!isPrevXAvail) || (!isPrevYAvail) || (!isPrevZAvail)) + { + continue; + } + int32_t indlist[12]; m_sampVolume.setPosition(iXVolSpace, iYVolSpace, iZVolSpace); From 50a8bebfa9e3853546cf9818d0f9e91e5d36f34d Mon Sep 17 00:00:00 2001 From: David Williams Date: Thu, 21 May 2015 23:31:19 +0200 Subject: [PATCH 23/61] Removed unneeded logic. --- .../PolyVox/MarchingCubesSurfaceExtractor.inl | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.inl b/include/PolyVox/MarchingCubesSurfaceExtractor.inl index 506f9185..e11dd42d 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.inl +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.inl @@ -133,7 +133,7 @@ namespace PolyVox } else //previous X not available { - v011 = iXVolSpace > m_regSizeInVoxels.getLowerX() ? m_sampVolume.peekVoxel1nx0py0pz() : VolumeType::VoxelType(); + v011 = m_sampVolume.peekVoxel1nx0py0pz(); v111 = m_sampVolume.peekVoxel0px0py0pz(); //z @@ -155,7 +155,7 @@ namespace PolyVox { if (isPrevXAvail) { - v101 = iYVolSpace > m_regSizeInVoxels.getLowerY() ? m_sampVolume.peekVoxel0px1ny0pz() : VolumeType::VoxelType(); + v101 = m_sampVolume.peekVoxel0px1ny0pz(); v111 = m_sampVolume.peekVoxel0px0py0pz(); //z @@ -174,9 +174,9 @@ namespace PolyVox } else //previous X not available { - v001 = iXVolSpace > m_regSizeInVoxels.getLowerX() && iYVolSpace > m_regSizeInVoxels.getLowerY() ? m_sampVolume.peekVoxel1nx1ny0pz() : VolumeType::VoxelType(); - v101 = iYVolSpace > m_regSizeInVoxels.getLowerY() ? m_sampVolume.peekVoxel0px1ny0pz() : VolumeType::VoxelType(); - v011 = iXVolSpace > m_regSizeInVoxels.getLowerX() ? m_sampVolume.peekVoxel1nx0py0pz() : VolumeType::VoxelType(); + v001 = m_sampVolume.peekVoxel1nx1ny0pz(); + v101 = m_sampVolume.peekVoxel0px1ny0pz(); + v011 = m_sampVolume.peekVoxel1nx0py0pz(); v111 = m_sampVolume.peekVoxel0px0py0pz(); //z @@ -196,7 +196,7 @@ namespace PolyVox { if (isPrevXAvail) { - v110 = iZVolSpace > m_regSizeInVoxels.getLowerZ() ? m_sampVolume.peekVoxel0px0py1nz() : VolumeType::VoxelType(); + v110 = m_sampVolume.peekVoxel0px0py1nz(); v111 = m_sampVolume.peekVoxel0px0py0pz(); //y @@ -216,10 +216,10 @@ namespace PolyVox } else //previous X not available { - v010 = iXVolSpace > m_regSizeInVoxels.getLowerX() && iZVolSpace > m_regSizeInVoxels.getLowerZ() ? m_sampVolume.peekVoxel1nx0py1nz() : VolumeType::VoxelType(); - v110 = iZVolSpace > m_regSizeInVoxels.getLowerZ() ? m_sampVolume.peekVoxel0px0py1nz() : VolumeType::VoxelType(); + v010 = m_sampVolume.peekVoxel1nx0py1nz(); + v110 = m_sampVolume.peekVoxel0px0py1nz(); - v011 = iXVolSpace > m_regSizeInVoxels.getLowerX() ? m_sampVolume.peekVoxel1nx0py0pz() : VolumeType::VoxelType(); + v011 = m_sampVolume.peekVoxel1nx0py0pz(); v111 = m_sampVolume.peekVoxel0px0py0pz(); //y @@ -239,10 +239,10 @@ namespace PolyVox { if (isPrevXAvail) { - v100 = iYVolSpace > m_regSizeInVoxels.getLowerY() && iZVolSpace > m_regSizeInVoxels.getLowerZ() ? m_sampVolume.peekVoxel0px1ny1nz() : VolumeType::VoxelType(); - v110 = iZVolSpace > m_regSizeInVoxels.getLowerZ() ? m_sampVolume.peekVoxel0px0py1nz() : VolumeType::VoxelType(); + v100 = m_sampVolume.peekVoxel0px1ny1nz(); + v110 = m_sampVolume.peekVoxel0px0py1nz(); - v101 = iYVolSpace > m_regSizeInVoxels.getLowerY() ? m_sampVolume.peekVoxel0px1ny0pz() : VolumeType::VoxelType(); + v101 = m_sampVolume.peekVoxel0px1ny0pz(); v111 = m_sampVolume.peekVoxel0px0py0pz(); //x @@ -259,14 +259,14 @@ namespace PolyVox } else //previous X not available { - v000 = iXVolSpace > m_regSizeInVoxels.getLowerX() && iYVolSpace > m_regSizeInVoxels.getLowerY() && iZVolSpace > m_regSizeInVoxels.getLowerZ() ? m_sampVolume.peekVoxel1nx1ny1nz() : VolumeType::VoxelType(); - v100 = iYVolSpace > m_regSizeInVoxels.getLowerY() && iZVolSpace > m_regSizeInVoxels.getLowerZ() ? m_sampVolume.peekVoxel0px1ny1nz() : VolumeType::VoxelType(); - v010 = iXVolSpace > m_regSizeInVoxels.getLowerX() && iZVolSpace > m_regSizeInVoxels.getLowerZ() ? m_sampVolume.peekVoxel1nx0py1nz() : VolumeType::VoxelType(); - v110 = iZVolSpace > m_regSizeInVoxels.getLowerZ() ? m_sampVolume.peekVoxel0px0py1nz() : VolumeType::VoxelType(); + v000 = m_sampVolume.peekVoxel1nx1ny1nz(); + v100 = m_sampVolume.peekVoxel0px1ny1nz(); + v010 = m_sampVolume.peekVoxel1nx0py1nz(); + v110 = m_sampVolume.peekVoxel0px0py1nz(); - v001 = iXVolSpace > m_regSizeInVoxels.getLowerX() && iYVolSpace > m_regSizeInVoxels.getLowerY() ? m_sampVolume.peekVoxel1nx1ny0pz() : VolumeType::VoxelType(); - v101 = iYVolSpace > m_regSizeInVoxels.getLowerY() ? m_sampVolume.peekVoxel0px1ny0pz() : VolumeType::VoxelType(); - v011 = iXVolSpace > m_regSizeInVoxels.getLowerX() ? m_sampVolume.peekVoxel1nx0py0pz() : VolumeType::VoxelType(); + v001 = m_sampVolume.peekVoxel1nx1ny0pz(); + v101 = m_sampVolume.peekVoxel0px1ny0pz(); + v011 = m_sampVolume.peekVoxel1nx0py0pz(); v111 = m_sampVolume.peekVoxel0px0py0pz(); if (m_controller.convertToDensity(v000) < m_tThreshold) iCubeIndex |= 1; From 50cf939e8ab8f548c8ff21f4b59596f899ea5e18 Mon Sep 17 00:00:00 2001 From: David Williams Date: Fri, 22 May 2015 16:15:53 +0200 Subject: [PATCH 24/61] Reorganizing code. --- .../PolyVox/MarchingCubesSurfaceExtractor.h | 6 +--- .../PolyVox/MarchingCubesSurfaceExtractor.inl | 28 ++++++++----------- 2 files changed, 13 insertions(+), 21 deletions(-) diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.h b/include/PolyVox/MarchingCubesSurfaceExtractor.h index 3a14afa1..1a854930 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.h +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.h @@ -159,11 +159,7 @@ namespace PolyVox private: //Compute the cell bitmask for a particular slice in z. - template - void computeBitmaskForSlice(Array3DUint8& pBitmask, - Array3DInt32& pIndicesX, - Array3DInt32& pIndicesY, - Array3DInt32& pIndicesZ); + void computeBitmaskForSlice(); //////////////////////////////////////////////////////////////////////////////// // NOTE: These two functions are in the .h file rather than the .inl due to an apparent bug in VC2010. diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.inl b/include/PolyVox/MarchingCubesSurfaceExtractor.inl index e11dd42d..06a03bb9 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.inl +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.inl @@ -43,6 +43,18 @@ namespace PolyVox Timer timer; m_meshCurrent->clear(); + computeBitmaskForSlice(); + + m_meshCurrent->setOffset(m_regSizeInVoxels.getLowerCorner()); + + POLYVOX_LOG_TRACE("Marching cubes surface extraction took ", timer.elapsedTimeInMilliSeconds(), + "ms (Region size = ", m_regSizeInVoxels.getWidthInVoxels(), "x", m_regSizeInVoxels.getHeightInVoxels(), + "x", m_regSizeInVoxels.getDepthInVoxels(), ")"); + } + + template + void MarchingCubesSurfaceExtractor::computeBitmaskForSlice() + { const uint32_t uArrayWidth = m_regSizeInVoxels.getUpperX() - m_regSizeInVoxels.getLowerX() + 2; const uint32_t uArrayHeight = m_regSizeInVoxels.getUpperY() - m_regSizeInVoxels.getLowerY() + 2; const uint32_t uArrayDepth = m_regSizeInVoxels.getUpperZ() - m_regSizeInVoxels.getLowerZ() + 2; @@ -59,22 +71,6 @@ namespace PolyVox Array3DUint8 pBitmask(uArrayWidth, uArrayHeight, uArrayDepth); memset(pBitmask.getRawData(), 0x00, pBitmask.getNoOfElements()); - computeBitmaskForSlice(pBitmask, pIndicesX, pIndicesY, pIndicesZ); - - m_meshCurrent->setOffset(m_regSizeInVoxels.getLowerCorner()); - - POLYVOX_LOG_TRACE("Marching cubes surface extraction took ", timer.elapsedTimeInMilliSeconds(), - "ms (Region size = ", m_regSizeInVoxels.getWidthInVoxels(), "x", m_regSizeInVoxels.getHeightInVoxels(), - "x", m_regSizeInVoxels.getDepthInVoxels(), ")"); - } - - template - template - void MarchingCubesSurfaceExtractor::computeBitmaskForSlice(Array3DUint8& pBitmask, - Array3DInt32& pIndicesX, - Array3DInt32& pIndicesY, - Array3DInt32& pIndicesZ) - { for (int32_t iZVolSpace = m_regSizeInVoxels.getLowerZ(); iZVolSpace <= m_regSizeInVoxels.getUpperZ(); iZVolSpace++) { const uint32_t uZRegSpace = iZVolSpace - m_regSizeInVoxels.getLowerZ(); From 762c9a5090825794eb1fabee11fdbe0057e97398 Mon Sep 17 00:00:00 2001 From: David Williams Date: Fri, 22 May 2015 16:48:42 +0200 Subject: [PATCH 25/61] Switched 3D array back to two 2D arrays to reduce memory usage. --- .../PolyVox/MarchingCubesSurfaceExtractor.inl | 35 +++++++++++-------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.inl b/include/PolyVox/MarchingCubesSurfaceExtractor.inl index 06a03bb9..43348da6 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.inl +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.inl @@ -68,8 +68,10 @@ namespace PolyVox memset(pIndicesY.getRawData(), 0xff, pIndicesY.getNoOfElements() * 4); memset(pIndicesZ.getRawData(), 0xff, pIndicesZ.getNoOfElements() * 4); - Array3DUint8 pBitmask(uArrayWidth, uArrayHeight, uArrayDepth); - memset(pBitmask.getRawData(), 0x00, pBitmask.getNoOfElements()); + Array2DUint8 pCurrentBitmask(uArrayWidth, uArrayHeight); + Array2DUint8 pPreviousBitmask(uArrayWidth, uArrayHeight); + memset(pCurrentBitmask.getRawData(), 0x00, pCurrentBitmask.getNoOfElements()); + memset(pPreviousBitmask.getRawData(), 0x00, pPreviousBitmask.getNoOfElements()); for (int32_t iZVolSpace = m_regSizeInVoxels.getLowerZ(); iZVolSpace <= m_regSizeInVoxels.getUpperZ(); iZVolSpace++) { @@ -110,16 +112,16 @@ namespace PolyVox v111 = m_sampVolume.peekVoxel0px0py0pz(); //z - uint8_t iPreviousCubeIndexZ = pBitmask(uXRegSpace, uYRegSpace, uZRegSpace - 1); + uint8_t iPreviousCubeIndexZ = pPreviousBitmask(uXRegSpace, uYRegSpace); iPreviousCubeIndexZ >>= 4; //y - uint8_t iPreviousCubeIndexY = pBitmask(uXRegSpace, uYRegSpace - 1, uZRegSpace); + uint8_t iPreviousCubeIndexY = pCurrentBitmask(uXRegSpace, uYRegSpace - 1); iPreviousCubeIndexY &= 192; //192 = 128 + 64 iPreviousCubeIndexY >>= 2; //x - uint8_t iPreviousCubeIndexX = pBitmask(uXRegSpace - 1, uYRegSpace, uZRegSpace); + uint8_t iPreviousCubeIndexX = pCurrentBitmask(uXRegSpace - 1, uYRegSpace); iPreviousCubeIndexX &= 128; iPreviousCubeIndexX >>= 1; @@ -133,11 +135,11 @@ namespace PolyVox v111 = m_sampVolume.peekVoxel0px0py0pz(); //z - uint8_t iPreviousCubeIndexZ = pBitmask(uXRegSpace, uYRegSpace, uZRegSpace - 1); + uint8_t iPreviousCubeIndexZ = pPreviousBitmask(uXRegSpace, uYRegSpace); iPreviousCubeIndexZ >>= 4; //y - uint8_t iPreviousCubeIndexY = pBitmask(uXRegSpace, uYRegSpace - 1, uZRegSpace); + uint8_t iPreviousCubeIndexY = pCurrentBitmask(uXRegSpace, uYRegSpace - 1); iPreviousCubeIndexY &= 192; //192 = 128 + 64 iPreviousCubeIndexY >>= 2; @@ -155,11 +157,11 @@ namespace PolyVox v111 = m_sampVolume.peekVoxel0px0py0pz(); //z - uint8_t iPreviousCubeIndexZ = pBitmask(uXRegSpace, uYRegSpace, uZRegSpace - 1); + uint8_t iPreviousCubeIndexZ = pPreviousBitmask(uXRegSpace, uYRegSpace); iPreviousCubeIndexZ >>= 4; //x - uint8_t iPreviousCubeIndexX = pBitmask(uXRegSpace - 1, uYRegSpace, uZRegSpace); + uint8_t iPreviousCubeIndexX = pCurrentBitmask(uXRegSpace - 1, uYRegSpace); iPreviousCubeIndexX &= 160; //160 = 128+32 iPreviousCubeIndexX >>= 1; @@ -176,7 +178,7 @@ namespace PolyVox v111 = m_sampVolume.peekVoxel0px0py0pz(); //z - uint8_t iPreviousCubeIndexZ = pBitmask(uXRegSpace, uYRegSpace, uZRegSpace - 1); + uint8_t iPreviousCubeIndexZ = pPreviousBitmask(uXRegSpace, uYRegSpace); iCubeIndex = iPreviousCubeIndexZ >> 4; if (m_controller.convertToDensity(v001) < m_tThreshold) iCubeIndex |= 16; @@ -196,12 +198,12 @@ namespace PolyVox v111 = m_sampVolume.peekVoxel0px0py0pz(); //y - uint8_t iPreviousCubeIndexY = pBitmask(uXRegSpace, uYRegSpace - 1, uZRegSpace); + uint8_t iPreviousCubeIndexY = pCurrentBitmask(uXRegSpace, uYRegSpace - 1); iPreviousCubeIndexY &= 204; //204 = 128+64+8+4 iPreviousCubeIndexY >>= 2; //x - uint8_t iPreviousCubeIndexX = pBitmask(uXRegSpace - 1, uYRegSpace, uZRegSpace); + uint8_t iPreviousCubeIndexX = pCurrentBitmask(uXRegSpace - 1, uYRegSpace); iPreviousCubeIndexX &= 170; //170 = 128+32+8+2 iPreviousCubeIndexX >>= 1; @@ -219,7 +221,7 @@ namespace PolyVox v111 = m_sampVolume.peekVoxel0px0py0pz(); //y - uint8_t iPreviousCubeIndexY = pBitmask(uXRegSpace, uYRegSpace - 1, uZRegSpace); + uint8_t iPreviousCubeIndexY = pCurrentBitmask(uXRegSpace, uYRegSpace - 1); iPreviousCubeIndexY &= 204; //204 = 128+64+8+4 iPreviousCubeIndexY >>= 2; @@ -242,7 +244,7 @@ namespace PolyVox v111 = m_sampVolume.peekVoxel0px0py0pz(); //x - uint8_t iPreviousCubeIndexX = pBitmask(uXRegSpace - 1, uYRegSpace, uZRegSpace); + uint8_t iPreviousCubeIndexX = pCurrentBitmask(uXRegSpace - 1, uYRegSpace); iPreviousCubeIndexX &= 170; //170 = 128+32+8+2 iPreviousCubeIndexX >>= 1; @@ -280,7 +282,7 @@ namespace PolyVox if (iCubeIndex != 0) { //Save the bitmask - pBitmask(uXRegSpace, uYRegSpace, uZRegSpace) = iCubeIndex; + pCurrentBitmask(uXRegSpace, uYRegSpace) = iCubeIndex; } m_sampVolume.setPosition(iXVolSpace, iYVolSpace, iZVolSpace); @@ -478,6 +480,9 @@ namespace PolyVox }//For each triangle }//For each cell } + + pPreviousBitmask.swap(pCurrentBitmask); + memset(pCurrentBitmask.getRawData(), 0x00, pCurrentBitmask.getNoOfElements()); } } } From 5b84c5a9a51da852cc12a0168de1532dce81df3b Mon Sep 17 00:00:00 2001 From: David Williams Date: Sat, 23 May 2015 17:23:59 +0200 Subject: [PATCH 26/61] Removed unneeded call to setPosition(). --- include/PolyVox/MarchingCubesSurfaceExtractor.inl | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.inl b/include/PolyVox/MarchingCubesSurfaceExtractor.inl index 43348da6..71e8e9c3 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.inl +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.inl @@ -285,8 +285,6 @@ namespace PolyVox pCurrentBitmask(uXRegSpace, uYRegSpace) = iCubeIndex; } - m_sampVolume.setPosition(iXVolSpace, iYVolSpace, iZVolSpace); - /* Cube is entirely in/out of the surface */ if (edgeTable[iCubeIndex] == 0) { From cee15a145f822b913d33e3bb26c82cdb49954ff7 Mon Sep 17 00:00:00 2001 From: David Williams Date: Sat, 23 May 2015 17:45:16 +0200 Subject: [PATCH 27/61] Avoid setting the sampler position every iteration. --- .../PolyVox/MarchingCubesSurfaceExtractor.inl | 370 +++++++++--------- 1 file changed, 184 insertions(+), 186 deletions(-) diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.inl b/include/PolyVox/MarchingCubesSurfaceExtractor.inl index 71e8e9c3..5fde56e4 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.inl +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.inl @@ -81,12 +81,12 @@ namespace PolyVox { const uint32_t uYRegSpace = iYVolSpace - m_regSizeInVoxels.getLowerY(); + m_sampVolume.setPosition(m_regSizeInVoxels.getLowerX(), iYVolSpace, iZVolSpace); + for (int32_t iXVolSpace = m_regSizeInVoxels.getLowerX(); iXVolSpace <= m_regSizeInVoxels.getUpperX(); iXVolSpace++) { const uint32_t uXRegSpace = iXVolSpace - m_regSizeInVoxels.getLowerX(); - m_sampVolume.setPosition(iXVolSpace, iYVolSpace, iZVolSpace); - typename VolumeType::VoxelType v000; typename VolumeType::VoxelType v100; typename VolumeType::VoxelType v010; @@ -216,7 +216,7 @@ namespace PolyVox { v010 = m_sampVolume.peekVoxel1nx0py1nz(); v110 = m_sampVolume.peekVoxel0px0py1nz(); - + v011 = m_sampVolume.peekVoxel1nx0py0pz(); v111 = m_sampVolume.peekVoxel0px0py0pz(); @@ -236,7 +236,7 @@ namespace PolyVox else //previous Y not available { if (isPrevXAvail) - { + { v100 = m_sampVolume.peekVoxel0px1ny1nz(); v110 = m_sampVolume.peekVoxel0px0py1nz(); @@ -286,197 +286,195 @@ namespace PolyVox } /* Cube is entirely in/out of the surface */ - if (edgeTable[iCubeIndex] == 0) + if (edgeTable[iCubeIndex] != 0) { - continue; - } - // These three might not have been sampled, as v111 is the only one we sample every iteration. - v110 = m_sampVolume.peekVoxel0px0py1nz(); - v101 = m_sampVolume.peekVoxel0px1ny0pz(); - v011 = m_sampVolume.peekVoxel1nx0py0pz(); - - const Vector3DFloat n000 = computeCentralDifferenceGradient(m_sampVolume); + // These three might not have been sampled, as v111 is the only one we sample every iteration. + v110 = m_sampVolume.peekVoxel0px0py1nz(); + v101 = m_sampVolume.peekVoxel0px1ny0pz(); + v011 = m_sampVolume.peekVoxel1nx0py0pz(); - /* Find the vertices where the surface intersects the cube */ - if ((edgeTable[iCubeIndex] & 64) && (uXRegSpace > 0)) - { - m_sampVolume.moveNegativeX(); - POLYVOX_ASSERT(v011 != v111, "Attempting to insert vertex between two voxels with the same value"); - const Vector3DFloat n100 = computeCentralDifferenceGradient(m_sampVolume); + const Vector3DFloat n000 = computeCentralDifferenceGradient(m_sampVolume); - const float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v011)) / static_cast(m_controller.convertToDensity(v111) - m_controller.convertToDensity(v011)); - - const Vector3DFloat v3dPosition(static_cast(uXRegSpace - 1) + fInterp, static_cast(uYRegSpace), static_cast(uZRegSpace)); - const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); - - Vector3DFloat v3dNormal = (n100*fInterp) + (n000*(1 - fInterp)); - - // The gradient for a voxel can be zero (e.g. solid voxel surrounded by empty ones) and so - // the interpolated normal can also be zero (e.g. a grid of alternating solid and empty voxels). - if (v3dNormal.lengthSquared() > 0.000001f) + /* Find the vertices where the surface intersects the cube */ + if ((edgeTable[iCubeIndex] & 64) && (uXRegSpace > 0)) { - v3dNormal.normalise(); + m_sampVolume.moveNegativeX(); + POLYVOX_ASSERT(v011 != v111, "Attempting to insert vertex between two voxels with the same value"); + const Vector3DFloat n100 = computeCentralDifferenceGradient(m_sampVolume); + + const float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v011)) / static_cast(m_controller.convertToDensity(v111) - m_controller.convertToDensity(v011)); + + const Vector3DFloat v3dPosition(static_cast(uXRegSpace - 1) + fInterp, static_cast(uYRegSpace), static_cast(uZRegSpace)); + const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); + + Vector3DFloat v3dNormal = (n100*fInterp) + (n000*(1 - fInterp)); + + // The gradient for a voxel can be zero (e.g. solid voxel surrounded by empty ones) and so + // the interpolated normal can also be zero (e.g. a grid of alternating solid and empty voxels). + if (v3dNormal.lengthSquared() > 0.000001f) + { + v3dNormal.normalise(); + } + + // Allow the controller to decide how the material should be derived from the voxels. + const typename VolumeType::VoxelType uMaterial = m_controller.blendMaterials(v011, v111, fInterp); + + MarchingCubesVertex surfaceVertex; + surfaceVertex.encodedPosition = v3dScaledPosition; + surfaceVertex.encodedNormal = encodeNormal(v3dNormal); + surfaceVertex.data = uMaterial; + + const uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex); + pIndicesX(uXRegSpace, uYRegSpace, uZRegSpace) = uLastVertexIndex; + + m_sampVolume.movePositiveX(); + } + if ((edgeTable[iCubeIndex] & 32) && (uYRegSpace > 0)) + { + m_sampVolume.moveNegativeY(); + POLYVOX_ASSERT(v101 != v111, "Attempting to insert vertex between two voxels with the same value"); + const Vector3DFloat n010 = computeCentralDifferenceGradient(m_sampVolume); + + const float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v101)) / static_cast(m_controller.convertToDensity(v111) - m_controller.convertToDensity(v101)); + + const Vector3DFloat v3dPosition(static_cast(uXRegSpace), static_cast(uYRegSpace - 1) + fInterp, static_cast(uZRegSpace)); + const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); + + Vector3DFloat v3dNormal = (n010*fInterp) + (n000*(1 - fInterp)); + + // The gradient for a voxel can be zero (e.g. solid voxel surrounded by empty ones) and so + // the interpolated normal can also be zero (e.g. a grid of alternating solid and empty voxels). + if (v3dNormal.lengthSquared() > 0.000001f) + { + v3dNormal.normalise(); + } + + // Allow the controller to decide how the material should be derived from the voxels. + const typename VolumeType::VoxelType uMaterial = m_controller.blendMaterials(v101, v111, fInterp); + + MarchingCubesVertex surfaceVertex; + surfaceVertex.encodedPosition = v3dScaledPosition; + surfaceVertex.encodedNormal = encodeNormal(v3dNormal); + surfaceVertex.data = uMaterial; + + uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex); + pIndicesY(uXRegSpace, uYRegSpace, uZRegSpace) = uLastVertexIndex; + + m_sampVolume.movePositiveY(); + } + if ((edgeTable[iCubeIndex] & 1024) && (uZRegSpace > 0)) + { + m_sampVolume.moveNegativeZ(); + POLYVOX_ASSERT(v110 != v111, "Attempting to insert vertex between two voxels with the same value"); + const Vector3DFloat n001 = computeCentralDifferenceGradient(m_sampVolume); + + const float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v110)) / static_cast(m_controller.convertToDensity(v111) - m_controller.convertToDensity(v110)); + + const Vector3DFloat v3dPosition(static_cast(uXRegSpace), static_cast(uYRegSpace), static_cast(uZRegSpace - 1) + fInterp); + const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); + + Vector3DFloat v3dNormal = (n001*fInterp) + (n000*(1 - fInterp)); + // The gradient for a voxel can be zero (e.g. solid voxel surrounded by empty ones) and so + // the interpolated normal can also be zero (e.g. a grid of alternating solid and empty voxels). + if (v3dNormal.lengthSquared() > 0.000001f) + { + v3dNormal.normalise(); + } + + // Allow the controller to decide how the material should be derived from the voxels. + const typename VolumeType::VoxelType uMaterial = m_controller.blendMaterials(v110, v111, fInterp); + + MarchingCubesVertex surfaceVertex; + surfaceVertex.encodedPosition = v3dScaledPosition; + surfaceVertex.encodedNormal = encodeNormal(v3dNormal); + surfaceVertex.data = uMaterial; + + const uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex); + pIndicesZ(uXRegSpace, uYRegSpace, uZRegSpace) = uLastVertexIndex; + + m_sampVolume.movePositiveZ(); } - // Allow the controller to decide how the material should be derived from the voxels. - const typename VolumeType::VoxelType uMaterial = m_controller.blendMaterials(v011, v111, fInterp); - - MarchingCubesVertex surfaceVertex; - surfaceVertex.encodedPosition = v3dScaledPosition; - surfaceVertex.encodedNormal = encodeNormal(v3dNormal); - surfaceVertex.data = uMaterial; - - const uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex); - pIndicesX(uXRegSpace, uYRegSpace, uZRegSpace) = uLastVertexIndex; - - m_sampVolume.movePositiveX(); - } - if ((edgeTable[iCubeIndex] & 32) && (uYRegSpace > 0)) - { - m_sampVolume.moveNegativeY(); - POLYVOX_ASSERT(v101 != v111, "Attempting to insert vertex between two voxels with the same value"); - const Vector3DFloat n010 = computeCentralDifferenceGradient(m_sampVolume); - - const float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v101)) / static_cast(m_controller.convertToDensity(v111) - m_controller.convertToDensity(v101)); - - const Vector3DFloat v3dPosition(static_cast(uXRegSpace), static_cast(uYRegSpace - 1) + fInterp, static_cast(uZRegSpace)); - const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); - - Vector3DFloat v3dNormal = (n010*fInterp) + (n000*(1 - fInterp)); - - // The gradient for a voxel can be zero (e.g. solid voxel surrounded by empty ones) and so - // the interpolated normal can also be zero (e.g. a grid of alternating solid and empty voxels). - if (v3dNormal.lengthSquared() > 0.000001f) + // Now output the indices. For the first row, column or slice there aren't + // any (the region size in cells is one less than the region size in voxels) + if ((isPrevXAvail) && (isPrevYAvail) && (isPrevZAvail)) { - v3dNormal.normalise(); + + int32_t indlist[12]; + + m_sampVolume.setPosition(iXVolSpace, iYVolSpace, iZVolSpace); + + /* Cube is entirely in/out of the surface */ + if (edgeTable[iCubeIndex] != 0) + { + + /* Find the vertices where the surface intersects the cube */ + if (edgeTable[iCubeIndex] & 1) + { + indlist[0] = pIndicesX(uXRegSpace, uYRegSpace - 1, uZRegSpace - 1); + } + if (edgeTable[iCubeIndex] & 2) + { + indlist[1] = pIndicesY(uXRegSpace, uYRegSpace, uZRegSpace - 1); + } + if (edgeTable[iCubeIndex] & 4) + { + indlist[2] = pIndicesX(uXRegSpace, uYRegSpace, uZRegSpace - 1); + } + if (edgeTable[iCubeIndex] & 8) + { + indlist[3] = pIndicesY(uXRegSpace - 1, uYRegSpace, uZRegSpace - 1); + } + if (edgeTable[iCubeIndex] & 16) + { + indlist[4] = pIndicesX(uXRegSpace, uYRegSpace - 1, uZRegSpace); + } + if (edgeTable[iCubeIndex] & 32) + { + indlist[5] = pIndicesY(uXRegSpace, uYRegSpace, uZRegSpace); + } + if (edgeTable[iCubeIndex] & 64) + { + indlist[6] = pIndicesX(uXRegSpace, uYRegSpace, uZRegSpace); + } + if (edgeTable[iCubeIndex] & 128) + { + indlist[7] = pIndicesY(uXRegSpace - 1, uYRegSpace, uZRegSpace); + } + if (edgeTable[iCubeIndex] & 256) + { + indlist[8] = pIndicesZ(uXRegSpace - 1, uYRegSpace - 1, uZRegSpace); + } + if (edgeTable[iCubeIndex] & 512) + { + indlist[9] = pIndicesZ(uXRegSpace, uYRegSpace - 1, uZRegSpace); + } + if (edgeTable[iCubeIndex] & 1024) + { + indlist[10] = pIndicesZ(uXRegSpace, uYRegSpace, uZRegSpace); + } + if (edgeTable[iCubeIndex] & 2048) + { + indlist[11] = pIndicesZ(uXRegSpace - 1, uYRegSpace, uZRegSpace); + } + + for (int i = 0; triTable[iCubeIndex][i] != -1; i += 3) + { + const int32_t ind0 = indlist[triTable[iCubeIndex][i]]; + const int32_t ind1 = indlist[triTable[iCubeIndex][i + 1]]; + const int32_t ind2 = indlist[triTable[iCubeIndex][i + 2]]; + + if ((ind0 != -1) && (ind1 != -1) && (ind2 != -1)) + { + m_meshCurrent->addTriangle(ind0, ind1, ind2); + } + }//For each triangle + } } - - // Allow the controller to decide how the material should be derived from the voxels. - const typename VolumeType::VoxelType uMaterial = m_controller.blendMaterials(v101, v111, fInterp); - - MarchingCubesVertex surfaceVertex; - surfaceVertex.encodedPosition = v3dScaledPosition; - surfaceVertex.encodedNormal = encodeNormal(v3dNormal); - surfaceVertex.data = uMaterial; - - uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex); - pIndicesY(uXRegSpace, uYRegSpace, uZRegSpace) = uLastVertexIndex; - - m_sampVolume.movePositiveY(); - } - if ((edgeTable[iCubeIndex] & 1024) && (uZRegSpace > 0)) - { - m_sampVolume.moveNegativeZ(); - POLYVOX_ASSERT(v110 != v111, "Attempting to insert vertex between two voxels with the same value"); - const Vector3DFloat n001 = computeCentralDifferenceGradient(m_sampVolume); - - const float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v110)) / static_cast(m_controller.convertToDensity(v111) - m_controller.convertToDensity(v110)); - - const Vector3DFloat v3dPosition(static_cast(uXRegSpace), static_cast(uYRegSpace), static_cast(uZRegSpace - 1) + fInterp); - const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); - - Vector3DFloat v3dNormal = (n001*fInterp) + (n000*(1 - fInterp)); - // The gradient for a voxel can be zero (e.g. solid voxel surrounded by empty ones) and so - // the interpolated normal can also be zero (e.g. a grid of alternating solid and empty voxels). - if (v3dNormal.lengthSquared() > 0.000001f) - { - v3dNormal.normalise(); - } - - // Allow the controller to decide how the material should be derived from the voxels. - const typename VolumeType::VoxelType uMaterial = m_controller.blendMaterials(v110, v111, fInterp); - - MarchingCubesVertex surfaceVertex; - surfaceVertex.encodedPosition = v3dScaledPosition; - surfaceVertex.encodedNormal = encodeNormal(v3dNormal); - surfaceVertex.data = uMaterial; - - const uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex); - pIndicesZ(uXRegSpace, uYRegSpace, uZRegSpace) = uLastVertexIndex; - - m_sampVolume.movePositiveZ(); - } - - // Now output the indices. For the first row, column or slice there aren't - // any (the region size in cells is one less than the region size in voxels) - if ((!isPrevXAvail) || (!isPrevYAvail) || (!isPrevZAvail)) - { - continue; - } - - int32_t indlist[12]; - - m_sampVolume.setPosition(iXVolSpace, iYVolSpace, iZVolSpace); - - /* Cube is entirely in/out of the surface */ - if (edgeTable[iCubeIndex] == 0) - { - continue; - } - - /* Find the vertices where the surface intersects the cube */ - if (edgeTable[iCubeIndex] & 1) - { - indlist[0] = pIndicesX(uXRegSpace, uYRegSpace - 1, uZRegSpace - 1); - } - if (edgeTable[iCubeIndex] & 2) - { - indlist[1] = pIndicesY(uXRegSpace, uYRegSpace, uZRegSpace - 1); - } - if (edgeTable[iCubeIndex] & 4) - { - indlist[2] = pIndicesX(uXRegSpace, uYRegSpace, uZRegSpace - 1); - } - if (edgeTable[iCubeIndex] & 8) - { - indlist[3] = pIndicesY(uXRegSpace - 1, uYRegSpace, uZRegSpace - 1); - } - if (edgeTable[iCubeIndex] & 16) - { - indlist[4] = pIndicesX(uXRegSpace, uYRegSpace - 1, uZRegSpace); - } - if (edgeTable[iCubeIndex] & 32) - { - indlist[5] = pIndicesY(uXRegSpace, uYRegSpace, uZRegSpace); - } - if (edgeTable[iCubeIndex] & 64) - { - indlist[6] = pIndicesX(uXRegSpace, uYRegSpace, uZRegSpace); - } - if (edgeTable[iCubeIndex] & 128) - { - indlist[7] = pIndicesY(uXRegSpace - 1, uYRegSpace, uZRegSpace); - } - if (edgeTable[iCubeIndex] & 256) - { - indlist[8] = pIndicesZ(uXRegSpace - 1, uYRegSpace - 1, uZRegSpace); - } - if (edgeTable[iCubeIndex] & 512) - { - indlist[9] = pIndicesZ(uXRegSpace, uYRegSpace - 1, uZRegSpace); - } - if (edgeTable[iCubeIndex] & 1024) - { - indlist[10] = pIndicesZ(uXRegSpace, uYRegSpace, uZRegSpace); - } - if (edgeTable[iCubeIndex] & 2048) - { - indlist[11] = pIndicesZ(uXRegSpace - 1, uYRegSpace, uZRegSpace); - } - - for (int i = 0; triTable[iCubeIndex][i] != -1; i += 3) - { - const int32_t ind0 = indlist[triTable[iCubeIndex][i]]; - const int32_t ind1 = indlist[triTable[iCubeIndex][i + 1]]; - const int32_t ind2 = indlist[triTable[iCubeIndex][i + 2]]; - - if ((ind0 != -1) && (ind1 != -1) && (ind2 != -1)) - { - m_meshCurrent->addTriangle(ind0, ind1, ind2); - } - }//For each triangle - }//For each cell + }//For each cell + m_sampVolume.movePositiveX(); + } } pPreviousBitmask.swap(pCurrentBitmask); From 4e9b0e374b55657d1a9921226697f94515e50b2e Mon Sep 17 00:00:00 2001 From: David Williams Date: Sun, 24 May 2015 00:02:27 +0200 Subject: [PATCH 28/61] Moved code into outer loops. --- include/PolyVox/MarchingCubesSurfaceExtractor.inl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.inl b/include/PolyVox/MarchingCubesSurfaceExtractor.inl index 5fde56e4..d561571e 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.inl +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.inl @@ -76,16 +76,19 @@ namespace PolyVox for (int32_t iZVolSpace = m_regSizeInVoxels.getLowerZ(); iZVolSpace <= m_regSizeInVoxels.getUpperZ(); iZVolSpace++) { const uint32_t uZRegSpace = iZVolSpace - m_regSizeInVoxels.getLowerZ(); + bool isPrevZAvail = iZVolSpace > m_regSizeInVoxels.getLowerZ(); for (int32_t iYVolSpace = m_regSizeInVoxels.getLowerY(); iYVolSpace <= m_regSizeInVoxels.getUpperY(); iYVolSpace++) { const uint32_t uYRegSpace = iYVolSpace - m_regSizeInVoxels.getLowerY(); + bool isPrevYAvail = iYVolSpace > m_regSizeInVoxels.getLowerY(); m_sampVolume.setPosition(m_regSizeInVoxels.getLowerX(), iYVolSpace, iZVolSpace); for (int32_t iXVolSpace = m_regSizeInVoxels.getLowerX(); iXVolSpace <= m_regSizeInVoxels.getUpperX(); iXVolSpace++) { const uint32_t uXRegSpace = iXVolSpace - m_regSizeInVoxels.getLowerX(); + bool isPrevXAvail = iXVolSpace > m_regSizeInVoxels.getLowerX(); typename VolumeType::VoxelType v000; typename VolumeType::VoxelType v100; @@ -98,10 +101,7 @@ namespace PolyVox typename VolumeType::VoxelType v111; uint8_t iCubeIndex = 0; - - bool isPrevXAvail = iXVolSpace > m_regSizeInVoxels.getLowerX(); - bool isPrevYAvail = iYVolSpace > m_regSizeInVoxels.getLowerY(); - bool isPrevZAvail = iZVolSpace > m_regSizeInVoxels.getLowerZ(); + if (isPrevZAvail) { From 32df8be8dab1ecc0ad404c91676ab8be531ab36d Mon Sep 17 00:00:00 2001 From: David Williams Date: Sun, 24 May 2015 07:59:03 +0200 Subject: [PATCH 29/61] Tweaked conditions and comments. --- .../PolyVox/MarchingCubesSurfaceExtractor.inl | 43 +++++++++---------- 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.inl b/include/PolyVox/MarchingCubesSurfaceExtractor.inl index d561571e..40827aa6 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.inl +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.inl @@ -76,19 +76,16 @@ namespace PolyVox for (int32_t iZVolSpace = m_regSizeInVoxels.getLowerZ(); iZVolSpace <= m_regSizeInVoxels.getUpperZ(); iZVolSpace++) { const uint32_t uZRegSpace = iZVolSpace - m_regSizeInVoxels.getLowerZ(); - bool isPrevZAvail = iZVolSpace > m_regSizeInVoxels.getLowerZ(); for (int32_t iYVolSpace = m_regSizeInVoxels.getLowerY(); iYVolSpace <= m_regSizeInVoxels.getUpperY(); iYVolSpace++) { const uint32_t uYRegSpace = iYVolSpace - m_regSizeInVoxels.getLowerY(); - bool isPrevYAvail = iYVolSpace > m_regSizeInVoxels.getLowerY(); m_sampVolume.setPosition(m_regSizeInVoxels.getLowerX(), iYVolSpace, iZVolSpace); for (int32_t iXVolSpace = m_regSizeInVoxels.getLowerX(); iXVolSpace <= m_regSizeInVoxels.getUpperX(); iXVolSpace++) { const uint32_t uXRegSpace = iXVolSpace - m_regSizeInVoxels.getLowerX(); - bool isPrevXAvail = iXVolSpace > m_regSizeInVoxels.getLowerX(); typename VolumeType::VoxelType v000; typename VolumeType::VoxelType v100; @@ -103,11 +100,11 @@ namespace PolyVox uint8_t iCubeIndex = 0; - if (isPrevZAvail) + if (uZRegSpace != 0) // Previous Z is available { - if (isPrevYAvail) + if (uYRegSpace != 0) // Previous Y is available { - if (isPrevXAvail) + if (uXRegSpace != 0) // Previous X is available { v111 = m_sampVolume.peekVoxel0px0py0pz(); @@ -129,7 +126,7 @@ namespace PolyVox if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128; } - else //previous X not available + else // Previous X not available { v011 = m_sampVolume.peekVoxel1nx0py0pz(); v111 = m_sampVolume.peekVoxel0px0py0pz(); @@ -149,9 +146,9 @@ namespace PolyVox if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128; } } - else //previous Y not available + else // Previous Y not available { - if (isPrevXAvail) + if (uXRegSpace != 0) { v101 = m_sampVolume.peekVoxel0px1ny0pz(); v111 = m_sampVolume.peekVoxel0px0py0pz(); @@ -170,7 +167,7 @@ namespace PolyVox if (m_controller.convertToDensity(v101) < m_tThreshold) iCubeIndex |= 32; if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128; } - else //previous X not available + else // Previous X not available { v001 = m_sampVolume.peekVoxel1nx1ny0pz(); v101 = m_sampVolume.peekVoxel0px1ny0pz(); @@ -188,11 +185,11 @@ namespace PolyVox } } } - else //previous Z not available + else // Previous Z not available { - if (isPrevYAvail) + if (uYRegSpace != 0) // Previous Y is available { - if (isPrevXAvail) + if (uXRegSpace != 0) // Previous X is available { v110 = m_sampVolume.peekVoxel0px0py1nz(); v111 = m_sampVolume.peekVoxel0px0py0pz(); @@ -212,7 +209,7 @@ namespace PolyVox if (m_controller.convertToDensity(v110) < m_tThreshold) iCubeIndex |= 8; if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128; } - else //previous X not available + else // Previous X not available { v010 = m_sampVolume.peekVoxel1nx0py1nz(); v110 = m_sampVolume.peekVoxel0px0py1nz(); @@ -233,9 +230,9 @@ namespace PolyVox if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128; } } - else //previous Y not available + else // Previous Y not available { - if (isPrevXAvail) + if (uXRegSpace != 0) // Previous X is available { v100 = m_sampVolume.peekVoxel0px1ny1nz(); v110 = m_sampVolume.peekVoxel0px0py1nz(); @@ -255,7 +252,7 @@ namespace PolyVox if (m_controller.convertToDensity(v101) < m_tThreshold) iCubeIndex |= 32; if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128; } - else //previous X not available + else // Previous X not available { v000 = m_sampVolume.peekVoxel1nx1ny1nz(); v100 = m_sampVolume.peekVoxel0px1ny1nz(); @@ -398,7 +395,7 @@ namespace PolyVox // Now output the indices. For the first row, column or slice there aren't // any (the region size in cells is one less than the region size in voxels) - if ((isPrevXAvail) && (isPrevYAvail) && (isPrevZAvail)) + if ((uXRegSpace != 0) && (uYRegSpace != 0) && (uZRegSpace != 0)) { int32_t indlist[12]; @@ -469,16 +466,16 @@ namespace PolyVox { m_meshCurrent->addTriangle(ind0, ind1, ind2); } - }//For each triangle + } // For each triangle } } - }//For each cell + } // For each cell m_sampVolume.movePositiveX(); - } - } + } // For X + } // For Y pPreviousBitmask.swap(pCurrentBitmask); memset(pCurrentBitmask.getRawData(), 0x00, pCurrentBitmask.getNoOfElements()); - } + } // For Z } } From eb3727de30a1895b328a8a1ddbcbce0176d6ac04 Mon Sep 17 00:00:00 2001 From: David Williams Date: Sun, 24 May 2015 20:41:46 +0200 Subject: [PATCH 30/61] Vastly simplified logic... hard to believe I made it so complicated :-) --- .../PolyVox/MarchingCubesSurfaceExtractor.inl | 210 +++--------------- 1 file changed, 27 insertions(+), 183 deletions(-) diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.inl b/include/PolyVox/MarchingCubesSurfaceExtractor.inl index 40827aa6..ec09a70e 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.inl +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.inl @@ -87,194 +87,38 @@ namespace PolyVox { const uint32_t uXRegSpace = iXVolSpace - m_regSizeInVoxels.getLowerX(); - typename VolumeType::VoxelType v000; - typename VolumeType::VoxelType v100; - typename VolumeType::VoxelType v010; - typename VolumeType::VoxelType v110; - - typename VolumeType::VoxelType v001; - typename VolumeType::VoxelType v101; - typename VolumeType::VoxelType v011; - typename VolumeType::VoxelType v111; - uint8_t iCubeIndex = 0; + typename VolumeType::VoxelType v111 = m_sampVolume.peekVoxel0px0py0pz(); + + uint8_t iPreviousCubeIndexX = 0; + uint8_t iPreviousCubeIndexY = 0; + uint8_t iPreviousCubeIndexZ = 0; + + if (uXRegSpace != 0) // Previous X is available + { + //x + iPreviousCubeIndexX = pCurrentBitmask(uXRegSpace - 1, uYRegSpace); + iPreviousCubeIndexX &= 170; //170 = 128+32+8+2 + iPreviousCubeIndexX >>= 1; + } + + if (uYRegSpace != 0) // Previous Y is available + { + iPreviousCubeIndexY = pCurrentBitmask(uXRegSpace, uYRegSpace - 1); + iPreviousCubeIndexY &= 204; //204 = 128+64+8+4 + iPreviousCubeIndexY >>= 2; + } if (uZRegSpace != 0) // Previous Z is available { - if (uYRegSpace != 0) // Previous Y is available - { - if (uXRegSpace != 0) // Previous X is available - { - v111 = m_sampVolume.peekVoxel0px0py0pz(); - - //z - uint8_t iPreviousCubeIndexZ = pPreviousBitmask(uXRegSpace, uYRegSpace); - iPreviousCubeIndexZ >>= 4; - - //y - uint8_t iPreviousCubeIndexY = pCurrentBitmask(uXRegSpace, uYRegSpace - 1); - iPreviousCubeIndexY &= 192; //192 = 128 + 64 - iPreviousCubeIndexY >>= 2; - - //x - uint8_t iPreviousCubeIndexX = pCurrentBitmask(uXRegSpace - 1, uYRegSpace); - iPreviousCubeIndexX &= 128; - iPreviousCubeIndexX >>= 1; - - iCubeIndex = iPreviousCubeIndexX | iPreviousCubeIndexY | iPreviousCubeIndexZ; - - if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128; - } - else // Previous X not available - { - v011 = m_sampVolume.peekVoxel1nx0py0pz(); - v111 = m_sampVolume.peekVoxel0px0py0pz(); - - //z - uint8_t iPreviousCubeIndexZ = pPreviousBitmask(uXRegSpace, uYRegSpace); - iPreviousCubeIndexZ >>= 4; - - //y - uint8_t iPreviousCubeIndexY = pCurrentBitmask(uXRegSpace, uYRegSpace - 1); - iPreviousCubeIndexY &= 192; //192 = 128 + 64 - iPreviousCubeIndexY >>= 2; - - iCubeIndex = iPreviousCubeIndexY | iPreviousCubeIndexZ; - - if (m_controller.convertToDensity(v011) < m_tThreshold) iCubeIndex |= 64; - if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128; - } - } - else // Previous Y not available - { - if (uXRegSpace != 0) - { - v101 = m_sampVolume.peekVoxel0px1ny0pz(); - v111 = m_sampVolume.peekVoxel0px0py0pz(); - - //z - uint8_t iPreviousCubeIndexZ = pPreviousBitmask(uXRegSpace, uYRegSpace); - iPreviousCubeIndexZ >>= 4; - - //x - uint8_t iPreviousCubeIndexX = pCurrentBitmask(uXRegSpace - 1, uYRegSpace); - iPreviousCubeIndexX &= 160; //160 = 128+32 - iPreviousCubeIndexX >>= 1; - - iCubeIndex = iPreviousCubeIndexX | iPreviousCubeIndexZ; - - if (m_controller.convertToDensity(v101) < m_tThreshold) iCubeIndex |= 32; - if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128; - } - else // Previous X not available - { - v001 = m_sampVolume.peekVoxel1nx1ny0pz(); - v101 = m_sampVolume.peekVoxel0px1ny0pz(); - v011 = m_sampVolume.peekVoxel1nx0py0pz(); - v111 = m_sampVolume.peekVoxel0px0py0pz(); - - //z - uint8_t iPreviousCubeIndexZ = pPreviousBitmask(uXRegSpace, uYRegSpace); - iCubeIndex = iPreviousCubeIndexZ >> 4; - - if (m_controller.convertToDensity(v001) < m_tThreshold) iCubeIndex |= 16; - if (m_controller.convertToDensity(v101) < m_tThreshold) iCubeIndex |= 32; - if (m_controller.convertToDensity(v011) < m_tThreshold) iCubeIndex |= 64; - if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128; - } - } + iPreviousCubeIndexZ = pPreviousBitmask(uXRegSpace, uYRegSpace); + iPreviousCubeIndexZ >>= 4; } - else // Previous Z not available - { - if (uYRegSpace != 0) // Previous Y is available - { - if (uXRegSpace != 0) // Previous X is available - { - v110 = m_sampVolume.peekVoxel0px0py1nz(); - v111 = m_sampVolume.peekVoxel0px0py0pz(); - //y - uint8_t iPreviousCubeIndexY = pCurrentBitmask(uXRegSpace, uYRegSpace - 1); - iPreviousCubeIndexY &= 204; //204 = 128+64+8+4 - iPreviousCubeIndexY >>= 2; + iCubeIndex = iPreviousCubeIndexX | iPreviousCubeIndexY | iPreviousCubeIndexZ; - //x - uint8_t iPreviousCubeIndexX = pCurrentBitmask(uXRegSpace - 1, uYRegSpace); - iPreviousCubeIndexX &= 170; //170 = 128+32+8+2 - iPreviousCubeIndexX >>= 1; - - iCubeIndex = iPreviousCubeIndexX | iPreviousCubeIndexY; - - if (m_controller.convertToDensity(v110) < m_tThreshold) iCubeIndex |= 8; - if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128; - } - else // Previous X not available - { - v010 = m_sampVolume.peekVoxel1nx0py1nz(); - v110 = m_sampVolume.peekVoxel0px0py1nz(); - - v011 = m_sampVolume.peekVoxel1nx0py0pz(); - v111 = m_sampVolume.peekVoxel0px0py0pz(); - - //y - uint8_t iPreviousCubeIndexY = pCurrentBitmask(uXRegSpace, uYRegSpace - 1); - iPreviousCubeIndexY &= 204; //204 = 128+64+8+4 - iPreviousCubeIndexY >>= 2; - - iCubeIndex = iPreviousCubeIndexY; - - if (m_controller.convertToDensity(v010) < m_tThreshold) iCubeIndex |= 4; - if (m_controller.convertToDensity(v110) < m_tThreshold) iCubeIndex |= 8; - if (m_controller.convertToDensity(v011) < m_tThreshold) iCubeIndex |= 64; - if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128; - } - } - else // Previous Y not available - { - if (uXRegSpace != 0) // Previous X is available - { - v100 = m_sampVolume.peekVoxel0px1ny1nz(); - v110 = m_sampVolume.peekVoxel0px0py1nz(); - - v101 = m_sampVolume.peekVoxel0px1ny0pz(); - v111 = m_sampVolume.peekVoxel0px0py0pz(); - - //x - uint8_t iPreviousCubeIndexX = pCurrentBitmask(uXRegSpace - 1, uYRegSpace); - iPreviousCubeIndexX &= 170; //170 = 128+32+8+2 - iPreviousCubeIndexX >>= 1; - - iCubeIndex = iPreviousCubeIndexX; - - if (m_controller.convertToDensity(v100) < m_tThreshold) iCubeIndex |= 2; - if (m_controller.convertToDensity(v110) < m_tThreshold) iCubeIndex |= 8; - if (m_controller.convertToDensity(v101) < m_tThreshold) iCubeIndex |= 32; - if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128; - } - else // Previous X not available - { - v000 = m_sampVolume.peekVoxel1nx1ny1nz(); - v100 = m_sampVolume.peekVoxel0px1ny1nz(); - v010 = m_sampVolume.peekVoxel1nx0py1nz(); - v110 = m_sampVolume.peekVoxel0px0py1nz(); - - v001 = m_sampVolume.peekVoxel1nx1ny0pz(); - v101 = m_sampVolume.peekVoxel0px1ny0pz(); - v011 = m_sampVolume.peekVoxel1nx0py0pz(); - v111 = m_sampVolume.peekVoxel0px0py0pz(); - - if (m_controller.convertToDensity(v000) < m_tThreshold) iCubeIndex |= 1; - if (m_controller.convertToDensity(v100) < m_tThreshold) iCubeIndex |= 2; - if (m_controller.convertToDensity(v010) < m_tThreshold) iCubeIndex |= 4; - if (m_controller.convertToDensity(v110) < m_tThreshold) iCubeIndex |= 8; - if (m_controller.convertToDensity(v001) < m_tThreshold) iCubeIndex |= 16; - if (m_controller.convertToDensity(v101) < m_tThreshold) iCubeIndex |= 32; - if (m_controller.convertToDensity(v011) < m_tThreshold) iCubeIndex |= 64; - if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128; - } - } - } + if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128; if (iCubeIndex != 0) { @@ -287,9 +131,9 @@ namespace PolyVox { // These three might not have been sampled, as v111 is the only one we sample every iteration. - v110 = m_sampVolume.peekVoxel0px0py1nz(); - v101 = m_sampVolume.peekVoxel0px1ny0pz(); - v011 = m_sampVolume.peekVoxel1nx0py0pz(); + typename VolumeType::VoxelType v110 = m_sampVolume.peekVoxel0px0py1nz(); + typename VolumeType::VoxelType v101 = m_sampVolume.peekVoxel0px1ny0pz(); + typename VolumeType::VoxelType v011 = m_sampVolume.peekVoxel1nx0py0pz(); const Vector3DFloat n000 = computeCentralDifferenceGradient(m_sampVolume); From 69349d95cdf8c0762f0be1010638aa8fc5b62389 Mon Sep 17 00:00:00 2001 From: David Williams Date: Sun, 24 May 2015 21:01:01 +0200 Subject: [PATCH 31/61] Tidying up. --- include/PolyVox/MarchingCubesSurfaceExtractor.inl | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.inl b/include/PolyVox/MarchingCubesSurfaceExtractor.inl index ec09a70e..5ec27210 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.inl +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.inl @@ -87,22 +87,15 @@ namespace PolyVox { const uint32_t uXRegSpace = iXVolSpace - m_regSizeInVoxels.getLowerX(); - uint8_t iCubeIndex = 0; - - typename VolumeType::VoxelType v111 = m_sampVolume.peekVoxel0px0py0pz(); - uint8_t iPreviousCubeIndexX = 0; - uint8_t iPreviousCubeIndexY = 0; - uint8_t iPreviousCubeIndexZ = 0; - if (uXRegSpace != 0) // Previous X is available { - //x iPreviousCubeIndexX = pCurrentBitmask(uXRegSpace - 1, uYRegSpace); iPreviousCubeIndexX &= 170; //170 = 128+32+8+2 iPreviousCubeIndexX >>= 1; } + uint8_t iPreviousCubeIndexY = 0; if (uYRegSpace != 0) // Previous Y is available { iPreviousCubeIndexY = pCurrentBitmask(uXRegSpace, uYRegSpace - 1); @@ -110,14 +103,16 @@ namespace PolyVox iPreviousCubeIndexY >>= 2; } + uint8_t iPreviousCubeIndexZ = 0; if (uZRegSpace != 0) // Previous Z is available { iPreviousCubeIndexZ = pPreviousBitmask(uXRegSpace, uYRegSpace); iPreviousCubeIndexZ >>= 4; } + + uint8_t iCubeIndex = iPreviousCubeIndexX | iPreviousCubeIndexY | iPreviousCubeIndexZ; - iCubeIndex = iPreviousCubeIndexX | iPreviousCubeIndexY | iPreviousCubeIndexZ; - + typename VolumeType::VoxelType v111 = m_sampVolume.peekVoxel0px0py0pz(); if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128; if (iCubeIndex != 0) From c8124097e356146e0f5954f695cfe0113c5385bb Mon Sep 17 00:00:00 2001 From: David Williams Date: Sun, 24 May 2015 23:32:52 +0200 Subject: [PATCH 32/61] Using a bit less memory. --- .../PolyVox/MarchingCubesSurfaceExtractor.inl | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.inl b/include/PolyVox/MarchingCubesSurfaceExtractor.inl index 5ec27210..f33e4e2e 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.inl +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.inl @@ -68,10 +68,12 @@ namespace PolyVox memset(pIndicesY.getRawData(), 0xff, pIndicesY.getNoOfElements() * 4); memset(pIndicesZ.getRawData(), 0xff, pIndicesZ.getNoOfElements() * 4); - Array2DUint8 pCurrentBitmask(uArrayWidth, uArrayHeight); - Array2DUint8 pPreviousBitmask(uArrayWidth, uArrayHeight); - memset(pCurrentBitmask.getRawData(), 0x00, pCurrentBitmask.getNoOfElements()); - memset(pPreviousBitmask.getRawData(), 0x00, pPreviousBitmask.getNoOfElements()); + Array2DUint8 pPreviousSliceBitmask(uArrayWidth, uArrayHeight); + Array1DUint8 pPreviousRowBitmask(uArrayWidth); + memset(pPreviousSliceBitmask.getRawData(), 0x00, pPreviousSliceBitmask.getNoOfElements()); + memset(pPreviousRowBitmask.getRawData(), 0x00, pPreviousRowBitmask.getNoOfElements()); + + uint8_t uPreviousCell = 0; for (int32_t iZVolSpace = m_regSizeInVoxels.getLowerZ(); iZVolSpace <= m_regSizeInVoxels.getUpperZ(); iZVolSpace++) { @@ -90,15 +92,15 @@ namespace PolyVox uint8_t iPreviousCubeIndexX = 0; if (uXRegSpace != 0) // Previous X is available { - iPreviousCubeIndexX = pCurrentBitmask(uXRegSpace - 1, uYRegSpace); + iPreviousCubeIndexX = uPreviousCell; iPreviousCubeIndexX &= 170; //170 = 128+32+8+2 iPreviousCubeIndexX >>= 1; - } + } uint8_t iPreviousCubeIndexY = 0; if (uYRegSpace != 0) // Previous Y is available { - iPreviousCubeIndexY = pCurrentBitmask(uXRegSpace, uYRegSpace - 1); + iPreviousCubeIndexY = pPreviousRowBitmask(uXRegSpace); iPreviousCubeIndexY &= 204; //204 = 128+64+8+4 iPreviousCubeIndexY >>= 2; } @@ -106,7 +108,7 @@ namespace PolyVox uint8_t iPreviousCubeIndexZ = 0; if (uZRegSpace != 0) // Previous Z is available { - iPreviousCubeIndexZ = pPreviousBitmask(uXRegSpace, uYRegSpace); + iPreviousCubeIndexZ = pPreviousSliceBitmask(uXRegSpace, uYRegSpace); iPreviousCubeIndexZ >>= 4; } @@ -115,11 +117,9 @@ namespace PolyVox typename VolumeType::VoxelType v111 = m_sampVolume.peekVoxel0px0py0pz(); if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128; - if (iCubeIndex != 0) - { - //Save the bitmask - pCurrentBitmask(uXRegSpace, uYRegSpace) = iCubeIndex; - } + uPreviousCell = iCubeIndex; + pPreviousRowBitmask(uXRegSpace) = iCubeIndex; + pPreviousSliceBitmask(uXRegSpace, uYRegSpace) = iCubeIndex; /* Cube is entirely in/out of the surface */ if (edgeTable[iCubeIndex] != 0) @@ -313,8 +313,8 @@ namespace PolyVox } // For X } // For Y - pPreviousBitmask.swap(pCurrentBitmask); - memset(pCurrentBitmask.getRawData(), 0x00, pCurrentBitmask.getNoOfElements()); + //pPreviousBitmask.swap(pCurrentBitmask); + //memset(pCurrentBitmask.getRawData(), 0x00, pCurrentBitmask.getNoOfElements()); } // For Z } } From f4941fb73c121d3c9f81cddafb1ae065c74bc6dd Mon Sep 17 00:00:00 2001 From: David Williams Date: Sun, 24 May 2015 23:58:51 +0200 Subject: [PATCH 33/61] Minor tweaks. --- include/PolyVox/MarchingCubesSurfaceExtractor.inl | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.inl b/include/PolyVox/MarchingCubesSurfaceExtractor.inl index f33e4e2e..1be34622 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.inl +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.inl @@ -89,12 +89,14 @@ namespace PolyVox { const uint32_t uXRegSpace = iXVolSpace - m_regSizeInVoxels.getLowerX(); + uint8_t iCubeIndex = 0; uint8_t iPreviousCubeIndexX = 0; if (uXRegSpace != 0) // Previous X is available { iPreviousCubeIndexX = uPreviousCell; iPreviousCubeIndexX &= 170; //170 = 128+32+8+2 iPreviousCubeIndexX >>= 1; + iCubeIndex |= iPreviousCubeIndexX; } uint8_t iPreviousCubeIndexY = 0; @@ -103,6 +105,7 @@ namespace PolyVox iPreviousCubeIndexY = pPreviousRowBitmask(uXRegSpace); iPreviousCubeIndexY &= 204; //204 = 128+64+8+4 iPreviousCubeIndexY >>= 2; + iCubeIndex |= iPreviousCubeIndexY; } uint8_t iPreviousCubeIndexZ = 0; @@ -110,9 +113,8 @@ namespace PolyVox { iPreviousCubeIndexZ = pPreviousSliceBitmask(uXRegSpace, uYRegSpace); iPreviousCubeIndexZ >>= 4; + iCubeIndex |= iPreviousCubeIndexZ; } - - uint8_t iCubeIndex = iPreviousCubeIndexX | iPreviousCubeIndexY | iPreviousCubeIndexZ; typename VolumeType::VoxelType v111 = m_sampVolume.peekVoxel0px0py0pz(); if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128; @@ -312,9 +314,6 @@ namespace PolyVox m_sampVolume.movePositiveX(); } // For X } // For Y - - //pPreviousBitmask.swap(pCurrentBitmask); - //memset(pCurrentBitmask.getRawData(), 0x00, pCurrentBitmask.getNoOfElements()); } // For Z } } From ecc06ba986a2f0f7ff5069d4c074bbd4754c21e0 Mon Sep 17 00:00:00 2001 From: David Williams Date: Mon, 25 May 2015 12:05:15 +0200 Subject: [PATCH 34/61] Changed the way samplers are used for a minor speed improvement. --- .../PolyVox/MarchingCubesSurfaceExtractor.h | 1 - .../PolyVox/MarchingCubesSurfaceExtractor.inl | 44 +++++++++++-------- 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.h b/include/PolyVox/MarchingCubesSurfaceExtractor.h index 1a854930..0c7b649e 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.h +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.h @@ -277,7 +277,6 @@ namespace PolyVox //The volume data and a sampler to access it. VolumeType* m_volData; - typename VolumeType::Sampler m_sampVolume; //The surface patch we are currently filling. MeshType* m_meshCurrent; diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.inl b/include/PolyVox/MarchingCubesSurfaceExtractor.inl index 1be34622..be7f77dc 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.inl +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.inl @@ -28,7 +28,6 @@ namespace PolyVox template MarchingCubesSurfaceExtractor::MarchingCubesSurfaceExtractor(VolumeType* volData, Region region, MeshType* result, ControllerType controller) :m_volData(volData) - ,m_sampVolume(volData) ,m_meshCurrent(result) ,m_regSizeInVoxels(region) ,m_controller(controller) @@ -75,15 +74,22 @@ namespace PolyVox uint8_t uPreviousCell = 0; + typename VolumeType::Sampler startOfSlice(m_volData); + startOfSlice.setPosition(m_regSizeInVoxels.getLowerX(), m_regSizeInVoxels.getLowerY(), m_regSizeInVoxels.getLowerZ()); + for (int32_t iZVolSpace = m_regSizeInVoxels.getLowerZ(); iZVolSpace <= m_regSizeInVoxels.getUpperZ(); iZVolSpace++) { const uint32_t uZRegSpace = iZVolSpace - m_regSizeInVoxels.getLowerZ(); + typename VolumeType::Sampler startOfRow = startOfSlice; + for (int32_t iYVolSpace = m_regSizeInVoxels.getLowerY(); iYVolSpace <= m_regSizeInVoxels.getUpperY(); iYVolSpace++) { const uint32_t uYRegSpace = iYVolSpace - m_regSizeInVoxels.getLowerY(); - m_sampVolume.setPosition(m_regSizeInVoxels.getLowerX(), iYVolSpace, iZVolSpace); + // Copying a sampler which is already pointing at the correct location seems (slightly) faster than + // calling setPosition(). Therefore we make use of 'startOfRow' and 'startOfSlice' to reset the sampler. + typename VolumeType::Sampler sampler = startOfRow; for (int32_t iXVolSpace = m_regSizeInVoxels.getLowerX(); iXVolSpace <= m_regSizeInVoxels.getUpperX(); iXVolSpace++) { @@ -116,7 +122,7 @@ namespace PolyVox iCubeIndex |= iPreviousCubeIndexZ; } - typename VolumeType::VoxelType v111 = m_sampVolume.peekVoxel0px0py0pz(); + typename VolumeType::VoxelType v111 = sampler.peekVoxel0px0py0pz(); if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128; uPreviousCell = iCubeIndex; @@ -128,18 +134,18 @@ namespace PolyVox { // These three might not have been sampled, as v111 is the only one we sample every iteration. - typename VolumeType::VoxelType v110 = m_sampVolume.peekVoxel0px0py1nz(); - typename VolumeType::VoxelType v101 = m_sampVolume.peekVoxel0px1ny0pz(); - typename VolumeType::VoxelType v011 = m_sampVolume.peekVoxel1nx0py0pz(); + typename VolumeType::VoxelType v110 = sampler.peekVoxel0px0py1nz(); + typename VolumeType::VoxelType v101 = sampler.peekVoxel0px1ny0pz(); + typename VolumeType::VoxelType v011 = sampler.peekVoxel1nx0py0pz(); - const Vector3DFloat n000 = computeCentralDifferenceGradient(m_sampVolume); + const Vector3DFloat n000 = computeCentralDifferenceGradient(sampler); /* Find the vertices where the surface intersects the cube */ if ((edgeTable[iCubeIndex] & 64) && (uXRegSpace > 0)) { - m_sampVolume.moveNegativeX(); + sampler.moveNegativeX(); POLYVOX_ASSERT(v011 != v111, "Attempting to insert vertex between two voxels with the same value"); - const Vector3DFloat n100 = computeCentralDifferenceGradient(m_sampVolume); + const Vector3DFloat n100 = computeCentralDifferenceGradient(sampler); const float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v011)) / static_cast(m_controller.convertToDensity(v111) - m_controller.convertToDensity(v011)); @@ -166,13 +172,13 @@ namespace PolyVox const uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex); pIndicesX(uXRegSpace, uYRegSpace, uZRegSpace) = uLastVertexIndex; - m_sampVolume.movePositiveX(); + sampler.movePositiveX(); } if ((edgeTable[iCubeIndex] & 32) && (uYRegSpace > 0)) { - m_sampVolume.moveNegativeY(); + sampler.moveNegativeY(); POLYVOX_ASSERT(v101 != v111, "Attempting to insert vertex between two voxels with the same value"); - const Vector3DFloat n010 = computeCentralDifferenceGradient(m_sampVolume); + const Vector3DFloat n010 = computeCentralDifferenceGradient(sampler); const float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v101)) / static_cast(m_controller.convertToDensity(v111) - m_controller.convertToDensity(v101)); @@ -199,13 +205,13 @@ namespace PolyVox uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex); pIndicesY(uXRegSpace, uYRegSpace, uZRegSpace) = uLastVertexIndex; - m_sampVolume.movePositiveY(); + sampler.movePositiveY(); } if ((edgeTable[iCubeIndex] & 1024) && (uZRegSpace > 0)) { - m_sampVolume.moveNegativeZ(); + sampler.moveNegativeZ(); POLYVOX_ASSERT(v110 != v111, "Attempting to insert vertex between two voxels with the same value"); - const Vector3DFloat n001 = computeCentralDifferenceGradient(m_sampVolume); + const Vector3DFloat n001 = computeCentralDifferenceGradient(sampler); const float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v110)) / static_cast(m_controller.convertToDensity(v111) - m_controller.convertToDensity(v110)); @@ -231,7 +237,7 @@ namespace PolyVox const uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex); pIndicesZ(uXRegSpace, uYRegSpace, uZRegSpace) = uLastVertexIndex; - m_sampVolume.movePositiveZ(); + sampler.movePositiveZ(); } // Now output the indices. For the first row, column or slice there aren't @@ -241,7 +247,7 @@ namespace PolyVox int32_t indlist[12]; - m_sampVolume.setPosition(iXVolSpace, iYVolSpace, iZVolSpace); + sampler.setPosition(iXVolSpace, iYVolSpace, iZVolSpace); /* Cube is entirely in/out of the surface */ if (edgeTable[iCubeIndex] != 0) @@ -311,9 +317,11 @@ namespace PolyVox } } } // For each cell - m_sampVolume.movePositiveX(); + sampler.movePositiveX(); } // For X + startOfRow.movePositiveY(); } // For Y + startOfSlice.movePositiveZ(); } // For Z } } From b353cd1ce8d2ec9669ee857549a6f8e882030517 Mon Sep 17 00:00:00 2001 From: David Williams Date: Mon, 25 May 2015 16:39:30 +0200 Subject: [PATCH 35/61] Removed unneeded conditions. --- .../PolyVox/MarchingCubesSurfaceExtractor.inl | 35 +++++++------------ 1 file changed, 12 insertions(+), 23 deletions(-) diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.inl b/include/PolyVox/MarchingCubesSurfaceExtractor.inl index be7f77dc..338ae2f0 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.inl +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.inl @@ -96,31 +96,20 @@ namespace PolyVox const uint32_t uXRegSpace = iXVolSpace - m_regSizeInVoxels.getLowerX(); uint8_t iCubeIndex = 0; - uint8_t iPreviousCubeIndexX = 0; - if (uXRegSpace != 0) // Previous X is available - { - iPreviousCubeIndexX = uPreviousCell; - iPreviousCubeIndexX &= 170; //170 = 128+32+8+2 - iPreviousCubeIndexX >>= 1; - iCubeIndex |= iPreviousCubeIndexX; - } - uint8_t iPreviousCubeIndexY = 0; - if (uYRegSpace != 0) // Previous Y is available - { - iPreviousCubeIndexY = pPreviousRowBitmask(uXRegSpace); - iPreviousCubeIndexY &= 204; //204 = 128+64+8+4 - iPreviousCubeIndexY >>= 2; - iCubeIndex |= iPreviousCubeIndexY; - } + uint8_t iPreviousCubeIndexX = uPreviousCell; + iPreviousCubeIndexX &= 170; //170 = 128+32+8+2 + iPreviousCubeIndexX >>= 1; + iCubeIndex |= iPreviousCubeIndexX; - uint8_t iPreviousCubeIndexZ = 0; - if (uZRegSpace != 0) // Previous Z is available - { - iPreviousCubeIndexZ = pPreviousSliceBitmask(uXRegSpace, uYRegSpace); - iPreviousCubeIndexZ >>= 4; - iCubeIndex |= iPreviousCubeIndexZ; - } + uint8_t iPreviousCubeIndexY = pPreviousRowBitmask(uXRegSpace); + iPreviousCubeIndexY &= 204; //204 = 128+64+8+4 + iPreviousCubeIndexY >>= 2; + iCubeIndex |= iPreviousCubeIndexY; + + uint8_t iPreviousCubeIndexZ = pPreviousSliceBitmask(uXRegSpace, uYRegSpace); + iPreviousCubeIndexZ >>= 4; + iCubeIndex |= iPreviousCubeIndexZ; typename VolumeType::VoxelType v111 = sampler.peekVoxel0px0py0pz(); if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128; From e0ce93acb1f5e8e05a954789135b75347bd54017 Mon Sep 17 00:00:00 2001 From: David Williams Date: Mon, 25 May 2015 16:45:52 +0200 Subject: [PATCH 36/61] Added comments. --- .../PolyVox/MarchingCubesSurfaceExtractor.inl | 25 +++++++++++++------ 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.inl b/include/PolyVox/MarchingCubesSurfaceExtractor.inl index 338ae2f0..1d75e73f 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.inl +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.inl @@ -97,23 +97,32 @@ namespace PolyVox uint8_t iCubeIndex = 0; - uint8_t iPreviousCubeIndexX = uPreviousCell; - iPreviousCubeIndexX &= 170; //170 = 128+32+8+2 - iPreviousCubeIndexX >>= 1; - iCubeIndex |= iPreviousCubeIndexX; + // Four bits of our cube index are obtained by looking at the cube index for + // the previous slice and copying four of those bits into their new positions. + uint8_t iPreviousCubeIndexZ = pPreviousSliceBitmask(uXRegSpace, uYRegSpace); + iPreviousCubeIndexZ >>= 4; + iCubeIndex |= iPreviousCubeIndexZ; + // Two bits of our cube index are obtained by looking at the cube index for + // the previous row and copying two of those bits into their new positions. uint8_t iPreviousCubeIndexY = pPreviousRowBitmask(uXRegSpace); iPreviousCubeIndexY &= 204; //204 = 128+64+8+4 iPreviousCubeIndexY >>= 2; iCubeIndex |= iPreviousCubeIndexY; - uint8_t iPreviousCubeIndexZ = pPreviousSliceBitmask(uXRegSpace, uYRegSpace); - iPreviousCubeIndexZ >>= 4; - iCubeIndex |= iPreviousCubeIndexZ; + // One bit of our cube index are obtained by looking at the cube index for + // the previous cell and copying one of those bits into it's new position. + uint8_t iPreviousCubeIndexX = uPreviousCell; + iPreviousCubeIndexX &= 170; //170 = 128+32+8+2 + iPreviousCubeIndexX >>= 1; + iCubeIndex |= iPreviousCubeIndexX; - typename VolumeType::VoxelType v111 = sampler.peekVoxel0px0py0pz(); + // The last bit of our cube index is obtained by looking + // at the relevant voxel and comparing it to the threshold + typename VolumeType::VoxelType v111 = sampler.getVoxel(); if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128; + // The current value becomes the previous value, ready for the next iteration. uPreviousCell = iCubeIndex; pPreviousRowBitmask(uXRegSpace) = iCubeIndex; pPreviousSliceBitmask(uXRegSpace, uYRegSpace) = iCubeIndex; From 13be35aac906ee34448c3160372db4dcb031022f Mon Sep 17 00:00:00 2001 From: David Williams Date: Mon, 25 May 2015 17:37:30 +0200 Subject: [PATCH 37/61] Rather ugly split of some code into a separate function, to keep the main loop as small and simple as possible. To be tidied up shortly. --- .../PolyVox/MarchingCubesSurfaceExtractor.h | 2 +- .../PolyVox/MarchingCubesSurfaceExtractor.inl | 392 +++++++++--------- 2 files changed, 197 insertions(+), 197 deletions(-) diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.h b/include/PolyVox/MarchingCubesSurfaceExtractor.h index 0c7b649e..6a8981f2 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.h +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.h @@ -159,7 +159,7 @@ namespace PolyVox private: //Compute the cell bitmask for a particular slice in z. - void computeBitmaskForSlice(); + void generateMeshForCell(uint32_t uXRegSpace, uint32_t uYRegSpace, uint32_t uZRegSpace, typename VolumeType::Sampler& sampler, typename VolumeType::VoxelType v111, uint8_t iCubeIndex, Array3DInt32& pIndicesX, Array3DInt32& pIndicesY, Array3DInt32& pIndicesZ, int32_t iXVolSpace, int32_t iYVolSpace, int32_t iZVolSpace); //////////////////////////////////////////////////////////////////////////////// // NOTE: These two functions are in the .h file rather than the .inl due to an apparent bug in VC2010. diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.inl b/include/PolyVox/MarchingCubesSurfaceExtractor.inl index 1d75e73f..55cbcfd6 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.inl +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.inl @@ -42,18 +42,6 @@ namespace PolyVox Timer timer; m_meshCurrent->clear(); - computeBitmaskForSlice(); - - m_meshCurrent->setOffset(m_regSizeInVoxels.getLowerCorner()); - - POLYVOX_LOG_TRACE("Marching cubes surface extraction took ", timer.elapsedTimeInMilliSeconds(), - "ms (Region size = ", m_regSizeInVoxels.getWidthInVoxels(), "x", m_regSizeInVoxels.getHeightInVoxels(), - "x", m_regSizeInVoxels.getDepthInVoxels(), ")"); - } - - template - void MarchingCubesSurfaceExtractor::computeBitmaskForSlice() - { const uint32_t uArrayWidth = m_regSizeInVoxels.getUpperX() - m_regSizeInVoxels.getLowerX() + 2; const uint32_t uArrayHeight = m_regSizeInVoxels.getUpperY() - m_regSizeInVoxels.getLowerY() + 2; const uint32_t uArrayDepth = m_regSizeInVoxels.getUpperZ() - m_regSizeInVoxels.getLowerZ() + 2; @@ -130,196 +118,208 @@ namespace PolyVox /* Cube is entirely in/out of the surface */ if (edgeTable[iCubeIndex] != 0) { + generateMeshForCell(uXRegSpace, uYRegSpace, uZRegSpace, sampler, v111, iCubeIndex, pIndicesX, pIndicesY, pIndicesZ, iXVolSpace, iYVolSpace, iZVolSpace); + } - // These three might not have been sampled, as v111 is the only one we sample every iteration. - typename VolumeType::VoxelType v110 = sampler.peekVoxel0px0py1nz(); - typename VolumeType::VoxelType v101 = sampler.peekVoxel0px1ny0pz(); - typename VolumeType::VoxelType v011 = sampler.peekVoxel1nx0py0pz(); - - const Vector3DFloat n000 = computeCentralDifferenceGradient(sampler); - - /* Find the vertices where the surface intersects the cube */ - if ((edgeTable[iCubeIndex] & 64) && (uXRegSpace > 0)) - { - sampler.moveNegativeX(); - POLYVOX_ASSERT(v011 != v111, "Attempting to insert vertex between two voxels with the same value"); - const Vector3DFloat n100 = computeCentralDifferenceGradient(sampler); - - const float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v011)) / static_cast(m_controller.convertToDensity(v111) - m_controller.convertToDensity(v011)); - - const Vector3DFloat v3dPosition(static_cast(uXRegSpace - 1) + fInterp, static_cast(uYRegSpace), static_cast(uZRegSpace)); - const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); - - Vector3DFloat v3dNormal = (n100*fInterp) + (n000*(1 - fInterp)); - - // The gradient for a voxel can be zero (e.g. solid voxel surrounded by empty ones) and so - // the interpolated normal can also be zero (e.g. a grid of alternating solid and empty voxels). - if (v3dNormal.lengthSquared() > 0.000001f) - { - v3dNormal.normalise(); - } - - // Allow the controller to decide how the material should be derived from the voxels. - const typename VolumeType::VoxelType uMaterial = m_controller.blendMaterials(v011, v111, fInterp); - - MarchingCubesVertex surfaceVertex; - surfaceVertex.encodedPosition = v3dScaledPosition; - surfaceVertex.encodedNormal = encodeNormal(v3dNormal); - surfaceVertex.data = uMaterial; - - const uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex); - pIndicesX(uXRegSpace, uYRegSpace, uZRegSpace) = uLastVertexIndex; - - sampler.movePositiveX(); - } - if ((edgeTable[iCubeIndex] & 32) && (uYRegSpace > 0)) - { - sampler.moveNegativeY(); - POLYVOX_ASSERT(v101 != v111, "Attempting to insert vertex between two voxels with the same value"); - const Vector3DFloat n010 = computeCentralDifferenceGradient(sampler); - - const float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v101)) / static_cast(m_controller.convertToDensity(v111) - m_controller.convertToDensity(v101)); - - const Vector3DFloat v3dPosition(static_cast(uXRegSpace), static_cast(uYRegSpace - 1) + fInterp, static_cast(uZRegSpace)); - const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); - - Vector3DFloat v3dNormal = (n010*fInterp) + (n000*(1 - fInterp)); - - // The gradient for a voxel can be zero (e.g. solid voxel surrounded by empty ones) and so - // the interpolated normal can also be zero (e.g. a grid of alternating solid and empty voxels). - if (v3dNormal.lengthSquared() > 0.000001f) - { - v3dNormal.normalise(); - } - - // Allow the controller to decide how the material should be derived from the voxels. - const typename VolumeType::VoxelType uMaterial = m_controller.blendMaterials(v101, v111, fInterp); - - MarchingCubesVertex surfaceVertex; - surfaceVertex.encodedPosition = v3dScaledPosition; - surfaceVertex.encodedNormal = encodeNormal(v3dNormal); - surfaceVertex.data = uMaterial; - - uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex); - pIndicesY(uXRegSpace, uYRegSpace, uZRegSpace) = uLastVertexIndex; - - sampler.movePositiveY(); - } - if ((edgeTable[iCubeIndex] & 1024) && (uZRegSpace > 0)) - { - sampler.moveNegativeZ(); - POLYVOX_ASSERT(v110 != v111, "Attempting to insert vertex between two voxels with the same value"); - const Vector3DFloat n001 = computeCentralDifferenceGradient(sampler); - - const float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v110)) / static_cast(m_controller.convertToDensity(v111) - m_controller.convertToDensity(v110)); - - const Vector3DFloat v3dPosition(static_cast(uXRegSpace), static_cast(uYRegSpace), static_cast(uZRegSpace - 1) + fInterp); - const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); - - Vector3DFloat v3dNormal = (n001*fInterp) + (n000*(1 - fInterp)); - // The gradient for a voxel can be zero (e.g. solid voxel surrounded by empty ones) and so - // the interpolated normal can also be zero (e.g. a grid of alternating solid and empty voxels). - if (v3dNormal.lengthSquared() > 0.000001f) - { - v3dNormal.normalise(); - } - - // Allow the controller to decide how the material should be derived from the voxels. - const typename VolumeType::VoxelType uMaterial = m_controller.blendMaterials(v110, v111, fInterp); - - MarchingCubesVertex surfaceVertex; - surfaceVertex.encodedPosition = v3dScaledPosition; - surfaceVertex.encodedNormal = encodeNormal(v3dNormal); - surfaceVertex.data = uMaterial; - - const uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex); - pIndicesZ(uXRegSpace, uYRegSpace, uZRegSpace) = uLastVertexIndex; - - sampler.movePositiveZ(); - } - - // Now output the indices. For the first row, column or slice there aren't - // any (the region size in cells is one less than the region size in voxels) - if ((uXRegSpace != 0) && (uYRegSpace != 0) && (uZRegSpace != 0)) - { - - int32_t indlist[12]; - - sampler.setPosition(iXVolSpace, iYVolSpace, iZVolSpace); - - /* Cube is entirely in/out of the surface */ - if (edgeTable[iCubeIndex] != 0) - { - - /* Find the vertices where the surface intersects the cube */ - if (edgeTable[iCubeIndex] & 1) - { - indlist[0] = pIndicesX(uXRegSpace, uYRegSpace - 1, uZRegSpace - 1); - } - if (edgeTable[iCubeIndex] & 2) - { - indlist[1] = pIndicesY(uXRegSpace, uYRegSpace, uZRegSpace - 1); - } - if (edgeTable[iCubeIndex] & 4) - { - indlist[2] = pIndicesX(uXRegSpace, uYRegSpace, uZRegSpace - 1); - } - if (edgeTable[iCubeIndex] & 8) - { - indlist[3] = pIndicesY(uXRegSpace - 1, uYRegSpace, uZRegSpace - 1); - } - if (edgeTable[iCubeIndex] & 16) - { - indlist[4] = pIndicesX(uXRegSpace, uYRegSpace - 1, uZRegSpace); - } - if (edgeTable[iCubeIndex] & 32) - { - indlist[5] = pIndicesY(uXRegSpace, uYRegSpace, uZRegSpace); - } - if (edgeTable[iCubeIndex] & 64) - { - indlist[6] = pIndicesX(uXRegSpace, uYRegSpace, uZRegSpace); - } - if (edgeTable[iCubeIndex] & 128) - { - indlist[7] = pIndicesY(uXRegSpace - 1, uYRegSpace, uZRegSpace); - } - if (edgeTable[iCubeIndex] & 256) - { - indlist[8] = pIndicesZ(uXRegSpace - 1, uYRegSpace - 1, uZRegSpace); - } - if (edgeTable[iCubeIndex] & 512) - { - indlist[9] = pIndicesZ(uXRegSpace, uYRegSpace - 1, uZRegSpace); - } - if (edgeTable[iCubeIndex] & 1024) - { - indlist[10] = pIndicesZ(uXRegSpace, uYRegSpace, uZRegSpace); - } - if (edgeTable[iCubeIndex] & 2048) - { - indlist[11] = pIndicesZ(uXRegSpace - 1, uYRegSpace, uZRegSpace); - } - - for (int i = 0; triTable[iCubeIndex][i] != -1; i += 3) - { - const int32_t ind0 = indlist[triTable[iCubeIndex][i]]; - const int32_t ind1 = indlist[triTable[iCubeIndex][i + 1]]; - const int32_t ind2 = indlist[triTable[iCubeIndex][i + 2]]; - - if ((ind0 != -1) && (ind1 != -1) && (ind2 != -1)) - { - m_meshCurrent->addTriangle(ind0, ind1, ind2); - } - } // For each triangle - } - } - } // For each cell sampler.movePositiveX(); } // For X startOfRow.movePositiveY(); } // For Y startOfSlice.movePositiveZ(); } // For Z + + m_meshCurrent->setOffset(m_regSizeInVoxels.getLowerCorner()); + + POLYVOX_LOG_TRACE("Marching cubes surface extraction took ", timer.elapsedTimeInMilliSeconds(), + "ms (Region size = ", m_regSizeInVoxels.getWidthInVoxels(), "x", m_regSizeInVoxels.getHeightInVoxels(), + "x", m_regSizeInVoxels.getDepthInVoxels(), ")"); + } + + template + void MarchingCubesSurfaceExtractor::generateMeshForCell(uint32_t uXRegSpace, uint32_t uYRegSpace, uint32_t uZRegSpace, typename VolumeType::Sampler& sampler, typename VolumeType::VoxelType v111, uint8_t iCubeIndex, Array3DInt32& pIndicesX, Array3DInt32& pIndicesY, Array3DInt32& pIndicesZ, int32_t iXVolSpace, int32_t iYVolSpace, int32_t iZVolSpace) + { + // These three might not have been sampled, as v111 is the only one we sample every iteration. + typename VolumeType::VoxelType v110 = sampler.peekVoxel0px0py1nz(); + typename VolumeType::VoxelType v101 = sampler.peekVoxel0px1ny0pz(); + typename VolumeType::VoxelType v011 = sampler.peekVoxel1nx0py0pz(); + + const Vector3DFloat n000 = computeCentralDifferenceGradient(sampler); + + /* Find the vertices where the surface intersects the cube */ + if ((edgeTable[iCubeIndex] & 64) && (uXRegSpace > 0)) + { + sampler.moveNegativeX(); + POLYVOX_ASSERT(v011 != v111, "Attempting to insert vertex between two voxels with the same value"); + const Vector3DFloat n100 = computeCentralDifferenceGradient(sampler); + + const float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v011)) / static_cast(m_controller.convertToDensity(v111) - m_controller.convertToDensity(v011)); + + const Vector3DFloat v3dPosition(static_cast(uXRegSpace - 1) + fInterp, static_cast(uYRegSpace), static_cast(uZRegSpace)); + const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); + + Vector3DFloat v3dNormal = (n100*fInterp) + (n000*(1 - fInterp)); + + // The gradient for a voxel can be zero (e.g. solid voxel surrounded by empty ones) and so + // the interpolated normal can also be zero (e.g. a grid of alternating solid and empty voxels). + if (v3dNormal.lengthSquared() > 0.000001f) + { + v3dNormal.normalise(); + } + + // Allow the controller to decide how the material should be derived from the voxels. + const typename VolumeType::VoxelType uMaterial = m_controller.blendMaterials(v011, v111, fInterp); + + MarchingCubesVertex surfaceVertex; + surfaceVertex.encodedPosition = v3dScaledPosition; + surfaceVertex.encodedNormal = encodeNormal(v3dNormal); + surfaceVertex.data = uMaterial; + + const uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex); + pIndicesX(uXRegSpace, uYRegSpace, uZRegSpace) = uLastVertexIndex; + + sampler.movePositiveX(); + } + if ((edgeTable[iCubeIndex] & 32) && (uYRegSpace > 0)) + { + sampler.moveNegativeY(); + POLYVOX_ASSERT(v101 != v111, "Attempting to insert vertex between two voxels with the same value"); + const Vector3DFloat n010 = computeCentralDifferenceGradient(sampler); + + const float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v101)) / static_cast(m_controller.convertToDensity(v111) - m_controller.convertToDensity(v101)); + + const Vector3DFloat v3dPosition(static_cast(uXRegSpace), static_cast(uYRegSpace - 1) + fInterp, static_cast(uZRegSpace)); + const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); + + Vector3DFloat v3dNormal = (n010*fInterp) + (n000*(1 - fInterp)); + + // The gradient for a voxel can be zero (e.g. solid voxel surrounded by empty ones) and so + // the interpolated normal can also be zero (e.g. a grid of alternating solid and empty voxels). + if (v3dNormal.lengthSquared() > 0.000001f) + { + v3dNormal.normalise(); + } + + // Allow the controller to decide how the material should be derived from the voxels. + const typename VolumeType::VoxelType uMaterial = m_controller.blendMaterials(v101, v111, fInterp); + + MarchingCubesVertex surfaceVertex; + surfaceVertex.encodedPosition = v3dScaledPosition; + surfaceVertex.encodedNormal = encodeNormal(v3dNormal); + surfaceVertex.data = uMaterial; + + uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex); + pIndicesY(uXRegSpace, uYRegSpace, uZRegSpace) = uLastVertexIndex; + + sampler.movePositiveY(); + } + if ((edgeTable[iCubeIndex] & 1024) && (uZRegSpace > 0)) + { + sampler.moveNegativeZ(); + POLYVOX_ASSERT(v110 != v111, "Attempting to insert vertex between two voxels with the same value"); + const Vector3DFloat n001 = computeCentralDifferenceGradient(sampler); + + const float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v110)) / static_cast(m_controller.convertToDensity(v111) - m_controller.convertToDensity(v110)); + + const Vector3DFloat v3dPosition(static_cast(uXRegSpace), static_cast(uYRegSpace), static_cast(uZRegSpace - 1) + fInterp); + const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); + + Vector3DFloat v3dNormal = (n001*fInterp) + (n000*(1 - fInterp)); + // The gradient for a voxel can be zero (e.g. solid voxel surrounded by empty ones) and so + // the interpolated normal can also be zero (e.g. a grid of alternating solid and empty voxels). + if (v3dNormal.lengthSquared() > 0.000001f) + { + v3dNormal.normalise(); + } + + // Allow the controller to decide how the material should be derived from the voxels. + const typename VolumeType::VoxelType uMaterial = m_controller.blendMaterials(v110, v111, fInterp); + + MarchingCubesVertex surfaceVertex; + surfaceVertex.encodedPosition = v3dScaledPosition; + surfaceVertex.encodedNormal = encodeNormal(v3dNormal); + surfaceVertex.data = uMaterial; + + const uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex); + pIndicesZ(uXRegSpace, uYRegSpace, uZRegSpace) = uLastVertexIndex; + + sampler.movePositiveZ(); + } + + // Now output the indices. For the first row, column or slice there aren't + // any (the region size in cells is one less than the region size in voxels) + if ((uXRegSpace != 0) && (uYRegSpace != 0) && (uZRegSpace != 0)) + { + + int32_t indlist[12]; + + sampler.setPosition(iXVolSpace, iYVolSpace, iZVolSpace); + + /* Cube is entirely in/out of the surface */ + if (edgeTable[iCubeIndex] != 0) + { + + /* Find the vertices where the surface intersects the cube */ + if (edgeTable[iCubeIndex] & 1) + { + indlist[0] = pIndicesX(uXRegSpace, uYRegSpace - 1, uZRegSpace - 1); + } + if (edgeTable[iCubeIndex] & 2) + { + indlist[1] = pIndicesY(uXRegSpace, uYRegSpace, uZRegSpace - 1); + } + if (edgeTable[iCubeIndex] & 4) + { + indlist[2] = pIndicesX(uXRegSpace, uYRegSpace, uZRegSpace - 1); + } + if (edgeTable[iCubeIndex] & 8) + { + indlist[3] = pIndicesY(uXRegSpace - 1, uYRegSpace, uZRegSpace - 1); + } + if (edgeTable[iCubeIndex] & 16) + { + indlist[4] = pIndicesX(uXRegSpace, uYRegSpace - 1, uZRegSpace); + } + if (edgeTable[iCubeIndex] & 32) + { + indlist[5] = pIndicesY(uXRegSpace, uYRegSpace, uZRegSpace); + } + if (edgeTable[iCubeIndex] & 64) + { + indlist[6] = pIndicesX(uXRegSpace, uYRegSpace, uZRegSpace); + } + if (edgeTable[iCubeIndex] & 128) + { + indlist[7] = pIndicesY(uXRegSpace - 1, uYRegSpace, uZRegSpace); + } + if (edgeTable[iCubeIndex] & 256) + { + indlist[8] = pIndicesZ(uXRegSpace - 1, uYRegSpace - 1, uZRegSpace); + } + if (edgeTable[iCubeIndex] & 512) + { + indlist[9] = pIndicesZ(uXRegSpace, uYRegSpace - 1, uZRegSpace); + } + if (edgeTable[iCubeIndex] & 1024) + { + indlist[10] = pIndicesZ(uXRegSpace, uYRegSpace, uZRegSpace); + } + if (edgeTable[iCubeIndex] & 2048) + { + indlist[11] = pIndicesZ(uXRegSpace - 1, uYRegSpace, uZRegSpace); + } + + for (int i = 0; triTable[iCubeIndex][i] != -1; i += 3) + { + const int32_t ind0 = indlist[triTable[iCubeIndex][i]]; + const int32_t ind1 = indlist[triTable[iCubeIndex][i + 1]]; + const int32_t ind2 = indlist[triTable[iCubeIndex][i + 2]]; + + if ((ind0 != -1) && (ind1 != -1) && (ind2 != -1)) + { + m_meshCurrent->addTriangle(ind0, ind1, ind2); + } + } // For each triangle + } + } } } From 96ec47a972fea2cd6efcaddd276728f8062d8f7b Mon Sep 17 00:00:00 2001 From: David Williams Date: Mon, 25 May 2015 17:45:40 +0200 Subject: [PATCH 38/61] Eliminated member variable. --- include/PolyVox/MarchingCubesSurfaceExtractor.h | 3 --- include/PolyVox/MarchingCubesSurfaceExtractor.inl | 13 ++++++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.h b/include/PolyVox/MarchingCubesSurfaceExtractor.h index 6a8981f2..ad1d2313 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.h +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.h @@ -286,9 +286,6 @@ namespace PolyVox //Used to convert arbitrary voxel types in densities and materials. ControllerType m_controller; - - //Our threshold value - typename ControllerType::DensityType m_tThreshold; }; // This version of the function performs the extraction into a user-provided mesh rather than allocating a mesh automatically. diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.inl b/include/PolyVox/MarchingCubesSurfaceExtractor.inl index 55cbcfd6..8b40c03c 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.inl +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.inl @@ -31,7 +31,6 @@ namespace PolyVox ,m_meshCurrent(result) ,m_regSizeInVoxels(region) ,m_controller(controller) - ,m_tThreshold(m_controller.getThreshold()) { POLYVOX_THROW_IF(m_meshCurrent == nullptr, std::invalid_argument, "Provided mesh cannot be null"); } @@ -62,6 +61,8 @@ namespace PolyVox uint8_t uPreviousCell = 0; + typename ControllerType::DensityType tThreshold = m_controller.getThreshold(); + typename VolumeType::Sampler startOfSlice(m_volData); startOfSlice.setPosition(m_regSizeInVoxels.getLowerX(), m_regSizeInVoxels.getLowerY(), m_regSizeInVoxels.getLowerZ()); @@ -108,7 +109,7 @@ namespace PolyVox // The last bit of our cube index is obtained by looking // at the relevant voxel and comparing it to the threshold typename VolumeType::VoxelType v111 = sampler.getVoxel(); - if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128; + if (m_controller.convertToDensity(v111) < tThreshold) iCubeIndex |= 128; // The current value becomes the previous value, ready for the next iteration. uPreviousCell = iCubeIndex; @@ -145,6 +146,8 @@ namespace PolyVox const Vector3DFloat n000 = computeCentralDifferenceGradient(sampler); + typename ControllerType::DensityType tThreshold = m_controller.getThreshold(); + /* Find the vertices where the surface intersects the cube */ if ((edgeTable[iCubeIndex] & 64) && (uXRegSpace > 0)) { @@ -152,7 +155,7 @@ namespace PolyVox POLYVOX_ASSERT(v011 != v111, "Attempting to insert vertex between two voxels with the same value"); const Vector3DFloat n100 = computeCentralDifferenceGradient(sampler); - const float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v011)) / static_cast(m_controller.convertToDensity(v111) - m_controller.convertToDensity(v011)); + const float fInterp = static_cast(tThreshold - m_controller.convertToDensity(v011)) / static_cast(m_controller.convertToDensity(v111) - m_controller.convertToDensity(v011)); const Vector3DFloat v3dPosition(static_cast(uXRegSpace - 1) + fInterp, static_cast(uYRegSpace), static_cast(uZRegSpace)); const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); @@ -185,7 +188,7 @@ namespace PolyVox POLYVOX_ASSERT(v101 != v111, "Attempting to insert vertex between two voxels with the same value"); const Vector3DFloat n010 = computeCentralDifferenceGradient(sampler); - const float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v101)) / static_cast(m_controller.convertToDensity(v111) - m_controller.convertToDensity(v101)); + const float fInterp = static_cast(tThreshold - m_controller.convertToDensity(v101)) / static_cast(m_controller.convertToDensity(v111) - m_controller.convertToDensity(v101)); const Vector3DFloat v3dPosition(static_cast(uXRegSpace), static_cast(uYRegSpace - 1) + fInterp, static_cast(uZRegSpace)); const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); @@ -218,7 +221,7 @@ namespace PolyVox POLYVOX_ASSERT(v110 != v111, "Attempting to insert vertex between two voxels with the same value"); const Vector3DFloat n001 = computeCentralDifferenceGradient(sampler); - const float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v110)) / static_cast(m_controller.convertToDensity(v111) - m_controller.convertToDensity(v110)); + const float fInterp = static_cast(tThreshold - m_controller.convertToDensity(v110)) / static_cast(m_controller.convertToDensity(v111) - m_controller.convertToDensity(v110)); const Vector3DFloat v3dPosition(static_cast(uXRegSpace), static_cast(uYRegSpace), static_cast(uZRegSpace - 1) + fInterp); const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); From c384fbfea8c9454babef2280dc17c466ecf828e3 Mon Sep 17 00:00:00 2001 From: David Williams Date: Mon, 25 May 2015 20:35:47 +0200 Subject: [PATCH 39/61] Revert "Eliminated member variable." This reverts commit 96ec47a972fea2cd6efcaddd276728f8062d8f7b. --- include/PolyVox/MarchingCubesSurfaceExtractor.h | 3 +++ include/PolyVox/MarchingCubesSurfaceExtractor.inl | 13 +++++-------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.h b/include/PolyVox/MarchingCubesSurfaceExtractor.h index ad1d2313..6a8981f2 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.h +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.h @@ -286,6 +286,9 @@ namespace PolyVox //Used to convert arbitrary voxel types in densities and materials. ControllerType m_controller; + + //Our threshold value + typename ControllerType::DensityType m_tThreshold; }; // This version of the function performs the extraction into a user-provided mesh rather than allocating a mesh automatically. diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.inl b/include/PolyVox/MarchingCubesSurfaceExtractor.inl index 8b40c03c..55cbcfd6 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.inl +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.inl @@ -31,6 +31,7 @@ namespace PolyVox ,m_meshCurrent(result) ,m_regSizeInVoxels(region) ,m_controller(controller) + ,m_tThreshold(m_controller.getThreshold()) { POLYVOX_THROW_IF(m_meshCurrent == nullptr, std::invalid_argument, "Provided mesh cannot be null"); } @@ -61,8 +62,6 @@ namespace PolyVox uint8_t uPreviousCell = 0; - typename ControllerType::DensityType tThreshold = m_controller.getThreshold(); - typename VolumeType::Sampler startOfSlice(m_volData); startOfSlice.setPosition(m_regSizeInVoxels.getLowerX(), m_regSizeInVoxels.getLowerY(), m_regSizeInVoxels.getLowerZ()); @@ -109,7 +108,7 @@ namespace PolyVox // The last bit of our cube index is obtained by looking // at the relevant voxel and comparing it to the threshold typename VolumeType::VoxelType v111 = sampler.getVoxel(); - if (m_controller.convertToDensity(v111) < tThreshold) iCubeIndex |= 128; + if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128; // The current value becomes the previous value, ready for the next iteration. uPreviousCell = iCubeIndex; @@ -146,8 +145,6 @@ namespace PolyVox const Vector3DFloat n000 = computeCentralDifferenceGradient(sampler); - typename ControllerType::DensityType tThreshold = m_controller.getThreshold(); - /* Find the vertices where the surface intersects the cube */ if ((edgeTable[iCubeIndex] & 64) && (uXRegSpace > 0)) { @@ -155,7 +152,7 @@ namespace PolyVox POLYVOX_ASSERT(v011 != v111, "Attempting to insert vertex between two voxels with the same value"); const Vector3DFloat n100 = computeCentralDifferenceGradient(sampler); - const float fInterp = static_cast(tThreshold - m_controller.convertToDensity(v011)) / static_cast(m_controller.convertToDensity(v111) - m_controller.convertToDensity(v011)); + const float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v011)) / static_cast(m_controller.convertToDensity(v111) - m_controller.convertToDensity(v011)); const Vector3DFloat v3dPosition(static_cast(uXRegSpace - 1) + fInterp, static_cast(uYRegSpace), static_cast(uZRegSpace)); const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); @@ -188,7 +185,7 @@ namespace PolyVox POLYVOX_ASSERT(v101 != v111, "Attempting to insert vertex between two voxels with the same value"); const Vector3DFloat n010 = computeCentralDifferenceGradient(sampler); - const float fInterp = static_cast(tThreshold - m_controller.convertToDensity(v101)) / static_cast(m_controller.convertToDensity(v111) - m_controller.convertToDensity(v101)); + const float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v101)) / static_cast(m_controller.convertToDensity(v111) - m_controller.convertToDensity(v101)); const Vector3DFloat v3dPosition(static_cast(uXRegSpace), static_cast(uYRegSpace - 1) + fInterp, static_cast(uZRegSpace)); const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); @@ -221,7 +218,7 @@ namespace PolyVox POLYVOX_ASSERT(v110 != v111, "Attempting to insert vertex between two voxels with the same value"); const Vector3DFloat n001 = computeCentralDifferenceGradient(sampler); - const float fInterp = static_cast(tThreshold - m_controller.convertToDensity(v110)) / static_cast(m_controller.convertToDensity(v111) - m_controller.convertToDensity(v110)); + const float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v110)) / static_cast(m_controller.convertToDensity(v111) - m_controller.convertToDensity(v110)); const Vector3DFloat v3dPosition(static_cast(uXRegSpace), static_cast(uYRegSpace), static_cast(uZRegSpace - 1) + fInterp); const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); From 1d51ee8d0a6bc1383a435ee7fb99adcdecf4d0d2 Mon Sep 17 00:00:00 2001 From: David Williams Date: Mon, 25 May 2015 20:35:55 +0200 Subject: [PATCH 40/61] Revert "Rather ugly split of some code into a separate function, to keep the main loop as small and simple as possible. To be tidied up shortly." This reverts commit 13be35aac906ee34448c3160372db4dcb031022f. --- .../PolyVox/MarchingCubesSurfaceExtractor.h | 2 +- .../PolyVox/MarchingCubesSurfaceExtractor.inl | 392 +++++++++--------- 2 files changed, 197 insertions(+), 197 deletions(-) diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.h b/include/PolyVox/MarchingCubesSurfaceExtractor.h index 6a8981f2..0c7b649e 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.h +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.h @@ -159,7 +159,7 @@ namespace PolyVox private: //Compute the cell bitmask for a particular slice in z. - void generateMeshForCell(uint32_t uXRegSpace, uint32_t uYRegSpace, uint32_t uZRegSpace, typename VolumeType::Sampler& sampler, typename VolumeType::VoxelType v111, uint8_t iCubeIndex, Array3DInt32& pIndicesX, Array3DInt32& pIndicesY, Array3DInt32& pIndicesZ, int32_t iXVolSpace, int32_t iYVolSpace, int32_t iZVolSpace); + void computeBitmaskForSlice(); //////////////////////////////////////////////////////////////////////////////// // NOTE: These two functions are in the .h file rather than the .inl due to an apparent bug in VC2010. diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.inl b/include/PolyVox/MarchingCubesSurfaceExtractor.inl index 55cbcfd6..1d75e73f 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.inl +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.inl @@ -42,6 +42,18 @@ namespace PolyVox Timer timer; m_meshCurrent->clear(); + computeBitmaskForSlice(); + + m_meshCurrent->setOffset(m_regSizeInVoxels.getLowerCorner()); + + POLYVOX_LOG_TRACE("Marching cubes surface extraction took ", timer.elapsedTimeInMilliSeconds(), + "ms (Region size = ", m_regSizeInVoxels.getWidthInVoxels(), "x", m_regSizeInVoxels.getHeightInVoxels(), + "x", m_regSizeInVoxels.getDepthInVoxels(), ")"); + } + + template + void MarchingCubesSurfaceExtractor::computeBitmaskForSlice() + { const uint32_t uArrayWidth = m_regSizeInVoxels.getUpperX() - m_regSizeInVoxels.getLowerX() + 2; const uint32_t uArrayHeight = m_regSizeInVoxels.getUpperY() - m_regSizeInVoxels.getLowerY() + 2; const uint32_t uArrayDepth = m_regSizeInVoxels.getUpperZ() - m_regSizeInVoxels.getLowerZ() + 2; @@ -118,208 +130,196 @@ namespace PolyVox /* Cube is entirely in/out of the surface */ if (edgeTable[iCubeIndex] != 0) { - generateMeshForCell(uXRegSpace, uYRegSpace, uZRegSpace, sampler, v111, iCubeIndex, pIndicesX, pIndicesY, pIndicesZ, iXVolSpace, iYVolSpace, iZVolSpace); - } + // These three might not have been sampled, as v111 is the only one we sample every iteration. + typename VolumeType::VoxelType v110 = sampler.peekVoxel0px0py1nz(); + typename VolumeType::VoxelType v101 = sampler.peekVoxel0px1ny0pz(); + typename VolumeType::VoxelType v011 = sampler.peekVoxel1nx0py0pz(); + + const Vector3DFloat n000 = computeCentralDifferenceGradient(sampler); + + /* Find the vertices where the surface intersects the cube */ + if ((edgeTable[iCubeIndex] & 64) && (uXRegSpace > 0)) + { + sampler.moveNegativeX(); + POLYVOX_ASSERT(v011 != v111, "Attempting to insert vertex between two voxels with the same value"); + const Vector3DFloat n100 = computeCentralDifferenceGradient(sampler); + + const float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v011)) / static_cast(m_controller.convertToDensity(v111) - m_controller.convertToDensity(v011)); + + const Vector3DFloat v3dPosition(static_cast(uXRegSpace - 1) + fInterp, static_cast(uYRegSpace), static_cast(uZRegSpace)); + const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); + + Vector3DFloat v3dNormal = (n100*fInterp) + (n000*(1 - fInterp)); + + // The gradient for a voxel can be zero (e.g. solid voxel surrounded by empty ones) and so + // the interpolated normal can also be zero (e.g. a grid of alternating solid and empty voxels). + if (v3dNormal.lengthSquared() > 0.000001f) + { + v3dNormal.normalise(); + } + + // Allow the controller to decide how the material should be derived from the voxels. + const typename VolumeType::VoxelType uMaterial = m_controller.blendMaterials(v011, v111, fInterp); + + MarchingCubesVertex surfaceVertex; + surfaceVertex.encodedPosition = v3dScaledPosition; + surfaceVertex.encodedNormal = encodeNormal(v3dNormal); + surfaceVertex.data = uMaterial; + + const uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex); + pIndicesX(uXRegSpace, uYRegSpace, uZRegSpace) = uLastVertexIndex; + + sampler.movePositiveX(); + } + if ((edgeTable[iCubeIndex] & 32) && (uYRegSpace > 0)) + { + sampler.moveNegativeY(); + POLYVOX_ASSERT(v101 != v111, "Attempting to insert vertex between two voxels with the same value"); + const Vector3DFloat n010 = computeCentralDifferenceGradient(sampler); + + const float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v101)) / static_cast(m_controller.convertToDensity(v111) - m_controller.convertToDensity(v101)); + + const Vector3DFloat v3dPosition(static_cast(uXRegSpace), static_cast(uYRegSpace - 1) + fInterp, static_cast(uZRegSpace)); + const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); + + Vector3DFloat v3dNormal = (n010*fInterp) + (n000*(1 - fInterp)); + + // The gradient for a voxel can be zero (e.g. solid voxel surrounded by empty ones) and so + // the interpolated normal can also be zero (e.g. a grid of alternating solid and empty voxels). + if (v3dNormal.lengthSquared() > 0.000001f) + { + v3dNormal.normalise(); + } + + // Allow the controller to decide how the material should be derived from the voxels. + const typename VolumeType::VoxelType uMaterial = m_controller.blendMaterials(v101, v111, fInterp); + + MarchingCubesVertex surfaceVertex; + surfaceVertex.encodedPosition = v3dScaledPosition; + surfaceVertex.encodedNormal = encodeNormal(v3dNormal); + surfaceVertex.data = uMaterial; + + uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex); + pIndicesY(uXRegSpace, uYRegSpace, uZRegSpace) = uLastVertexIndex; + + sampler.movePositiveY(); + } + if ((edgeTable[iCubeIndex] & 1024) && (uZRegSpace > 0)) + { + sampler.moveNegativeZ(); + POLYVOX_ASSERT(v110 != v111, "Attempting to insert vertex between two voxels with the same value"); + const Vector3DFloat n001 = computeCentralDifferenceGradient(sampler); + + const float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v110)) / static_cast(m_controller.convertToDensity(v111) - m_controller.convertToDensity(v110)); + + const Vector3DFloat v3dPosition(static_cast(uXRegSpace), static_cast(uYRegSpace), static_cast(uZRegSpace - 1) + fInterp); + const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); + + Vector3DFloat v3dNormal = (n001*fInterp) + (n000*(1 - fInterp)); + // The gradient for a voxel can be zero (e.g. solid voxel surrounded by empty ones) and so + // the interpolated normal can also be zero (e.g. a grid of alternating solid and empty voxels). + if (v3dNormal.lengthSquared() > 0.000001f) + { + v3dNormal.normalise(); + } + + // Allow the controller to decide how the material should be derived from the voxels. + const typename VolumeType::VoxelType uMaterial = m_controller.blendMaterials(v110, v111, fInterp); + + MarchingCubesVertex surfaceVertex; + surfaceVertex.encodedPosition = v3dScaledPosition; + surfaceVertex.encodedNormal = encodeNormal(v3dNormal); + surfaceVertex.data = uMaterial; + + const uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex); + pIndicesZ(uXRegSpace, uYRegSpace, uZRegSpace) = uLastVertexIndex; + + sampler.movePositiveZ(); + } + + // Now output the indices. For the first row, column or slice there aren't + // any (the region size in cells is one less than the region size in voxels) + if ((uXRegSpace != 0) && (uYRegSpace != 0) && (uZRegSpace != 0)) + { + + int32_t indlist[12]; + + sampler.setPosition(iXVolSpace, iYVolSpace, iZVolSpace); + + /* Cube is entirely in/out of the surface */ + if (edgeTable[iCubeIndex] != 0) + { + + /* Find the vertices where the surface intersects the cube */ + if (edgeTable[iCubeIndex] & 1) + { + indlist[0] = pIndicesX(uXRegSpace, uYRegSpace - 1, uZRegSpace - 1); + } + if (edgeTable[iCubeIndex] & 2) + { + indlist[1] = pIndicesY(uXRegSpace, uYRegSpace, uZRegSpace - 1); + } + if (edgeTable[iCubeIndex] & 4) + { + indlist[2] = pIndicesX(uXRegSpace, uYRegSpace, uZRegSpace - 1); + } + if (edgeTable[iCubeIndex] & 8) + { + indlist[3] = pIndicesY(uXRegSpace - 1, uYRegSpace, uZRegSpace - 1); + } + if (edgeTable[iCubeIndex] & 16) + { + indlist[4] = pIndicesX(uXRegSpace, uYRegSpace - 1, uZRegSpace); + } + if (edgeTable[iCubeIndex] & 32) + { + indlist[5] = pIndicesY(uXRegSpace, uYRegSpace, uZRegSpace); + } + if (edgeTable[iCubeIndex] & 64) + { + indlist[6] = pIndicesX(uXRegSpace, uYRegSpace, uZRegSpace); + } + if (edgeTable[iCubeIndex] & 128) + { + indlist[7] = pIndicesY(uXRegSpace - 1, uYRegSpace, uZRegSpace); + } + if (edgeTable[iCubeIndex] & 256) + { + indlist[8] = pIndicesZ(uXRegSpace - 1, uYRegSpace - 1, uZRegSpace); + } + if (edgeTable[iCubeIndex] & 512) + { + indlist[9] = pIndicesZ(uXRegSpace, uYRegSpace - 1, uZRegSpace); + } + if (edgeTable[iCubeIndex] & 1024) + { + indlist[10] = pIndicesZ(uXRegSpace, uYRegSpace, uZRegSpace); + } + if (edgeTable[iCubeIndex] & 2048) + { + indlist[11] = pIndicesZ(uXRegSpace - 1, uYRegSpace, uZRegSpace); + } + + for (int i = 0; triTable[iCubeIndex][i] != -1; i += 3) + { + const int32_t ind0 = indlist[triTable[iCubeIndex][i]]; + const int32_t ind1 = indlist[triTable[iCubeIndex][i + 1]]; + const int32_t ind2 = indlist[triTable[iCubeIndex][i + 2]]; + + if ((ind0 != -1) && (ind1 != -1) && (ind2 != -1)) + { + m_meshCurrent->addTriangle(ind0, ind1, ind2); + } + } // For each triangle + } + } + } // For each cell sampler.movePositiveX(); } // For X startOfRow.movePositiveY(); } // For Y startOfSlice.movePositiveZ(); } // For Z - - m_meshCurrent->setOffset(m_regSizeInVoxels.getLowerCorner()); - - POLYVOX_LOG_TRACE("Marching cubes surface extraction took ", timer.elapsedTimeInMilliSeconds(), - "ms (Region size = ", m_regSizeInVoxels.getWidthInVoxels(), "x", m_regSizeInVoxels.getHeightInVoxels(), - "x", m_regSizeInVoxels.getDepthInVoxels(), ")"); - } - - template - void MarchingCubesSurfaceExtractor::generateMeshForCell(uint32_t uXRegSpace, uint32_t uYRegSpace, uint32_t uZRegSpace, typename VolumeType::Sampler& sampler, typename VolumeType::VoxelType v111, uint8_t iCubeIndex, Array3DInt32& pIndicesX, Array3DInt32& pIndicesY, Array3DInt32& pIndicesZ, int32_t iXVolSpace, int32_t iYVolSpace, int32_t iZVolSpace) - { - // These three might not have been sampled, as v111 is the only one we sample every iteration. - typename VolumeType::VoxelType v110 = sampler.peekVoxel0px0py1nz(); - typename VolumeType::VoxelType v101 = sampler.peekVoxel0px1ny0pz(); - typename VolumeType::VoxelType v011 = sampler.peekVoxel1nx0py0pz(); - - const Vector3DFloat n000 = computeCentralDifferenceGradient(sampler); - - /* Find the vertices where the surface intersects the cube */ - if ((edgeTable[iCubeIndex] & 64) && (uXRegSpace > 0)) - { - sampler.moveNegativeX(); - POLYVOX_ASSERT(v011 != v111, "Attempting to insert vertex between two voxels with the same value"); - const Vector3DFloat n100 = computeCentralDifferenceGradient(sampler); - - const float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v011)) / static_cast(m_controller.convertToDensity(v111) - m_controller.convertToDensity(v011)); - - const Vector3DFloat v3dPosition(static_cast(uXRegSpace - 1) + fInterp, static_cast(uYRegSpace), static_cast(uZRegSpace)); - const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); - - Vector3DFloat v3dNormal = (n100*fInterp) + (n000*(1 - fInterp)); - - // The gradient for a voxel can be zero (e.g. solid voxel surrounded by empty ones) and so - // the interpolated normal can also be zero (e.g. a grid of alternating solid and empty voxels). - if (v3dNormal.lengthSquared() > 0.000001f) - { - v3dNormal.normalise(); - } - - // Allow the controller to decide how the material should be derived from the voxels. - const typename VolumeType::VoxelType uMaterial = m_controller.blendMaterials(v011, v111, fInterp); - - MarchingCubesVertex surfaceVertex; - surfaceVertex.encodedPosition = v3dScaledPosition; - surfaceVertex.encodedNormal = encodeNormal(v3dNormal); - surfaceVertex.data = uMaterial; - - const uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex); - pIndicesX(uXRegSpace, uYRegSpace, uZRegSpace) = uLastVertexIndex; - - sampler.movePositiveX(); - } - if ((edgeTable[iCubeIndex] & 32) && (uYRegSpace > 0)) - { - sampler.moveNegativeY(); - POLYVOX_ASSERT(v101 != v111, "Attempting to insert vertex between two voxels with the same value"); - const Vector3DFloat n010 = computeCentralDifferenceGradient(sampler); - - const float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v101)) / static_cast(m_controller.convertToDensity(v111) - m_controller.convertToDensity(v101)); - - const Vector3DFloat v3dPosition(static_cast(uXRegSpace), static_cast(uYRegSpace - 1) + fInterp, static_cast(uZRegSpace)); - const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); - - Vector3DFloat v3dNormal = (n010*fInterp) + (n000*(1 - fInterp)); - - // The gradient for a voxel can be zero (e.g. solid voxel surrounded by empty ones) and so - // the interpolated normal can also be zero (e.g. a grid of alternating solid and empty voxels). - if (v3dNormal.lengthSquared() > 0.000001f) - { - v3dNormal.normalise(); - } - - // Allow the controller to decide how the material should be derived from the voxels. - const typename VolumeType::VoxelType uMaterial = m_controller.blendMaterials(v101, v111, fInterp); - - MarchingCubesVertex surfaceVertex; - surfaceVertex.encodedPosition = v3dScaledPosition; - surfaceVertex.encodedNormal = encodeNormal(v3dNormal); - surfaceVertex.data = uMaterial; - - uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex); - pIndicesY(uXRegSpace, uYRegSpace, uZRegSpace) = uLastVertexIndex; - - sampler.movePositiveY(); - } - if ((edgeTable[iCubeIndex] & 1024) && (uZRegSpace > 0)) - { - sampler.moveNegativeZ(); - POLYVOX_ASSERT(v110 != v111, "Attempting to insert vertex between two voxels with the same value"); - const Vector3DFloat n001 = computeCentralDifferenceGradient(sampler); - - const float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v110)) / static_cast(m_controller.convertToDensity(v111) - m_controller.convertToDensity(v110)); - - const Vector3DFloat v3dPosition(static_cast(uXRegSpace), static_cast(uYRegSpace), static_cast(uZRegSpace - 1) + fInterp); - const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); - - Vector3DFloat v3dNormal = (n001*fInterp) + (n000*(1 - fInterp)); - // The gradient for a voxel can be zero (e.g. solid voxel surrounded by empty ones) and so - // the interpolated normal can also be zero (e.g. a grid of alternating solid and empty voxels). - if (v3dNormal.lengthSquared() > 0.000001f) - { - v3dNormal.normalise(); - } - - // Allow the controller to decide how the material should be derived from the voxels. - const typename VolumeType::VoxelType uMaterial = m_controller.blendMaterials(v110, v111, fInterp); - - MarchingCubesVertex surfaceVertex; - surfaceVertex.encodedPosition = v3dScaledPosition; - surfaceVertex.encodedNormal = encodeNormal(v3dNormal); - surfaceVertex.data = uMaterial; - - const uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex); - pIndicesZ(uXRegSpace, uYRegSpace, uZRegSpace) = uLastVertexIndex; - - sampler.movePositiveZ(); - } - - // Now output the indices. For the first row, column or slice there aren't - // any (the region size in cells is one less than the region size in voxels) - if ((uXRegSpace != 0) && (uYRegSpace != 0) && (uZRegSpace != 0)) - { - - int32_t indlist[12]; - - sampler.setPosition(iXVolSpace, iYVolSpace, iZVolSpace); - - /* Cube is entirely in/out of the surface */ - if (edgeTable[iCubeIndex] != 0) - { - - /* Find the vertices where the surface intersects the cube */ - if (edgeTable[iCubeIndex] & 1) - { - indlist[0] = pIndicesX(uXRegSpace, uYRegSpace - 1, uZRegSpace - 1); - } - if (edgeTable[iCubeIndex] & 2) - { - indlist[1] = pIndicesY(uXRegSpace, uYRegSpace, uZRegSpace - 1); - } - if (edgeTable[iCubeIndex] & 4) - { - indlist[2] = pIndicesX(uXRegSpace, uYRegSpace, uZRegSpace - 1); - } - if (edgeTable[iCubeIndex] & 8) - { - indlist[3] = pIndicesY(uXRegSpace - 1, uYRegSpace, uZRegSpace - 1); - } - if (edgeTable[iCubeIndex] & 16) - { - indlist[4] = pIndicesX(uXRegSpace, uYRegSpace - 1, uZRegSpace); - } - if (edgeTable[iCubeIndex] & 32) - { - indlist[5] = pIndicesY(uXRegSpace, uYRegSpace, uZRegSpace); - } - if (edgeTable[iCubeIndex] & 64) - { - indlist[6] = pIndicesX(uXRegSpace, uYRegSpace, uZRegSpace); - } - if (edgeTable[iCubeIndex] & 128) - { - indlist[7] = pIndicesY(uXRegSpace - 1, uYRegSpace, uZRegSpace); - } - if (edgeTable[iCubeIndex] & 256) - { - indlist[8] = pIndicesZ(uXRegSpace - 1, uYRegSpace - 1, uZRegSpace); - } - if (edgeTable[iCubeIndex] & 512) - { - indlist[9] = pIndicesZ(uXRegSpace, uYRegSpace - 1, uZRegSpace); - } - if (edgeTable[iCubeIndex] & 1024) - { - indlist[10] = pIndicesZ(uXRegSpace, uYRegSpace, uZRegSpace); - } - if (edgeTable[iCubeIndex] & 2048) - { - indlist[11] = pIndicesZ(uXRegSpace - 1, uYRegSpace, uZRegSpace); - } - - for (int i = 0; triTable[iCubeIndex][i] != -1; i += 3) - { - const int32_t ind0 = indlist[triTable[iCubeIndex][i]]; - const int32_t ind1 = indlist[triTable[iCubeIndex][i + 1]]; - const int32_t ind2 = indlist[triTable[iCubeIndex][i + 2]]; - - if ((ind0 != -1) && (ind1 != -1) && (ind2 != -1)) - { - m_meshCurrent->addTriangle(ind0, ind1, ind2); - } - } // For each triangle - } - } } } From d353685ce9c994a8f6e3809dedc702cbe52d0b49 Mon Sep 17 00:00:00 2001 From: David Williams Date: Mon, 25 May 2015 20:42:40 +0200 Subject: [PATCH 41/61] Restructuring code... --- .../PolyVox/MarchingCubesSurfaceExtractor.h | 10 ++--- .../PolyVox/MarchingCubesSurfaceExtractor.inl | 40 +++++++++---------- 2 files changed, 22 insertions(+), 28 deletions(-) diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.h b/include/PolyVox/MarchingCubesSurfaceExtractor.h index 0c7b649e..05ab9c3b 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.h +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.h @@ -153,13 +153,11 @@ namespace PolyVox class MarchingCubesSurfaceExtractor { public: - MarchingCubesSurfaceExtractor(VolumeType* volData, Region region, MeshType* result, ControllerType controller); + MarchingCubesSurfaceExtractor(); - void execute(); + void execute(VolumeType* volData, Region region, MeshType* result, ControllerType controller); private: - //Compute the cell bitmask for a particular slice in z. - void computeBitmaskForSlice(); //////////////////////////////////////////////////////////////////////////////// // NOTE: These two functions are in the .h file rather than the .inl due to an apparent bug in VC2010. @@ -307,8 +305,8 @@ namespace PolyVox template< typename VolumeType, typename MeshType, typename ControllerType = DefaultMarchingCubesController > void extractMarchingCubesMeshCustom(VolumeType* volData, Region region, MeshType* result, ControllerType controller = ControllerType()) { - MarchingCubesSurfaceExtractor extractor(volData, region, result, controller); - extractor.execute(); + MarchingCubesSurfaceExtractor extractor; + extractor.execute(volData, region, result, controller); } template< typename VolumeType, typename ControllerType = DefaultMarchingCubesController > diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.inl b/include/PolyVox/MarchingCubesSurfaceExtractor.inl index 1d75e73f..defb2b82 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.inl +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.inl @@ -26,34 +26,24 @@ freely, subject to the following restrictions: namespace PolyVox { template - MarchingCubesSurfaceExtractor::MarchingCubesSurfaceExtractor(VolumeType* volData, Region region, MeshType* result, ControllerType controller) - :m_volData(volData) - ,m_meshCurrent(result) - ,m_regSizeInVoxels(region) - ,m_controller(controller) - ,m_tThreshold(m_controller.getThreshold()) - { - POLYVOX_THROW_IF(m_meshCurrent == nullptr, std::invalid_argument, "Provided mesh cannot be null"); + MarchingCubesSurfaceExtractor::MarchingCubesSurfaceExtractor() + { } template - void MarchingCubesSurfaceExtractor::execute() + void MarchingCubesSurfaceExtractor::execute(VolumeType* volData, Region region, MeshType* result, ControllerType controller) { + POLYVOX_THROW_IF(result == nullptr, std::invalid_argument, "Provided mesh cannot be null"); + + m_volData = volData; + m_meshCurrent = result; + m_regSizeInVoxels = region; + m_controller = controller; + m_tThreshold = m_controller.getThreshold(); + Timer timer; m_meshCurrent->clear(); - computeBitmaskForSlice(); - - m_meshCurrent->setOffset(m_regSizeInVoxels.getLowerCorner()); - - POLYVOX_LOG_TRACE("Marching cubes surface extraction took ", timer.elapsedTimeInMilliSeconds(), - "ms (Region size = ", m_regSizeInVoxels.getWidthInVoxels(), "x", m_regSizeInVoxels.getHeightInVoxels(), - "x", m_regSizeInVoxels.getDepthInVoxels(), ")"); - } - - template - void MarchingCubesSurfaceExtractor::computeBitmaskForSlice() - { const uint32_t uArrayWidth = m_regSizeInVoxels.getUpperX() - m_regSizeInVoxels.getLowerX() + 2; const uint32_t uArrayHeight = m_regSizeInVoxels.getUpperY() - m_regSizeInVoxels.getLowerY() + 2; const uint32_t uArrayDepth = m_regSizeInVoxels.getUpperZ() - m_regSizeInVoxels.getLowerZ() + 2; @@ -321,5 +311,11 @@ namespace PolyVox } // For Y startOfSlice.movePositiveZ(); } // For Z - } + + m_meshCurrent->setOffset(m_regSizeInVoxels.getLowerCorner()); + + POLYVOX_LOG_TRACE("Marching cubes surface extraction took ", timer.elapsedTimeInMilliSeconds(), + "ms (Region size = ", m_regSizeInVoxels.getWidthInVoxels(), "x", m_regSizeInVoxels.getHeightInVoxels(), + "x", m_regSizeInVoxels.getDepthInVoxels(), ")"); + } } From b3ce982ef3d3b898ee64a93beff4a3ae9faf7ef8 Mon Sep 17 00:00:00 2001 From: David Williams Date: Mon, 25 May 2015 20:51:42 +0200 Subject: [PATCH 42/61] Removed some member variables. --- .../PolyVox/MarchingCubesSurfaceExtractor.h | 12 ----- .../PolyVox/MarchingCubesSurfaceExtractor.inl | 51 +++++++++---------- 2 files changed, 24 insertions(+), 39 deletions(-) diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.h b/include/PolyVox/MarchingCubesSurfaceExtractor.h index 05ab9c3b..46003e8b 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.h +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.h @@ -273,20 +273,8 @@ namespace PolyVox // End of compiler bug workaroumd. //////////////////////////////////////////////////////////////////////////////// - //The volume data and a sampler to access it. - VolumeType* m_volData; - - //The surface patch we are currently filling. - MeshType* m_meshCurrent; - - //Information about the region we are currently processing - Region m_regSizeInVoxels; - //Used to convert arbitrary voxel types in densities and materials. ControllerType m_controller; - - //Our threshold value - typename ControllerType::DensityType m_tThreshold; }; // This version of the function performs the extraction into a user-provided mesh rather than allocating a mesh automatically. diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.inl b/include/PolyVox/MarchingCubesSurfaceExtractor.inl index defb2b82..fcccdbe3 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.inl +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.inl @@ -35,18 +35,15 @@ namespace PolyVox { POLYVOX_THROW_IF(result == nullptr, std::invalid_argument, "Provided mesh cannot be null"); - m_volData = volData; - m_meshCurrent = result; - m_regSizeInVoxels = region; m_controller = controller; - m_tThreshold = m_controller.getThreshold(); + typename ControllerType::DensityType tThreshold = m_controller.getThreshold(); Timer timer; - m_meshCurrent->clear(); + result->clear(); - const uint32_t uArrayWidth = m_regSizeInVoxels.getUpperX() - m_regSizeInVoxels.getLowerX() + 2; - const uint32_t uArrayHeight = m_regSizeInVoxels.getUpperY() - m_regSizeInVoxels.getLowerY() + 2; - const uint32_t uArrayDepth = m_regSizeInVoxels.getUpperZ() - m_regSizeInVoxels.getLowerZ() + 2; + const uint32_t uArrayWidth = region.getUpperX() - region.getLowerX() + 2; + const uint32_t uArrayHeight = region.getUpperY() - region.getLowerY() + 2; + const uint32_t uArrayDepth = region.getUpperZ() - region.getLowerZ() + 2; //For edge indices Array3DInt32 pIndicesX(uArrayWidth, uArrayHeight, uArrayDepth); @@ -64,26 +61,26 @@ namespace PolyVox uint8_t uPreviousCell = 0; - typename VolumeType::Sampler startOfSlice(m_volData); - startOfSlice.setPosition(m_regSizeInVoxels.getLowerX(), m_regSizeInVoxels.getLowerY(), m_regSizeInVoxels.getLowerZ()); + typename VolumeType::Sampler startOfSlice(volData); + startOfSlice.setPosition(region.getLowerX(), region.getLowerY(), region.getLowerZ()); - for (int32_t iZVolSpace = m_regSizeInVoxels.getLowerZ(); iZVolSpace <= m_regSizeInVoxels.getUpperZ(); iZVolSpace++) + for (int32_t iZVolSpace = region.getLowerZ(); iZVolSpace <= region.getUpperZ(); iZVolSpace++) { - const uint32_t uZRegSpace = iZVolSpace - m_regSizeInVoxels.getLowerZ(); + const uint32_t uZRegSpace = iZVolSpace - region.getLowerZ(); typename VolumeType::Sampler startOfRow = startOfSlice; - for (int32_t iYVolSpace = m_regSizeInVoxels.getLowerY(); iYVolSpace <= m_regSizeInVoxels.getUpperY(); iYVolSpace++) + for (int32_t iYVolSpace = region.getLowerY(); iYVolSpace <= region.getUpperY(); iYVolSpace++) { - const uint32_t uYRegSpace = iYVolSpace - m_regSizeInVoxels.getLowerY(); + const uint32_t uYRegSpace = iYVolSpace - region.getLowerY(); // Copying a sampler which is already pointing at the correct location seems (slightly) faster than // calling setPosition(). Therefore we make use of 'startOfRow' and 'startOfSlice' to reset the sampler. typename VolumeType::Sampler sampler = startOfRow; - for (int32_t iXVolSpace = m_regSizeInVoxels.getLowerX(); iXVolSpace <= m_regSizeInVoxels.getUpperX(); iXVolSpace++) + for (int32_t iXVolSpace = region.getLowerX(); iXVolSpace <= region.getUpperX(); iXVolSpace++) { - const uint32_t uXRegSpace = iXVolSpace - m_regSizeInVoxels.getLowerX(); + const uint32_t uXRegSpace = iXVolSpace - region.getLowerX(); uint8_t iCubeIndex = 0; @@ -110,7 +107,7 @@ namespace PolyVox // The last bit of our cube index is obtained by looking // at the relevant voxel and comparing it to the threshold typename VolumeType::VoxelType v111 = sampler.getVoxel(); - if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128; + if (m_controller.convertToDensity(v111) < tThreshold) iCubeIndex |= 128; // The current value becomes the previous value, ready for the next iteration. uPreviousCell = iCubeIndex; @@ -135,7 +132,7 @@ namespace PolyVox POLYVOX_ASSERT(v011 != v111, "Attempting to insert vertex between two voxels with the same value"); const Vector3DFloat n100 = computeCentralDifferenceGradient(sampler); - const float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v011)) / static_cast(m_controller.convertToDensity(v111) - m_controller.convertToDensity(v011)); + const float fInterp = static_cast(tThreshold - m_controller.convertToDensity(v011)) / static_cast(m_controller.convertToDensity(v111) - m_controller.convertToDensity(v011)); const Vector3DFloat v3dPosition(static_cast(uXRegSpace - 1) + fInterp, static_cast(uYRegSpace), static_cast(uZRegSpace)); const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); @@ -157,7 +154,7 @@ namespace PolyVox surfaceVertex.encodedNormal = encodeNormal(v3dNormal); surfaceVertex.data = uMaterial; - const uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex); + const uint32_t uLastVertexIndex = result->addVertex(surfaceVertex); pIndicesX(uXRegSpace, uYRegSpace, uZRegSpace) = uLastVertexIndex; sampler.movePositiveX(); @@ -168,7 +165,7 @@ namespace PolyVox POLYVOX_ASSERT(v101 != v111, "Attempting to insert vertex between two voxels with the same value"); const Vector3DFloat n010 = computeCentralDifferenceGradient(sampler); - const float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v101)) / static_cast(m_controller.convertToDensity(v111) - m_controller.convertToDensity(v101)); + const float fInterp = static_cast(tThreshold - m_controller.convertToDensity(v101)) / static_cast(m_controller.convertToDensity(v111) - m_controller.convertToDensity(v101)); const Vector3DFloat v3dPosition(static_cast(uXRegSpace), static_cast(uYRegSpace - 1) + fInterp, static_cast(uZRegSpace)); const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); @@ -190,7 +187,7 @@ namespace PolyVox surfaceVertex.encodedNormal = encodeNormal(v3dNormal); surfaceVertex.data = uMaterial; - uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex); + uint32_t uLastVertexIndex = result->addVertex(surfaceVertex); pIndicesY(uXRegSpace, uYRegSpace, uZRegSpace) = uLastVertexIndex; sampler.movePositiveY(); @@ -201,7 +198,7 @@ namespace PolyVox POLYVOX_ASSERT(v110 != v111, "Attempting to insert vertex between two voxels with the same value"); const Vector3DFloat n001 = computeCentralDifferenceGradient(sampler); - const float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v110)) / static_cast(m_controller.convertToDensity(v111) - m_controller.convertToDensity(v110)); + const float fInterp = static_cast(tThreshold - m_controller.convertToDensity(v110)) / static_cast(m_controller.convertToDensity(v111) - m_controller.convertToDensity(v110)); const Vector3DFloat v3dPosition(static_cast(uXRegSpace), static_cast(uYRegSpace), static_cast(uZRegSpace - 1) + fInterp); const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); @@ -222,7 +219,7 @@ namespace PolyVox surfaceVertex.encodedNormal = encodeNormal(v3dNormal); surfaceVertex.data = uMaterial; - const uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex); + const uint32_t uLastVertexIndex = result->addVertex(surfaceVertex); pIndicesZ(uXRegSpace, uYRegSpace, uZRegSpace) = uLastVertexIndex; sampler.movePositiveZ(); @@ -299,7 +296,7 @@ namespace PolyVox if ((ind0 != -1) && (ind1 != -1) && (ind2 != -1)) { - m_meshCurrent->addTriangle(ind0, ind1, ind2); + result->addTriangle(ind0, ind1, ind2); } } // For each triangle } @@ -312,10 +309,10 @@ namespace PolyVox startOfSlice.movePositiveZ(); } // For Z - m_meshCurrent->setOffset(m_regSizeInVoxels.getLowerCorner()); + result->setOffset(region.getLowerCorner()); POLYVOX_LOG_TRACE("Marching cubes surface extraction took ", timer.elapsedTimeInMilliSeconds(), - "ms (Region size = ", m_regSizeInVoxels.getWidthInVoxels(), "x", m_regSizeInVoxels.getHeightInVoxels(), - "x", m_regSizeInVoxels.getDepthInVoxels(), ")"); + "ms (Region size = ", region.getWidthInVoxels(), "x", region.getHeightInVoxels(), + "x", region.getDepthInVoxels(), ")"); } } From e4ef84504556189679a29905232488edc9392e87 Mon Sep 17 00:00:00 2001 From: David Williams Date: Mon, 25 May 2015 21:00:50 +0200 Subject: [PATCH 43/61] Removed sobel gradient calculation code. Removed m_controller member. --- .../PolyVox/MarchingCubesSurfaceExtractor.h | 102 ++---------------- .../PolyVox/MarchingCubesSurfaceExtractor.inl | 25 +++-- 2 files changed, 19 insertions(+), 108 deletions(-) diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.h b/include/PolyVox/MarchingCubesSurfaceExtractor.h index 46003e8b..dde8acdf 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.h +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.h @@ -163,19 +163,19 @@ namespace PolyVox // NOTE: These two functions are in the .h file rather than the .inl due to an apparent bug in VC2010. //See http://stackoverflow.com/questions/1484885/strange-vc-compile-error-c2244 for details. //////////////////////////////////////////////////////////////////////////////// - Vector3DFloat computeCentralDifferenceGradient(const typename VolumeType::Sampler& volIter) + Vector3DFloat computeCentralDifferenceGradient(const typename VolumeType::Sampler& volIter, ControllerType& controller) { //FIXME - Should actually use DensityType here, both in principle and because the maths may be //faster (and to reduce casts). So it would be good to add a way to get DensityType from a voxel. //But watch out for when the DensityType is unsigned and the difference could be negative. - float voxel1nx = static_cast(m_controller.convertToDensity(volIter.peekVoxel1nx0py0pz())); - float voxel1px = static_cast(m_controller.convertToDensity(volIter.peekVoxel1px0py0pz())); + float voxel1nx = static_cast(controller.convertToDensity(volIter.peekVoxel1nx0py0pz())); + float voxel1px = static_cast(controller.convertToDensity(volIter.peekVoxel1px0py0pz())); - float voxel1ny = static_cast(m_controller.convertToDensity(volIter.peekVoxel0px1ny0pz())); - float voxel1py = static_cast(m_controller.convertToDensity(volIter.peekVoxel0px1py0pz())); + float voxel1ny = static_cast(controller.convertToDensity(volIter.peekVoxel0px1ny0pz())); + float voxel1py = static_cast(controller.convertToDensity(volIter.peekVoxel0px1py0pz())); - float voxel1nz = static_cast(m_controller.convertToDensity(volIter.peekVoxel0px0py1nz())); - float voxel1pz = static_cast(m_controller.convertToDensity(volIter.peekVoxel0px0py1pz())); + float voxel1nz = static_cast(controller.convertToDensity(volIter.peekVoxel0px0py1nz())); + float voxel1pz = static_cast(controller.convertToDensity(volIter.peekVoxel0px0py1pz())); return Vector3DFloat ( @@ -184,97 +184,9 @@ namespace PolyVox voxel1nz - voxel1pz ); } - - Vector3DFloat computeSobelGradient(const typename VolumeType::Sampler& volIter) - { - static const int weights[3][3][3] = { { {2,3,2}, {3,6,3}, {2,3,2} }, { - {3,6,3}, {6,0,6}, {3,6,3} }, { {2,3,2}, {3,6,3}, {2,3,2} } }; - - //FIXME - Should actually use DensityType here, both in principle and because the maths may be - //faster (and to reduce casts). So it would be good to add a way to get DensityType from a voxel. - //But watch out for when the DensityType is unsigned and the difference could be negative. - const float pVoxel1nx1ny1nz = static_cast(m_controller.convertToDensity(volIter.peekVoxel1nx1ny1nz())); - const float pVoxel1nx1ny0pz = static_cast(m_controller.convertToDensity(volIter.peekVoxel1nx1ny0pz())); - const float pVoxel1nx1ny1pz = static_cast(m_controller.convertToDensity(volIter.peekVoxel1nx1ny1pz())); - const float pVoxel1nx0py1nz = static_cast(m_controller.convertToDensity(volIter.peekVoxel1nx0py1nz())); - const float pVoxel1nx0py0pz = static_cast(m_controller.convertToDensity(volIter.peekVoxel1nx0py0pz())); - const float pVoxel1nx0py1pz = static_cast(m_controller.convertToDensity(volIter.peekVoxel1nx0py1pz())); - const float pVoxel1nx1py1nz = static_cast(m_controller.convertToDensity(volIter.peekVoxel1nx1py1nz())); - const float pVoxel1nx1py0pz = static_cast(m_controller.convertToDensity(volIter.peekVoxel1nx1py0pz())); - const float pVoxel1nx1py1pz = static_cast(m_controller.convertToDensity(volIter.peekVoxel1nx1py1pz())); - - const float pVoxel0px1ny1nz = static_cast(m_controller.convertToDensity(volIter.peekVoxel0px1ny1nz())); - const float pVoxel0px1ny0pz = static_cast(m_controller.convertToDensity(volIter.peekVoxel0px1ny0pz())); - const float pVoxel0px1ny1pz = static_cast(m_controller.convertToDensity(volIter.peekVoxel0px1ny1pz())); - const float pVoxel0px0py1nz = static_cast(m_controller.convertToDensity(volIter.peekVoxel0px0py1nz())); - //const float pVoxel0px0py0pz = static_cast(m_controller.convertToDensity(volIter.peekVoxel0px0py0pz())); - const float pVoxel0px0py1pz = static_cast(m_controller.convertToDensity(volIter.peekVoxel0px0py1pz())); - const float pVoxel0px1py1nz = static_cast(m_controller.convertToDensity(volIter.peekVoxel0px1py1nz())); - const float pVoxel0px1py0pz = static_cast(m_controller.convertToDensity(volIter.peekVoxel0px1py0pz())); - const float pVoxel0px1py1pz = static_cast(m_controller.convertToDensity(volIter.peekVoxel0px1py1pz())); - - const float pVoxel1px1ny1nz = static_cast(m_controller.convertToDensity(volIter.peekVoxel1px1ny1nz())); - const float pVoxel1px1ny0pz = static_cast(m_controller.convertToDensity(volIter.peekVoxel1px1ny0pz())); - const float pVoxel1px1ny1pz = static_cast(m_controller.convertToDensity(volIter.peekVoxel1px1ny1pz())); - const float pVoxel1px0py1nz = static_cast(m_controller.convertToDensity(volIter.peekVoxel1px0py1nz())); - const float pVoxel1px0py0pz = static_cast(m_controller.convertToDensity(volIter.peekVoxel1px0py0pz())); - const float pVoxel1px0py1pz = static_cast(m_controller.convertToDensity(volIter.peekVoxel1px0py1pz())); - const float pVoxel1px1py1nz = static_cast(m_controller.convertToDensity(volIter.peekVoxel1px1py1nz())); - const float pVoxel1px1py0pz = static_cast(m_controller.convertToDensity(volIter.peekVoxel1px1py0pz())); - const float pVoxel1px1py1pz = static_cast(m_controller.convertToDensity(volIter.peekVoxel1px1py1pz())); - - const float xGrad(- weights[0][0][0] * pVoxel1nx1ny1nz - - weights[1][0][0] * pVoxel1nx1ny0pz - weights[2][0][0] * - pVoxel1nx1ny1pz - weights[0][1][0] * pVoxel1nx0py1nz - - weights[1][1][0] * pVoxel1nx0py0pz - weights[2][1][0] * - pVoxel1nx0py1pz - weights[0][2][0] * pVoxel1nx1py1nz - - weights[1][2][0] * pVoxel1nx1py0pz - weights[2][2][0] * - pVoxel1nx1py1pz + weights[0][0][2] * pVoxel1px1ny1nz + - weights[1][0][2] * pVoxel1px1ny0pz + weights[2][0][2] * - pVoxel1px1ny1pz + weights[0][1][2] * pVoxel1px0py1nz + - weights[1][1][2] * pVoxel1px0py0pz + weights[2][1][2] * - pVoxel1px0py1pz + weights[0][2][2] * pVoxel1px1py1nz + - weights[1][2][2] * pVoxel1px1py0pz + weights[2][2][2] * - pVoxel1px1py1pz); - - const float yGrad(- weights[0][0][0] * pVoxel1nx1ny1nz - - weights[1][0][0] * pVoxel1nx1ny0pz - weights[2][0][0] * - pVoxel1nx1ny1pz + weights[0][2][0] * pVoxel1nx1py1nz + - weights[1][2][0] * pVoxel1nx1py0pz + weights[2][2][0] * - pVoxel1nx1py1pz - weights[0][0][1] * pVoxel0px1ny1nz - - weights[1][0][1] * pVoxel0px1ny0pz - weights[2][0][1] * - pVoxel0px1ny1pz + weights[0][2][1] * pVoxel0px1py1nz + - weights[1][2][1] * pVoxel0px1py0pz + weights[2][2][1] * - pVoxel0px1py1pz - weights[0][0][2] * pVoxel1px1ny1nz - - weights[1][0][2] * pVoxel1px1ny0pz - weights[2][0][2] * - pVoxel1px1ny1pz + weights[0][2][2] * pVoxel1px1py1nz + - weights[1][2][2] * pVoxel1px1py0pz + weights[2][2][2] * - pVoxel1px1py1pz); - - const float zGrad(- weights[0][0][0] * pVoxel1nx1ny1nz + - weights[2][0][0] * pVoxel1nx1ny1pz - weights[0][1][0] * - pVoxel1nx0py1nz + weights[2][1][0] * pVoxel1nx0py1pz - - weights[0][2][0] * pVoxel1nx1py1nz + weights[2][2][0] * - pVoxel1nx1py1pz - weights[0][0][1] * pVoxel0px1ny1nz + - weights[2][0][1] * pVoxel0px1ny1pz - weights[0][1][1] * - pVoxel0px0py1nz + weights[2][1][1] * pVoxel0px0py1pz - - weights[0][2][1] * pVoxel0px1py1nz + weights[2][2][1] * - pVoxel0px1py1pz - weights[0][0][2] * pVoxel1px1ny1nz + - weights[2][0][2] * pVoxel1px1ny1pz - weights[0][1][2] * - pVoxel1px0py1nz + weights[2][1][2] * pVoxel1px0py1pz - - weights[0][2][2] * pVoxel1px1py1nz + weights[2][2][2] * - pVoxel1px1py1pz); - - //Note: The above actually give gradients going from low density to high density. - //For our normals we want the the other way around, so we switch the components as we return them. - return Vector3DFloat(-xGrad,-yGrad,-zGrad); - } //////////////////////////////////////////////////////////////////////////////// // End of compiler bug workaroumd. //////////////////////////////////////////////////////////////////////////////// - - //Used to convert arbitrary voxel types in densities and materials. - ControllerType m_controller; }; // This version of the function performs the extraction into a user-provided mesh rather than allocating a mesh automatically. diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.inl b/include/PolyVox/MarchingCubesSurfaceExtractor.inl index fcccdbe3..e70b7374 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.inl +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.inl @@ -35,8 +35,7 @@ namespace PolyVox { POLYVOX_THROW_IF(result == nullptr, std::invalid_argument, "Provided mesh cannot be null"); - m_controller = controller; - typename ControllerType::DensityType tThreshold = m_controller.getThreshold(); + typename ControllerType::DensityType tThreshold = controller.getThreshold(); Timer timer; result->clear(); @@ -107,7 +106,7 @@ namespace PolyVox // The last bit of our cube index is obtained by looking // at the relevant voxel and comparing it to the threshold typename VolumeType::VoxelType v111 = sampler.getVoxel(); - if (m_controller.convertToDensity(v111) < tThreshold) iCubeIndex |= 128; + if (controller.convertToDensity(v111) < tThreshold) iCubeIndex |= 128; // The current value becomes the previous value, ready for the next iteration. uPreviousCell = iCubeIndex; @@ -123,16 +122,16 @@ namespace PolyVox typename VolumeType::VoxelType v101 = sampler.peekVoxel0px1ny0pz(); typename VolumeType::VoxelType v011 = sampler.peekVoxel1nx0py0pz(); - const Vector3DFloat n000 = computeCentralDifferenceGradient(sampler); + const Vector3DFloat n000 = computeCentralDifferenceGradient(sampler, controller); /* Find the vertices where the surface intersects the cube */ if ((edgeTable[iCubeIndex] & 64) && (uXRegSpace > 0)) { sampler.moveNegativeX(); POLYVOX_ASSERT(v011 != v111, "Attempting to insert vertex between two voxels with the same value"); - const Vector3DFloat n100 = computeCentralDifferenceGradient(sampler); + const Vector3DFloat n100 = computeCentralDifferenceGradient(sampler, controller); - const float fInterp = static_cast(tThreshold - m_controller.convertToDensity(v011)) / static_cast(m_controller.convertToDensity(v111) - m_controller.convertToDensity(v011)); + const float fInterp = static_cast(tThreshold - controller.convertToDensity(v011)) / static_cast(controller.convertToDensity(v111) - controller.convertToDensity(v011)); const Vector3DFloat v3dPosition(static_cast(uXRegSpace - 1) + fInterp, static_cast(uYRegSpace), static_cast(uZRegSpace)); const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); @@ -147,7 +146,7 @@ namespace PolyVox } // Allow the controller to decide how the material should be derived from the voxels. - const typename VolumeType::VoxelType uMaterial = m_controller.blendMaterials(v011, v111, fInterp); + const typename VolumeType::VoxelType uMaterial = controller.blendMaterials(v011, v111, fInterp); MarchingCubesVertex surfaceVertex; surfaceVertex.encodedPosition = v3dScaledPosition; @@ -163,9 +162,9 @@ namespace PolyVox { sampler.moveNegativeY(); POLYVOX_ASSERT(v101 != v111, "Attempting to insert vertex between two voxels with the same value"); - const Vector3DFloat n010 = computeCentralDifferenceGradient(sampler); + const Vector3DFloat n010 = computeCentralDifferenceGradient(sampler, controller); - const float fInterp = static_cast(tThreshold - m_controller.convertToDensity(v101)) / static_cast(m_controller.convertToDensity(v111) - m_controller.convertToDensity(v101)); + const float fInterp = static_cast(tThreshold - controller.convertToDensity(v101)) / static_cast(controller.convertToDensity(v111) - controller.convertToDensity(v101)); const Vector3DFloat v3dPosition(static_cast(uXRegSpace), static_cast(uYRegSpace - 1) + fInterp, static_cast(uZRegSpace)); const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); @@ -180,7 +179,7 @@ namespace PolyVox } // Allow the controller to decide how the material should be derived from the voxels. - const typename VolumeType::VoxelType uMaterial = m_controller.blendMaterials(v101, v111, fInterp); + const typename VolumeType::VoxelType uMaterial = controller.blendMaterials(v101, v111, fInterp); MarchingCubesVertex surfaceVertex; surfaceVertex.encodedPosition = v3dScaledPosition; @@ -196,9 +195,9 @@ namespace PolyVox { sampler.moveNegativeZ(); POLYVOX_ASSERT(v110 != v111, "Attempting to insert vertex between two voxels with the same value"); - const Vector3DFloat n001 = computeCentralDifferenceGradient(sampler); + const Vector3DFloat n001 = computeCentralDifferenceGradient(sampler, controller); - const float fInterp = static_cast(tThreshold - m_controller.convertToDensity(v110)) / static_cast(m_controller.convertToDensity(v111) - m_controller.convertToDensity(v110)); + const float fInterp = static_cast(tThreshold - controller.convertToDensity(v110)) / static_cast(controller.convertToDensity(v111) - controller.convertToDensity(v110)); const Vector3DFloat v3dPosition(static_cast(uXRegSpace), static_cast(uYRegSpace), static_cast(uZRegSpace - 1) + fInterp); const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); @@ -212,7 +211,7 @@ namespace PolyVox } // Allow the controller to decide how the material should be derived from the voxels. - const typename VolumeType::VoxelType uMaterial = m_controller.blendMaterials(v110, v111, fInterp); + const typename VolumeType::VoxelType uMaterial = controller.blendMaterials(v110, v111, fInterp); MarchingCubesVertex surfaceVertex; surfaceVertex.encodedPosition = v3dScaledPosition; From 37db0bac52f3c67b753734b394cd7805819e56ca Mon Sep 17 00:00:00 2001 From: David Williams Date: Mon, 25 May 2015 21:16:29 +0200 Subject: [PATCH 44/61] Moved gradient calculation outside of class. --- .../PolyVox/MarchingCubesSurfaceExtractor.h | 31 ------------------- .../PolyVox/MarchingCubesSurfaceExtractor.inl | 23 ++++++++++++++ 2 files changed, 23 insertions(+), 31 deletions(-) diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.h b/include/PolyVox/MarchingCubesSurfaceExtractor.h index dde8acdf..ee6fd518 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.h +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.h @@ -156,37 +156,6 @@ namespace PolyVox MarchingCubesSurfaceExtractor(); void execute(VolumeType* volData, Region region, MeshType* result, ControllerType controller); - - private: - - //////////////////////////////////////////////////////////////////////////////// - // NOTE: These two functions are in the .h file rather than the .inl due to an apparent bug in VC2010. - //See http://stackoverflow.com/questions/1484885/strange-vc-compile-error-c2244 for details. - //////////////////////////////////////////////////////////////////////////////// - Vector3DFloat computeCentralDifferenceGradient(const typename VolumeType::Sampler& volIter, ControllerType& controller) - { - //FIXME - Should actually use DensityType here, both in principle and because the maths may be - //faster (and to reduce casts). So it would be good to add a way to get DensityType from a voxel. - //But watch out for when the DensityType is unsigned and the difference could be negative. - float voxel1nx = static_cast(controller.convertToDensity(volIter.peekVoxel1nx0py0pz())); - float voxel1px = static_cast(controller.convertToDensity(volIter.peekVoxel1px0py0pz())); - - float voxel1ny = static_cast(controller.convertToDensity(volIter.peekVoxel0px1ny0pz())); - float voxel1py = static_cast(controller.convertToDensity(volIter.peekVoxel0px1py0pz())); - - float voxel1nz = static_cast(controller.convertToDensity(volIter.peekVoxel0px0py1nz())); - float voxel1pz = static_cast(controller.convertToDensity(volIter.peekVoxel0px0py1pz())); - - return Vector3DFloat - ( - voxel1nx - voxel1px, - voxel1ny - voxel1py, - voxel1nz - voxel1pz - ); - } - //////////////////////////////////////////////////////////////////////////////// - // End of compiler bug workaroumd. - //////////////////////////////////////////////////////////////////////////////// }; // This version of the function performs the extraction into a user-provided mesh rather than allocating a mesh automatically. diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.inl b/include/PolyVox/MarchingCubesSurfaceExtractor.inl index e70b7374..0ed3d28d 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.inl +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.inl @@ -25,6 +25,29 @@ freely, subject to the following restrictions: namespace PolyVox { + template< typename Sampler, typename ControllerType> + Vector3DFloat computeCentralDifferenceGradient(const Sampler& volIter, ControllerType& controller) + { + //FIXME - Should actually use DensityType here, both in principle and because the maths may be + //faster (and to reduce casts). So it would be good to add a way to get DensityType from a voxel. + //But watch out for when the DensityType is unsigned and the difference could be negative. + float voxel1nx = static_cast(controller.convertToDensity(volIter.peekVoxel1nx0py0pz())); + float voxel1px = static_cast(controller.convertToDensity(volIter.peekVoxel1px0py0pz())); + + float voxel1ny = static_cast(controller.convertToDensity(volIter.peekVoxel0px1ny0pz())); + float voxel1py = static_cast(controller.convertToDensity(volIter.peekVoxel0px1py0pz())); + + float voxel1nz = static_cast(controller.convertToDensity(volIter.peekVoxel0px0py1nz())); + float voxel1pz = static_cast(controller.convertToDensity(volIter.peekVoxel0px0py1pz())); + + return Vector3DFloat + ( + voxel1nx - voxel1px, + voxel1ny - voxel1py, + voxel1nz - voxel1pz + ); + } + template MarchingCubesSurfaceExtractor::MarchingCubesSurfaceExtractor() { From 04c4e49aa19705ad03ddf9b117df818527c1736e Mon Sep 17 00:00:00 2001 From: David Williams Date: Mon, 25 May 2015 21:23:27 +0200 Subject: [PATCH 45/61] Fully eliminated MarchingCubesSurfaceExtractor class. It's now only a standalone function called 'extractMarchingCubesMesh'. --- include/PolyVox/MarchingCubesSurfaceExtractor.h | 16 +--------------- .../PolyVox/MarchingCubesSurfaceExtractor.inl | 9 ++------- include/PolyVox/PolyVoxForwardDeclarations.h | 5 ----- 3 files changed, 3 insertions(+), 27 deletions(-) diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.h b/include/PolyVox/MarchingCubesSurfaceExtractor.h index ee6fd518..0bd2df59 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.h +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.h @@ -148,16 +148,6 @@ namespace PolyVox return result; } - /// Do not use this class directly. Use the 'extractMarchingCubesSurface' function instead (see examples). - template< typename VolumeType, typename MeshType, typename ControllerType> - class MarchingCubesSurfaceExtractor - { - public: - MarchingCubesSurfaceExtractor(); - - void execute(VolumeType* volData, Region region, MeshType* result, ControllerType controller); - }; - // This version of the function performs the extraction into a user-provided mesh rather than allocating a mesh automatically. // There are a few reasons why this might be useful to more advanced users: // @@ -172,11 +162,7 @@ namespace PolyVox // are provided (would the third parameter be a controller or a mesh?). It seems this can be fixed by using enable_if/static_assert to emulate concepts, // but this is relatively complex and I haven't done it yet. Could always add it later as another overload. template< typename VolumeType, typename MeshType, typename ControllerType = DefaultMarchingCubesController > - void extractMarchingCubesMeshCustom(VolumeType* volData, Region region, MeshType* result, ControllerType controller = ControllerType()) - { - MarchingCubesSurfaceExtractor extractor; - extractor.execute(volData, region, result, controller); - } + void extractMarchingCubesMeshCustom(VolumeType* volData, Region region, MeshType* result, ControllerType controller = ControllerType()); template< typename VolumeType, typename ControllerType = DefaultMarchingCubesController > Mesh > extractMarchingCubesMesh(VolumeType* volData, Region region, ControllerType controller = ControllerType()) diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.inl b/include/PolyVox/MarchingCubesSurfaceExtractor.inl index 0ed3d28d..cc6b1c97 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.inl +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.inl @@ -48,13 +48,8 @@ namespace PolyVox ); } - template - MarchingCubesSurfaceExtractor::MarchingCubesSurfaceExtractor() - { - } - - template - void MarchingCubesSurfaceExtractor::execute(VolumeType* volData, Region region, MeshType* result, ControllerType controller) + template< typename VolumeType, typename MeshType, typename ControllerType > + void extractMarchingCubesMeshCustom(VolumeType* volData, Region region, MeshType* result, ControllerType controller) { POLYVOX_THROW_IF(result == nullptr, std::invalid_argument, "Provided mesh cannot be null"); diff --git a/include/PolyVox/PolyVoxForwardDeclarations.h b/include/PolyVox/PolyVoxForwardDeclarations.h index 9dbc44ca..c0c1f872 100644 --- a/include/PolyVox/PolyVoxForwardDeclarations.h +++ b/include/PolyVox/PolyVoxForwardDeclarations.h @@ -98,11 +98,6 @@ namespace PolyVox //////////////////////////////////////////////////////////////////////////////// template class FilePager; - //////////////////////////////////////////////////////////////////////////////// - // MarchingCubesSurfaceExtractor - //////////////////////////////////////////////////////////////////////////////// - template class MarchingCubesSurfaceExtractor; - //////////////////////////////////////////////////////////////////////////////// // MarchingCubesVertex //////////////////////////////////////////////////////////////////////////////// From 48a6929a7a43eb613296e31b7abfacee82888100 Mon Sep 17 00:00:00 2001 From: David Williams Date: Tue, 26 May 2015 21:24:38 +0200 Subject: [PATCH 46/61] Tidying up. --- .../PolyVox/MarchingCubesSurfaceExtractor.inl | 44 ++++++++++--------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.inl b/include/PolyVox/MarchingCubesSurfaceExtractor.inl index cc6b1c97..fed2561e 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.inl +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.inl @@ -134,26 +134,22 @@ namespace PolyVox /* Cube is entirely in/out of the surface */ if (edgeTable[iCubeIndex] != 0) { - - // These three might not have been sampled, as v111 is the only one we sample every iteration. - typename VolumeType::VoxelType v110 = sampler.peekVoxel0px0py1nz(); - typename VolumeType::VoxelType v101 = sampler.peekVoxel0px1ny0pz(); - typename VolumeType::VoxelType v011 = sampler.peekVoxel1nx0py0pz(); - + auto v111Density = controller.convertToDensity(v111); const Vector3DFloat n000 = computeCentralDifferenceGradient(sampler, controller); /* Find the vertices where the surface intersects the cube */ if ((edgeTable[iCubeIndex] & 64) && (uXRegSpace > 0)) { sampler.moveNegativeX(); - POLYVOX_ASSERT(v011 != v111, "Attempting to insert vertex between two voxels with the same value"); - const Vector3DFloat n100 = computeCentralDifferenceGradient(sampler, controller); - - const float fInterp = static_cast(tThreshold - controller.convertToDensity(v011)) / static_cast(controller.convertToDensity(v111) - controller.convertToDensity(v011)); + typename VolumeType::VoxelType v011 = sampler.getVoxel(); + auto v011Density = controller.convertToDensity(v011); + const float fInterp = static_cast(tThreshold - v011Density) / static_cast(v111Density - v011Density); + // Compute the position const Vector3DFloat v3dPosition(static_cast(uXRegSpace - 1) + fInterp, static_cast(uYRegSpace), static_cast(uZRegSpace)); - const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); + // Compute the normal + const Vector3DFloat n100 = computeCentralDifferenceGradient(sampler, controller); Vector3DFloat v3dNormal = (n100*fInterp) + (n000*(1 - fInterp)); // The gradient for a voxel can be zero (e.g. solid voxel surrounded by empty ones) and so @@ -167,6 +163,7 @@ namespace PolyVox const typename VolumeType::VoxelType uMaterial = controller.blendMaterials(v011, v111, fInterp); MarchingCubesVertex surfaceVertex; + const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); surfaceVertex.encodedPosition = v3dScaledPosition; surfaceVertex.encodedNormal = encodeNormal(v3dNormal); surfaceVertex.data = uMaterial; @@ -179,14 +176,15 @@ namespace PolyVox if ((edgeTable[iCubeIndex] & 32) && (uYRegSpace > 0)) { sampler.moveNegativeY(); - POLYVOX_ASSERT(v101 != v111, "Attempting to insert vertex between two voxels with the same value"); - const Vector3DFloat n010 = computeCentralDifferenceGradient(sampler, controller); - - const float fInterp = static_cast(tThreshold - controller.convertToDensity(v101)) / static_cast(controller.convertToDensity(v111) - controller.convertToDensity(v101)); + typename VolumeType::VoxelType v101 = sampler.getVoxel(); + auto v101Density = controller.convertToDensity(v101); + const float fInterp = static_cast(tThreshold - v101Density) / static_cast(v111Density - v101Density); + // Compute the position const Vector3DFloat v3dPosition(static_cast(uXRegSpace), static_cast(uYRegSpace - 1) + fInterp, static_cast(uZRegSpace)); - const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); + // Compute the normal + const Vector3DFloat n010 = computeCentralDifferenceGradient(sampler, controller); Vector3DFloat v3dNormal = (n010*fInterp) + (n000*(1 - fInterp)); // The gradient for a voxel can be zero (e.g. solid voxel surrounded by empty ones) and so @@ -200,6 +198,7 @@ namespace PolyVox const typename VolumeType::VoxelType uMaterial = controller.blendMaterials(v101, v111, fInterp); MarchingCubesVertex surfaceVertex; + const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); surfaceVertex.encodedPosition = v3dScaledPosition; surfaceVertex.encodedNormal = encodeNormal(v3dNormal); surfaceVertex.data = uMaterial; @@ -212,15 +211,17 @@ namespace PolyVox if ((edgeTable[iCubeIndex] & 1024) && (uZRegSpace > 0)) { sampler.moveNegativeZ(); - POLYVOX_ASSERT(v110 != v111, "Attempting to insert vertex between two voxels with the same value"); - const Vector3DFloat n001 = computeCentralDifferenceGradient(sampler, controller); - - const float fInterp = static_cast(tThreshold - controller.convertToDensity(v110)) / static_cast(controller.convertToDensity(v111) - controller.convertToDensity(v110)); + typename VolumeType::VoxelType v110 = sampler.getVoxel(); + auto v110Density = controller.convertToDensity(v110); + const float fInterp = static_cast(tThreshold - v110Density) / static_cast(v111Density - v110Density); + // Compute the position const Vector3DFloat v3dPosition(static_cast(uXRegSpace), static_cast(uYRegSpace), static_cast(uZRegSpace - 1) + fInterp); - const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); + // Compute the normal + const Vector3DFloat n001 = computeCentralDifferenceGradient(sampler, controller); Vector3DFloat v3dNormal = (n001*fInterp) + (n000*(1 - fInterp)); + // The gradient for a voxel can be zero (e.g. solid voxel surrounded by empty ones) and so // the interpolated normal can also be zero (e.g. a grid of alternating solid and empty voxels). if (v3dNormal.lengthSquared() > 0.000001f) @@ -232,6 +233,7 @@ namespace PolyVox const typename VolumeType::VoxelType uMaterial = controller.blendMaterials(v110, v111, fInterp); MarchingCubesVertex surfaceVertex; + const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); surfaceVertex.encodedPosition = v3dScaledPosition; surfaceVertex.encodedNormal = encodeNormal(v3dNormal); surfaceVertex.data = uMaterial; From baf5cf2cabb2d14ca73e4c5852285f17d1e8adec Mon Sep 17 00:00:00 2001 From: David Williams Date: Wed, 27 May 2015 07:25:04 +0200 Subject: [PATCH 47/61] Removed unneeded memsets. --- include/PolyVox/MarchingCubesSurfaceExtractor.inl | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.inl b/include/PolyVox/MarchingCubesSurfaceExtractor.inl index fed2561e..fffe2dfd 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.inl +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.inl @@ -62,19 +62,13 @@ namespace PolyVox const uint32_t uArrayHeight = region.getUpperY() - region.getLowerY() + 2; const uint32_t uArrayDepth = region.getUpperZ() - region.getLowerZ() + 2; - //For edge indices + // No need to clear memory because we only read from elements we have written to. Array3DInt32 pIndicesX(uArrayWidth, uArrayHeight, uArrayDepth); Array3DInt32 pIndicesY(uArrayWidth, uArrayHeight, uArrayDepth); Array3DInt32 pIndicesZ(uArrayWidth, uArrayHeight, uArrayDepth); - memset(pIndicesX.getRawData(), 0xff, pIndicesX.getNoOfElements() * 4); - memset(pIndicesY.getRawData(), 0xff, pIndicesY.getNoOfElements() * 4); - memset(pIndicesZ.getRawData(), 0xff, pIndicesZ.getNoOfElements() * 4); - Array2DUint8 pPreviousSliceBitmask(uArrayWidth, uArrayHeight); Array1DUint8 pPreviousRowBitmask(uArrayWidth); - memset(pPreviousSliceBitmask.getRawData(), 0x00, pPreviousSliceBitmask.getNoOfElements()); - memset(pPreviousRowBitmask.getRawData(), 0x00, pPreviousRowBitmask.getNoOfElements()); uint8_t uPreviousCell = 0; From ccedb0e294ade62d94f85d57321f0c8e1402c508 Mon Sep 17 00:00:00 2001 From: David Williams Date: Wed, 27 May 2015 22:55:36 +0200 Subject: [PATCH 48/61] Replaced separate arrays with arrays of vectors. --- .../PolyVox/MarchingCubesSurfaceExtractor.inl | 37 ++++++++++--------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.inl b/include/PolyVox/MarchingCubesSurfaceExtractor.inl index fffe2dfd..06982858 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.inl +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.inl @@ -63,9 +63,8 @@ namespace PolyVox const uint32_t uArrayDepth = region.getUpperZ() - region.getLowerZ() + 2; // No need to clear memory because we only read from elements we have written to. - Array3DInt32 pIndicesX(uArrayWidth, uArrayHeight, uArrayDepth); - Array3DInt32 pIndicesY(uArrayWidth, uArrayHeight, uArrayDepth); - Array3DInt32 pIndicesZ(uArrayWidth, uArrayHeight, uArrayDepth); + Array<2, Vector3DInt32> pIndices(uArrayWidth, uArrayHeight); + Array<2, Vector3DInt32> pPreviousIndices(uArrayWidth, uArrayHeight); Array2DUint8 pPreviousSliceBitmask(uArrayWidth, uArrayHeight); Array1DUint8 pPreviousRowBitmask(uArrayWidth); @@ -163,7 +162,7 @@ namespace PolyVox surfaceVertex.data = uMaterial; const uint32_t uLastVertexIndex = result->addVertex(surfaceVertex); - pIndicesX(uXRegSpace, uYRegSpace, uZRegSpace) = uLastVertexIndex; + pIndices(uXRegSpace, uYRegSpace).setX(uLastVertexIndex); sampler.movePositiveX(); } @@ -198,7 +197,7 @@ namespace PolyVox surfaceVertex.data = uMaterial; uint32_t uLastVertexIndex = result->addVertex(surfaceVertex); - pIndicesY(uXRegSpace, uYRegSpace, uZRegSpace) = uLastVertexIndex; + pIndices(uXRegSpace, uYRegSpace).setY(uLastVertexIndex); sampler.movePositiveY(); } @@ -233,7 +232,7 @@ namespace PolyVox surfaceVertex.data = uMaterial; const uint32_t uLastVertexIndex = result->addVertex(surfaceVertex); - pIndicesZ(uXRegSpace, uYRegSpace, uZRegSpace) = uLastVertexIndex; + pIndices(uXRegSpace, uYRegSpace).setZ(uLastVertexIndex); sampler.movePositiveZ(); } @@ -254,51 +253,51 @@ namespace PolyVox /* Find the vertices where the surface intersects the cube */ if (edgeTable[iCubeIndex] & 1) { - indlist[0] = pIndicesX(uXRegSpace, uYRegSpace - 1, uZRegSpace - 1); + indlist[0] = pPreviousIndices(uXRegSpace, uYRegSpace - 1).getX(); } if (edgeTable[iCubeIndex] & 2) { - indlist[1] = pIndicesY(uXRegSpace, uYRegSpace, uZRegSpace - 1); + indlist[1] = pPreviousIndices(uXRegSpace, uYRegSpace).getY(); } if (edgeTable[iCubeIndex] & 4) { - indlist[2] = pIndicesX(uXRegSpace, uYRegSpace, uZRegSpace - 1); + indlist[2] = pPreviousIndices(uXRegSpace, uYRegSpace).getX(); } if (edgeTable[iCubeIndex] & 8) { - indlist[3] = pIndicesY(uXRegSpace - 1, uYRegSpace, uZRegSpace - 1); + indlist[3] = pPreviousIndices(uXRegSpace - 1, uYRegSpace).getY(); } if (edgeTable[iCubeIndex] & 16) { - indlist[4] = pIndicesX(uXRegSpace, uYRegSpace - 1, uZRegSpace); + indlist[4] = pIndices(uXRegSpace, uYRegSpace - 1).getX(); } if (edgeTable[iCubeIndex] & 32) { - indlist[5] = pIndicesY(uXRegSpace, uYRegSpace, uZRegSpace); + indlist[5] = pIndices(uXRegSpace, uYRegSpace).getY(); } if (edgeTable[iCubeIndex] & 64) { - indlist[6] = pIndicesX(uXRegSpace, uYRegSpace, uZRegSpace); + indlist[6] = pIndices(uXRegSpace, uYRegSpace).getX(); } if (edgeTable[iCubeIndex] & 128) { - indlist[7] = pIndicesY(uXRegSpace - 1, uYRegSpace, uZRegSpace); + indlist[7] = pIndices(uXRegSpace - 1, uYRegSpace).getY(); } if (edgeTable[iCubeIndex] & 256) { - indlist[8] = pIndicesZ(uXRegSpace - 1, uYRegSpace - 1, uZRegSpace); + indlist[8] = pIndices(uXRegSpace - 1, uYRegSpace - 1).getZ(); } if (edgeTable[iCubeIndex] & 512) { - indlist[9] = pIndicesZ(uXRegSpace, uYRegSpace - 1, uZRegSpace); + indlist[9] = pIndices(uXRegSpace, uYRegSpace - 1).getZ(); } if (edgeTable[iCubeIndex] & 1024) { - indlist[10] = pIndicesZ(uXRegSpace, uYRegSpace, uZRegSpace); + indlist[10] = pIndices(uXRegSpace, uYRegSpace).getZ(); } if (edgeTable[iCubeIndex] & 2048) { - indlist[11] = pIndicesZ(uXRegSpace - 1, uYRegSpace, uZRegSpace); + indlist[11] = pIndices(uXRegSpace - 1, uYRegSpace).getZ(); } for (int i = 0; triTable[iCubeIndex][i] != -1; i += 3) @@ -320,6 +319,8 @@ namespace PolyVox startOfRow.movePositiveY(); } // For Y startOfSlice.movePositiveZ(); + + pIndices.swap(pPreviousIndices); } // For Z result->setOffset(region.getLowerCorner()); From edd1af14ca5a230743a5089254ba2cd982e84aee Mon Sep 17 00:00:00 2001 From: David Williams Date: Wed, 27 May 2015 22:57:48 +0200 Subject: [PATCH 49/61] Removed unnecessary setting of sampler position. --- include/PolyVox/MarchingCubesSurfaceExtractor.inl | 3 --- 1 file changed, 3 deletions(-) diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.inl b/include/PolyVox/MarchingCubesSurfaceExtractor.inl index 06982858..a585d7ee 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.inl +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.inl @@ -244,12 +244,9 @@ namespace PolyVox int32_t indlist[12]; - sampler.setPosition(iXVolSpace, iYVolSpace, iZVolSpace); - /* Cube is entirely in/out of the surface */ if (edgeTable[iCubeIndex] != 0) { - /* Find the vertices where the surface intersects the cube */ if (edgeTable[iCubeIndex] & 1) { From 6493e88d4cae53c42563dfabc1947f98a5900ddc Mon Sep 17 00:00:00 2001 From: David Williams Date: Wed, 27 May 2015 22:58:46 +0200 Subject: [PATCH 50/61] Removed unnecessary condition. --- .../PolyVox/MarchingCubesSurfaceExtractor.inl | 122 +++++++++--------- 1 file changed, 59 insertions(+), 63 deletions(-) diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.inl b/include/PolyVox/MarchingCubesSurfaceExtractor.inl index a585d7ee..6889fa76 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.inl +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.inl @@ -244,71 +244,67 @@ namespace PolyVox int32_t indlist[12]; - /* Cube is entirely in/out of the surface */ - if (edgeTable[iCubeIndex] != 0) + /* Find the vertices where the surface intersects the cube */ + if (edgeTable[iCubeIndex] & 1) { - /* Find the vertices where the surface intersects the cube */ - if (edgeTable[iCubeIndex] & 1) - { - indlist[0] = pPreviousIndices(uXRegSpace, uYRegSpace - 1).getX(); - } - if (edgeTable[iCubeIndex] & 2) - { - indlist[1] = pPreviousIndices(uXRegSpace, uYRegSpace).getY(); - } - if (edgeTable[iCubeIndex] & 4) - { - indlist[2] = pPreviousIndices(uXRegSpace, uYRegSpace).getX(); - } - if (edgeTable[iCubeIndex] & 8) - { - indlist[3] = pPreviousIndices(uXRegSpace - 1, uYRegSpace).getY(); - } - if (edgeTable[iCubeIndex] & 16) - { - indlist[4] = pIndices(uXRegSpace, uYRegSpace - 1).getX(); - } - if (edgeTable[iCubeIndex] & 32) - { - indlist[5] = pIndices(uXRegSpace, uYRegSpace).getY(); - } - if (edgeTable[iCubeIndex] & 64) - { - indlist[6] = pIndices(uXRegSpace, uYRegSpace).getX(); - } - if (edgeTable[iCubeIndex] & 128) - { - indlist[7] = pIndices(uXRegSpace - 1, uYRegSpace).getY(); - } - if (edgeTable[iCubeIndex] & 256) - { - indlist[8] = pIndices(uXRegSpace - 1, uYRegSpace - 1).getZ(); - } - if (edgeTable[iCubeIndex] & 512) - { - indlist[9] = pIndices(uXRegSpace, uYRegSpace - 1).getZ(); - } - if (edgeTable[iCubeIndex] & 1024) - { - indlist[10] = pIndices(uXRegSpace, uYRegSpace).getZ(); - } - if (edgeTable[iCubeIndex] & 2048) - { - indlist[11] = pIndices(uXRegSpace - 1, uYRegSpace).getZ(); - } - - for (int i = 0; triTable[iCubeIndex][i] != -1; i += 3) - { - const int32_t ind0 = indlist[triTable[iCubeIndex][i]]; - const int32_t ind1 = indlist[triTable[iCubeIndex][i + 1]]; - const int32_t ind2 = indlist[triTable[iCubeIndex][i + 2]]; - - if ((ind0 != -1) && (ind1 != -1) && (ind2 != -1)) - { - result->addTriangle(ind0, ind1, ind2); - } - } // For each triangle + indlist[0] = pPreviousIndices(uXRegSpace, uYRegSpace - 1).getX(); } + if (edgeTable[iCubeIndex] & 2) + { + indlist[1] = pPreviousIndices(uXRegSpace, uYRegSpace).getY(); + } + if (edgeTable[iCubeIndex] & 4) + { + indlist[2] = pPreviousIndices(uXRegSpace, uYRegSpace).getX(); + } + if (edgeTable[iCubeIndex] & 8) + { + indlist[3] = pPreviousIndices(uXRegSpace - 1, uYRegSpace).getY(); + } + if (edgeTable[iCubeIndex] & 16) + { + indlist[4] = pIndices(uXRegSpace, uYRegSpace - 1).getX(); + } + if (edgeTable[iCubeIndex] & 32) + { + indlist[5] = pIndices(uXRegSpace, uYRegSpace).getY(); + } + if (edgeTable[iCubeIndex] & 64) + { + indlist[6] = pIndices(uXRegSpace, uYRegSpace).getX(); + } + if (edgeTable[iCubeIndex] & 128) + { + indlist[7] = pIndices(uXRegSpace - 1, uYRegSpace).getY(); + } + if (edgeTable[iCubeIndex] & 256) + { + indlist[8] = pIndices(uXRegSpace - 1, uYRegSpace - 1).getZ(); + } + if (edgeTable[iCubeIndex] & 512) + { + indlist[9] = pIndices(uXRegSpace, uYRegSpace - 1).getZ(); + } + if (edgeTable[iCubeIndex] & 1024) + { + indlist[10] = pIndices(uXRegSpace, uYRegSpace).getZ(); + } + if (edgeTable[iCubeIndex] & 2048) + { + indlist[11] = pIndices(uXRegSpace - 1, uYRegSpace).getZ(); + } + + for (int i = 0; triTable[iCubeIndex][i] != -1; i += 3) + { + const int32_t ind0 = indlist[triTable[iCubeIndex][i]]; + const int32_t ind1 = indlist[triTable[iCubeIndex][i + 1]]; + const int32_t ind2 = indlist[triTable[iCubeIndex][i + 2]]; + + if ((ind0 != -1) && (ind1 != -1) && (ind2 != -1)) + { + result->addTriangle(ind0, ind1, ind2); + } + } // For each triangle } } // For each cell sampler.movePositiveX(); From ac7bec0c45c89db1f2ed7335c5ccb26029a5bcc2 Mon Sep 17 00:00:00 2001 From: David Williams Date: Thu, 28 May 2015 21:46:50 +0200 Subject: [PATCH 51/61] Eliminated unused variables. --- include/PolyVox/MarchingCubesSurfaceExtractor.inl | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.inl b/include/PolyVox/MarchingCubesSurfaceExtractor.inl index 6889fa76..930885cb 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.inl +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.inl @@ -74,24 +74,18 @@ namespace PolyVox typename VolumeType::Sampler startOfSlice(volData); startOfSlice.setPosition(region.getLowerX(), region.getLowerY(), region.getLowerZ()); - for (int32_t iZVolSpace = region.getLowerZ(); iZVolSpace <= region.getUpperZ(); iZVolSpace++) + for (int32_t uZRegSpace = 0; uZRegSpace < region.getDepthInVoxels(); uZRegSpace++) { - const uint32_t uZRegSpace = iZVolSpace - region.getLowerZ(); - typename VolumeType::Sampler startOfRow = startOfSlice; - for (int32_t iYVolSpace = region.getLowerY(); iYVolSpace <= region.getUpperY(); iYVolSpace++) + for (int32_t uYRegSpace = 0; uYRegSpace < region.getHeightInVoxels(); uYRegSpace++) { - const uint32_t uYRegSpace = iYVolSpace - region.getLowerY(); - // Copying a sampler which is already pointing at the correct location seems (slightly) faster than // calling setPosition(). Therefore we make use of 'startOfRow' and 'startOfSlice' to reset the sampler. typename VolumeType::Sampler sampler = startOfRow; - for (int32_t iXVolSpace = region.getLowerX(); iXVolSpace <= region.getUpperX(); iXVolSpace++) + for (int32_t uXRegSpace = 0; uXRegSpace < region.getWidthInVoxels(); uXRegSpace++) { - const uint32_t uXRegSpace = iXVolSpace - region.getLowerX(); - uint8_t iCubeIndex = 0; // Four bits of our cube index are obtained by looking at the cube index for From 68bdd9ca99cfd8919414acaa7a6d14aa178fa963 Mon Sep 17 00:00:00 2001 From: David Williams Date: Thu, 28 May 2015 21:51:57 +0200 Subject: [PATCH 52/61] Tidying up. --- .../PolyVox/MarchingCubesSurfaceExtractor.inl | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.inl b/include/PolyVox/MarchingCubesSurfaceExtractor.inl index 930885cb..1b1672d6 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.inl +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.inl @@ -53,38 +53,38 @@ namespace PolyVox { POLYVOX_THROW_IF(result == nullptr, std::invalid_argument, "Provided mesh cannot be null"); - typename ControllerType::DensityType tThreshold = controller.getThreshold(); - Timer timer; result->clear(); - const uint32_t uArrayWidth = region.getUpperX() - region.getLowerX() + 2; - const uint32_t uArrayHeight = region.getUpperY() - region.getLowerY() + 2; - const uint32_t uArrayDepth = region.getUpperZ() - region.getLowerZ() + 2; + typename ControllerType::DensityType tThreshold = controller.getThreshold(); + + const uint32_t uRegionWidthInVoxels = region.getWidthInVoxels(); + const uint32_t uRegionHeightInVoxels = region.getHeightInVoxels(); + const uint32_t uRegionDepthInVoxels = region.getDepthInVoxels(); // No need to clear memory because we only read from elements we have written to. - Array<2, Vector3DInt32> pIndices(uArrayWidth, uArrayHeight); - Array<2, Vector3DInt32> pPreviousIndices(uArrayWidth, uArrayHeight); + Array<2, Vector3DInt32> pIndices(uRegionWidthInVoxels, uRegionHeightInVoxels); + Array<2, Vector3DInt32> pPreviousIndices(uRegionWidthInVoxels, uRegionHeightInVoxels); - Array2DUint8 pPreviousSliceBitmask(uArrayWidth, uArrayHeight); - Array1DUint8 pPreviousRowBitmask(uArrayWidth); + Array2DUint8 pPreviousSliceBitmask(uRegionWidthInVoxels, uRegionHeightInVoxels); + Array1DUint8 pPreviousRowBitmask(uRegionWidthInVoxels); uint8_t uPreviousCell = 0; typename VolumeType::Sampler startOfSlice(volData); startOfSlice.setPosition(region.getLowerX(), region.getLowerY(), region.getLowerZ()); - for (int32_t uZRegSpace = 0; uZRegSpace < region.getDepthInVoxels(); uZRegSpace++) + for (int32_t uZRegSpace = 0; uZRegSpace < uRegionDepthInVoxels; uZRegSpace++) { typename VolumeType::Sampler startOfRow = startOfSlice; - for (int32_t uYRegSpace = 0; uYRegSpace < region.getHeightInVoxels(); uYRegSpace++) + for (int32_t uYRegSpace = 0; uYRegSpace < uRegionHeightInVoxels; uYRegSpace++) { // Copying a sampler which is already pointing at the correct location seems (slightly) faster than // calling setPosition(). Therefore we make use of 'startOfRow' and 'startOfSlice' to reset the sampler. typename VolumeType::Sampler sampler = startOfRow; - for (int32_t uXRegSpace = 0; uXRegSpace < region.getWidthInVoxels(); uXRegSpace++) + for (int32_t uXRegSpace = 0; uXRegSpace < uRegionWidthInVoxels; uXRegSpace++) { uint8_t iCubeIndex = 0; From 01963bd4627d786a8d24899ff186cc57965c8595 Mon Sep 17 00:00:00 2001 From: David Williams Date: Thu, 28 May 2015 22:37:05 +0200 Subject: [PATCH 53/61] Added comment about performance. --- include/PolyVox/MarchingCubesSurfaceExtractor.inl | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.inl b/include/PolyVox/MarchingCubesSurfaceExtractor.inl index 1b1672d6..57ff044e 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.inl +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.inl @@ -86,6 +86,16 @@ namespace PolyVox for (int32_t uXRegSpace = 0; uXRegSpace < uRegionWidthInVoxels; uXRegSpace++) { + // Note: In many cases the provided region will be (mostly) empty which means mesh vertices/indices + // are not generated and the only thing that is done for each cell is the computation of iCubeIndex. + // It appears that retriving the voxel value is not so expensive and that it is the bitwise combining + // which actually carries the cost. + // + // If we really need to speed this up more then it may be possible to pack 4 8-bit cell indices into + // a single 32-bit value and then perform the bitwise logic on all four of them at the same time. + // However, this complicates the code and there would still be the cost of packing/unpacking so it's + // not clear if there is really a benefit. It's something to consider in the future. + uint8_t iCubeIndex = 0; // Four bits of our cube index are obtained by looking at the cube index for From 92db00625072e7c7870ed27a6b12539533c69f72 Mon Sep 17 00:00:00 2001 From: David Williams Date: Thu, 28 May 2015 22:40:25 +0200 Subject: [PATCH 54/61] Fixed compile warnings. --- include/PolyVox/MarchingCubesSurfaceExtractor.inl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.inl b/include/PolyVox/MarchingCubesSurfaceExtractor.inl index 57ff044e..df5be386 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.inl +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.inl @@ -74,17 +74,17 @@ namespace PolyVox typename VolumeType::Sampler startOfSlice(volData); startOfSlice.setPosition(region.getLowerX(), region.getLowerY(), region.getLowerZ()); - for (int32_t uZRegSpace = 0; uZRegSpace < uRegionDepthInVoxels; uZRegSpace++) + for (uint32_t uZRegSpace = 0; uZRegSpace < uRegionDepthInVoxels; uZRegSpace++) { typename VolumeType::Sampler startOfRow = startOfSlice; - for (int32_t uYRegSpace = 0; uYRegSpace < uRegionHeightInVoxels; uYRegSpace++) + for (uint32_t uYRegSpace = 0; uYRegSpace < uRegionHeightInVoxels; uYRegSpace++) { // Copying a sampler which is already pointing at the correct location seems (slightly) faster than // calling setPosition(). Therefore we make use of 'startOfRow' and 'startOfSlice' to reset the sampler. typename VolumeType::Sampler sampler = startOfRow; - for (int32_t uXRegSpace = 0; uXRegSpace < uRegionWidthInVoxels; uXRegSpace++) + for (uint32_t uXRegSpace = 0; uXRegSpace < uRegionWidthInVoxels; uXRegSpace++) { // Note: In many cases the provided region will be (mostly) empty which means mesh vertices/indices // are not generated and the only thing that is done for each cell is the computation of iCubeIndex. From f32bb1d1ed59adf1449c99d953e7afc356c68168 Mon Sep 17 00:00:00 2001 From: David Williams Date: Thu, 28 May 2015 23:02:14 +0200 Subject: [PATCH 55/61] Reduced array accesses. --- .../PolyVox/MarchingCubesSurfaceExtractor.inl | 33 ++++++++++--------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.inl b/include/PolyVox/MarchingCubesSurfaceExtractor.inl index df5be386..b812d250 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.inl +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.inl @@ -129,13 +129,14 @@ namespace PolyVox pPreviousSliceBitmask(uXRegSpace, uYRegSpace) = iCubeIndex; /* Cube is entirely in/out of the surface */ - if (edgeTable[iCubeIndex] != 0) + uint16_t uEdge = edgeTable[iCubeIndex]; + if (uEdge != 0) { auto v111Density = controller.convertToDensity(v111); const Vector3DFloat n000 = computeCentralDifferenceGradient(sampler, controller); /* Find the vertices where the surface intersects the cube */ - if ((edgeTable[iCubeIndex] & 64) && (uXRegSpace > 0)) + if ((uEdge & 64) && (uXRegSpace > 0)) { sampler.moveNegativeX(); typename VolumeType::VoxelType v011 = sampler.getVoxel(); @@ -170,7 +171,7 @@ namespace PolyVox sampler.movePositiveX(); } - if ((edgeTable[iCubeIndex] & 32) && (uYRegSpace > 0)) + if ((uEdge & 32) && (uYRegSpace > 0)) { sampler.moveNegativeY(); typename VolumeType::VoxelType v101 = sampler.getVoxel(); @@ -205,7 +206,7 @@ namespace PolyVox sampler.movePositiveY(); } - if ((edgeTable[iCubeIndex] & 1024) && (uZRegSpace > 0)) + if ((uEdge & 1024) && (uZRegSpace > 0)) { sampler.moveNegativeZ(); typename VolumeType::VoxelType v110 = sampler.getVoxel(); @@ -249,51 +250,51 @@ namespace PolyVox int32_t indlist[12]; /* Find the vertices where the surface intersects the cube */ - if (edgeTable[iCubeIndex] & 1) + if (uEdge & 1) { indlist[0] = pPreviousIndices(uXRegSpace, uYRegSpace - 1).getX(); } - if (edgeTable[iCubeIndex] & 2) + if (uEdge & 2) { indlist[1] = pPreviousIndices(uXRegSpace, uYRegSpace).getY(); } - if (edgeTable[iCubeIndex] & 4) + if (uEdge & 4) { indlist[2] = pPreviousIndices(uXRegSpace, uYRegSpace).getX(); } - if (edgeTable[iCubeIndex] & 8) + if (uEdge & 8) { indlist[3] = pPreviousIndices(uXRegSpace - 1, uYRegSpace).getY(); } - if (edgeTable[iCubeIndex] & 16) + if (uEdge & 16) { indlist[4] = pIndices(uXRegSpace, uYRegSpace - 1).getX(); } - if (edgeTable[iCubeIndex] & 32) + if (uEdge & 32) { indlist[5] = pIndices(uXRegSpace, uYRegSpace).getY(); } - if (edgeTable[iCubeIndex] & 64) + if (uEdge & 64) { indlist[6] = pIndices(uXRegSpace, uYRegSpace).getX(); } - if (edgeTable[iCubeIndex] & 128) + if (uEdge & 128) { indlist[7] = pIndices(uXRegSpace - 1, uYRegSpace).getY(); } - if (edgeTable[iCubeIndex] & 256) + if (uEdge & 256) { indlist[8] = pIndices(uXRegSpace - 1, uYRegSpace - 1).getZ(); } - if (edgeTable[iCubeIndex] & 512) + if (uEdge & 512) { indlist[9] = pIndices(uXRegSpace, uYRegSpace - 1).getZ(); } - if (edgeTable[iCubeIndex] & 1024) + if (uEdge & 1024) { indlist[10] = pIndices(uXRegSpace, uYRegSpace).getZ(); } - if (edgeTable[iCubeIndex] & 2048) + if (uEdge & 2048) { indlist[11] = pIndices(uXRegSpace - 1, uYRegSpace).getZ(); } From 2fa291d16f13adf039dc4fa636bfccde52377989 Mon Sep 17 00:00:00 2001 From: David Williams Date: Thu, 28 May 2015 23:26:50 +0200 Subject: [PATCH 56/61] Split the code which generates vertices and indices for a single cell into a separate function. --- .../PolyVox/MarchingCubesSurfaceExtractor.inl | 378 +++++++++--------- 1 file changed, 196 insertions(+), 182 deletions(-) diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.inl b/include/PolyVox/MarchingCubesSurfaceExtractor.inl index b812d250..08564a35 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.inl +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.inl @@ -48,6 +48,192 @@ namespace PolyVox ); } + template< typename VolumeType, typename MeshType, typename ControllerType > + void generateMeshForCell(Region& region, MeshType* result, ControllerType& controller, typename VolumeType::Sampler& sampler, Array<2, Vector3DInt32>& pIndices, Array<2, Vector3DInt32>& pPreviousIndices, uint8_t iCubeIndex, uint32_t uXRegSpace, uint32_t uYRegSpace, uint32_t uZRegSpace, typename ControllerType::DensityType tThreshold) + { + auto v111 = sampler.getVoxel(); + auto v111Density = controller.convertToDensity(v111); + const Vector3DFloat n000 = computeCentralDifferenceGradient(sampler, controller); + + uint16_t uEdge = edgeTable[iCubeIndex]; + /* Find the vertices where the surface intersects the cube */ + if ((uEdge & 64) && (uXRegSpace > 0)) + { + sampler.moveNegativeX(); + typename VolumeType::VoxelType v011 = sampler.getVoxel(); + auto v011Density = controller.convertToDensity(v011); + const float fInterp = static_cast(tThreshold - v011Density) / static_cast(v111Density - v011Density); + + // Compute the position + const Vector3DFloat v3dPosition(static_cast(uXRegSpace - 1) + fInterp, static_cast(uYRegSpace), static_cast(uZRegSpace)); + + // Compute the normal + const Vector3DFloat n100 = computeCentralDifferenceGradient(sampler, controller); + Vector3DFloat v3dNormal = (n100*fInterp) + (n000*(1 - fInterp)); + + // The gradient for a voxel can be zero (e.g. solid voxel surrounded by empty ones) and so + // the interpolated normal can also be zero (e.g. a grid of alternating solid and empty voxels). + if (v3dNormal.lengthSquared() > 0.000001f) + { + v3dNormal.normalise(); + } + + // Allow the controller to decide how the material should be derived from the voxels. + const typename VolumeType::VoxelType uMaterial = controller.blendMaterials(v011, v111, fInterp); + + MarchingCubesVertex surfaceVertex; + const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); + surfaceVertex.encodedPosition = v3dScaledPosition; + surfaceVertex.encodedNormal = encodeNormal(v3dNormal); + surfaceVertex.data = uMaterial; + + const uint32_t uLastVertexIndex = result->addVertex(surfaceVertex); + pIndices(uXRegSpace, uYRegSpace).setX(uLastVertexIndex); + + sampler.movePositiveX(); + } + if ((uEdge & 32) && (uYRegSpace > 0)) + { + sampler.moveNegativeY(); + typename VolumeType::VoxelType v101 = sampler.getVoxel(); + auto v101Density = controller.convertToDensity(v101); + const float fInterp = static_cast(tThreshold - v101Density) / static_cast(v111Density - v101Density); + + // Compute the position + const Vector3DFloat v3dPosition(static_cast(uXRegSpace), static_cast(uYRegSpace - 1) + fInterp, static_cast(uZRegSpace)); + + // Compute the normal + const Vector3DFloat n010 = computeCentralDifferenceGradient(sampler, controller); + Vector3DFloat v3dNormal = (n010*fInterp) + (n000*(1 - fInterp)); + + // The gradient for a voxel can be zero (e.g. solid voxel surrounded by empty ones) and so + // the interpolated normal can also be zero (e.g. a grid of alternating solid and empty voxels). + if (v3dNormal.lengthSquared() > 0.000001f) + { + v3dNormal.normalise(); + } + + // Allow the controller to decide how the material should be derived from the voxels. + const typename VolumeType::VoxelType uMaterial = controller.blendMaterials(v101, v111, fInterp); + + MarchingCubesVertex surfaceVertex; + const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); + surfaceVertex.encodedPosition = v3dScaledPosition; + surfaceVertex.encodedNormal = encodeNormal(v3dNormal); + surfaceVertex.data = uMaterial; + + uint32_t uLastVertexIndex = result->addVertex(surfaceVertex); + pIndices(uXRegSpace, uYRegSpace).setY(uLastVertexIndex); + + sampler.movePositiveY(); + } + if ((uEdge & 1024) && (uZRegSpace > 0)) + { + sampler.moveNegativeZ(); + typename VolumeType::VoxelType v110 = sampler.getVoxel(); + auto v110Density = controller.convertToDensity(v110); + const float fInterp = static_cast(tThreshold - v110Density) / static_cast(v111Density - v110Density); + + // Compute the position + const Vector3DFloat v3dPosition(static_cast(uXRegSpace), static_cast(uYRegSpace), static_cast(uZRegSpace - 1) + fInterp); + + // Compute the normal + const Vector3DFloat n001 = computeCentralDifferenceGradient(sampler, controller); + Vector3DFloat v3dNormal = (n001*fInterp) + (n000*(1 - fInterp)); + + // The gradient for a voxel can be zero (e.g. solid voxel surrounded by empty ones) and so + // the interpolated normal can also be zero (e.g. a grid of alternating solid and empty voxels). + if (v3dNormal.lengthSquared() > 0.000001f) + { + v3dNormal.normalise(); + } + + // Allow the controller to decide how the material should be derived from the voxels. + const typename VolumeType::VoxelType uMaterial = controller.blendMaterials(v110, v111, fInterp); + + MarchingCubesVertex surfaceVertex; + const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); + surfaceVertex.encodedPosition = v3dScaledPosition; + surfaceVertex.encodedNormal = encodeNormal(v3dNormal); + surfaceVertex.data = uMaterial; + + const uint32_t uLastVertexIndex = result->addVertex(surfaceVertex); + pIndices(uXRegSpace, uYRegSpace).setZ(uLastVertexIndex); + + sampler.movePositiveZ(); + } + + // Now output the indices. For the first row, column or slice there aren't + // any (the region size in cells is one less than the region size in voxels) + if ((uXRegSpace != 0) && (uYRegSpace != 0) && (uZRegSpace != 0)) + { + + int32_t indlist[12]; + + /* Find the vertices where the surface intersects the cube */ + if (uEdge & 1) + { + indlist[0] = pPreviousIndices(uXRegSpace, uYRegSpace - 1).getX(); + } + if (uEdge & 2) + { + indlist[1] = pPreviousIndices(uXRegSpace, uYRegSpace).getY(); + } + if (uEdge & 4) + { + indlist[2] = pPreviousIndices(uXRegSpace, uYRegSpace).getX(); + } + if (uEdge & 8) + { + indlist[3] = pPreviousIndices(uXRegSpace - 1, uYRegSpace).getY(); + } + if (uEdge & 16) + { + indlist[4] = pIndices(uXRegSpace, uYRegSpace - 1).getX(); + } + if (uEdge & 32) + { + indlist[5] = pIndices(uXRegSpace, uYRegSpace).getY(); + } + if (uEdge & 64) + { + indlist[6] = pIndices(uXRegSpace, uYRegSpace).getX(); + } + if (uEdge & 128) + { + indlist[7] = pIndices(uXRegSpace - 1, uYRegSpace).getY(); + } + if (uEdge & 256) + { + indlist[8] = pIndices(uXRegSpace - 1, uYRegSpace - 1).getZ(); + } + if (uEdge & 512) + { + indlist[9] = pIndices(uXRegSpace, uYRegSpace - 1).getZ(); + } + if (uEdge & 1024) + { + indlist[10] = pIndices(uXRegSpace, uYRegSpace).getZ(); + } + if (uEdge & 2048) + { + indlist[11] = pIndices(uXRegSpace - 1, uYRegSpace).getZ(); + } + + for (int i = 0; triTable[iCubeIndex][i] != -1; i += 3) + { + const int32_t ind0 = indlist[triTable[iCubeIndex][i]]; + const int32_t ind1 = indlist[triTable[iCubeIndex][i + 1]]; + const int32_t ind2 = indlist[triTable[iCubeIndex][i + 2]]; + + if ((ind0 != -1) && (ind1 != -1) && (ind2 != -1)) + { + result->addTriangle(ind0, ind1, ind2); + } + } // For each triangle + } + } + template< typename VolumeType, typename MeshType, typename ControllerType > void extractMarchingCubesMeshCustom(VolumeType* volData, Region region, MeshType* result, ControllerType controller) { @@ -128,189 +314,17 @@ namespace PolyVox pPreviousRowBitmask(uXRegSpace) = iCubeIndex; pPreviousSliceBitmask(uXRegSpace, uYRegSpace) = iCubeIndex; - /* Cube is entirely in/out of the surface */ - uint16_t uEdge = edgeTable[iCubeIndex]; - if (uEdge != 0) + /* Cube is entirely in/out of the surface */ + if (edgeTable[iCubeIndex] != 0) { - auto v111Density = controller.convertToDensity(v111); - const Vector3DFloat n000 = computeCentralDifferenceGradient(sampler, controller); - - /* Find the vertices where the surface intersects the cube */ - if ((uEdge & 64) && (uXRegSpace > 0)) - { - sampler.moveNegativeX(); - typename VolumeType::VoxelType v011 = sampler.getVoxel(); - auto v011Density = controller.convertToDensity(v011); - const float fInterp = static_cast(tThreshold - v011Density) / static_cast(v111Density - v011Density); - - // Compute the position - const Vector3DFloat v3dPosition(static_cast(uXRegSpace - 1) + fInterp, static_cast(uYRegSpace), static_cast(uZRegSpace)); - - // Compute the normal - const Vector3DFloat n100 = computeCentralDifferenceGradient(sampler, controller); - Vector3DFloat v3dNormal = (n100*fInterp) + (n000*(1 - fInterp)); - - // The gradient for a voxel can be zero (e.g. solid voxel surrounded by empty ones) and so - // the interpolated normal can also be zero (e.g. a grid of alternating solid and empty voxels). - if (v3dNormal.lengthSquared() > 0.000001f) - { - v3dNormal.normalise(); - } - - // Allow the controller to decide how the material should be derived from the voxels. - const typename VolumeType::VoxelType uMaterial = controller.blendMaterials(v011, v111, fInterp); - - MarchingCubesVertex surfaceVertex; - const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); - surfaceVertex.encodedPosition = v3dScaledPosition; - surfaceVertex.encodedNormal = encodeNormal(v3dNormal); - surfaceVertex.data = uMaterial; - - const uint32_t uLastVertexIndex = result->addVertex(surfaceVertex); - pIndices(uXRegSpace, uYRegSpace).setX(uLastVertexIndex); - - sampler.movePositiveX(); - } - if ((uEdge & 32) && (uYRegSpace > 0)) - { - sampler.moveNegativeY(); - typename VolumeType::VoxelType v101 = sampler.getVoxel(); - auto v101Density = controller.convertToDensity(v101); - const float fInterp = static_cast(tThreshold - v101Density) / static_cast(v111Density - v101Density); - - // Compute the position - const Vector3DFloat v3dPosition(static_cast(uXRegSpace), static_cast(uYRegSpace - 1) + fInterp, static_cast(uZRegSpace)); - - // Compute the normal - const Vector3DFloat n010 = computeCentralDifferenceGradient(sampler, controller); - Vector3DFloat v3dNormal = (n010*fInterp) + (n000*(1 - fInterp)); - - // The gradient for a voxel can be zero (e.g. solid voxel surrounded by empty ones) and so - // the interpolated normal can also be zero (e.g. a grid of alternating solid and empty voxels). - if (v3dNormal.lengthSquared() > 0.000001f) - { - v3dNormal.normalise(); - } - - // Allow the controller to decide how the material should be derived from the voxels. - const typename VolumeType::VoxelType uMaterial = controller.blendMaterials(v101, v111, fInterp); - - MarchingCubesVertex surfaceVertex; - const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); - surfaceVertex.encodedPosition = v3dScaledPosition; - surfaceVertex.encodedNormal = encodeNormal(v3dNormal); - surfaceVertex.data = uMaterial; - - uint32_t uLastVertexIndex = result->addVertex(surfaceVertex); - pIndices(uXRegSpace, uYRegSpace).setY(uLastVertexIndex); - - sampler.movePositiveY(); - } - if ((uEdge & 1024) && (uZRegSpace > 0)) - { - sampler.moveNegativeZ(); - typename VolumeType::VoxelType v110 = sampler.getVoxel(); - auto v110Density = controller.convertToDensity(v110); - const float fInterp = static_cast(tThreshold - v110Density) / static_cast(v111Density - v110Density); - - // Compute the position - const Vector3DFloat v3dPosition(static_cast(uXRegSpace), static_cast(uYRegSpace), static_cast(uZRegSpace - 1) + fInterp); - - // Compute the normal - const Vector3DFloat n001 = computeCentralDifferenceGradient(sampler, controller); - Vector3DFloat v3dNormal = (n001*fInterp) + (n000*(1 - fInterp)); - - // The gradient for a voxel can be zero (e.g. solid voxel surrounded by empty ones) and so - // the interpolated normal can also be zero (e.g. a grid of alternating solid and empty voxels). - if (v3dNormal.lengthSquared() > 0.000001f) - { - v3dNormal.normalise(); - } - - // Allow the controller to decide how the material should be derived from the voxels. - const typename VolumeType::VoxelType uMaterial = controller.blendMaterials(v110, v111, fInterp); - - MarchingCubesVertex surfaceVertex; - const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); - surfaceVertex.encodedPosition = v3dScaledPosition; - surfaceVertex.encodedNormal = encodeNormal(v3dNormal); - surfaceVertex.data = uMaterial; - - const uint32_t uLastVertexIndex = result->addVertex(surfaceVertex); - pIndices(uXRegSpace, uYRegSpace).setZ(uLastVertexIndex); - - sampler.movePositiveZ(); - } - - // Now output the indices. For the first row, column or slice there aren't - // any (the region size in cells is one less than the region size in voxels) - if ((uXRegSpace != 0) && (uYRegSpace != 0) && (uZRegSpace != 0)) - { - - int32_t indlist[12]; - - /* Find the vertices where the surface intersects the cube */ - if (uEdge & 1) - { - indlist[0] = pPreviousIndices(uXRegSpace, uYRegSpace - 1).getX(); - } - if (uEdge & 2) - { - indlist[1] = pPreviousIndices(uXRegSpace, uYRegSpace).getY(); - } - if (uEdge & 4) - { - indlist[2] = pPreviousIndices(uXRegSpace, uYRegSpace).getX(); - } - if (uEdge & 8) - { - indlist[3] = pPreviousIndices(uXRegSpace - 1, uYRegSpace).getY(); - } - if (uEdge & 16) - { - indlist[4] = pIndices(uXRegSpace, uYRegSpace - 1).getX(); - } - if (uEdge & 32) - { - indlist[5] = pIndices(uXRegSpace, uYRegSpace).getY(); - } - if (uEdge & 64) - { - indlist[6] = pIndices(uXRegSpace, uYRegSpace).getX(); - } - if (uEdge & 128) - { - indlist[7] = pIndices(uXRegSpace - 1, uYRegSpace).getY(); - } - if (uEdge & 256) - { - indlist[8] = pIndices(uXRegSpace - 1, uYRegSpace - 1).getZ(); - } - if (uEdge & 512) - { - indlist[9] = pIndices(uXRegSpace, uYRegSpace - 1).getZ(); - } - if (uEdge & 1024) - { - indlist[10] = pIndices(uXRegSpace, uYRegSpace).getZ(); - } - if (uEdge & 2048) - { - indlist[11] = pIndices(uXRegSpace - 1, uYRegSpace).getZ(); - } - - for (int i = 0; triTable[iCubeIndex][i] != -1; i += 3) - { - const int32_t ind0 = indlist[triTable[iCubeIndex][i]]; - const int32_t ind1 = indlist[triTable[iCubeIndex][i + 1]]; - const int32_t ind2 = indlist[triTable[iCubeIndex][i + 2]]; - - if ((ind0 != -1) && (ind1 != -1) && (ind2 != -1)) - { - result->addTriangle(ind0, ind1, ind2); - } - } // For each triangle - } + // This is a rather ugly function call and appears to have some cost compared to inlining the code. + // As a result the case when a cell contains vertices/indices is slightly slower, but the (more common) + // case where a cell is empty is slightly faster, probably because the main loop is a lot more compact. + // Having a seperate function will also make it easier to profile in the future and see whether empty or + // occupied cells are really the bottleneck. The large number of parameters is messy though, so it + // would be nice to reduce these if we can work out how. + generateMeshForCell(region, result, controller, + sampler, pIndices, pPreviousIndices, iCubeIndex, uXRegSpace, uYRegSpace, uZRegSpace, tThreshold); } // For each cell sampler.movePositiveX(); } // For X From ebab89b9adac576b0d20fd8cbacf0154e7e74fe4 Mon Sep 17 00:00:00 2001 From: David Williams Date: Thu, 28 May 2015 23:42:50 +0200 Subject: [PATCH 57/61] Passing sampled voxel. --- include/PolyVox/MarchingCubesSurfaceExtractor.inl | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.inl b/include/PolyVox/MarchingCubesSurfaceExtractor.inl index 08564a35..9dc24088 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.inl +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.inl @@ -49,9 +49,8 @@ namespace PolyVox } template< typename VolumeType, typename MeshType, typename ControllerType > - void generateMeshForCell(Region& region, MeshType* result, ControllerType& controller, typename VolumeType::Sampler& sampler, Array<2, Vector3DInt32>& pIndices, Array<2, Vector3DInt32>& pPreviousIndices, uint8_t iCubeIndex, uint32_t uXRegSpace, uint32_t uYRegSpace, uint32_t uZRegSpace, typename ControllerType::DensityType tThreshold) + void generateMeshForCell(Region& region, MeshType* result, ControllerType& controller, typename VolumeType::Sampler& sampler, Array<2, Vector3DInt32>& pIndices, Array<2, Vector3DInt32>& pPreviousIndices, uint8_t iCubeIndex, uint32_t uXRegSpace, uint32_t uYRegSpace, uint32_t uZRegSpace, typename ControllerType::DensityType tThreshold, typename VolumeType::VoxelType& v111) { - auto v111 = sampler.getVoxel(); auto v111Density = controller.convertToDensity(v111); const Vector3DFloat n000 = computeCentralDifferenceGradient(sampler, controller); @@ -324,7 +323,7 @@ namespace PolyVox // occupied cells are really the bottleneck. The large number of parameters is messy though, so it // would be nice to reduce these if we can work out how. generateMeshForCell(region, result, controller, - sampler, pIndices, pPreviousIndices, iCubeIndex, uXRegSpace, uYRegSpace, uZRegSpace, tThreshold); + sampler, pIndices, pPreviousIndices, iCubeIndex, uXRegSpace, uYRegSpace, uZRegSpace, tThreshold, v111); } // For each cell sampler.movePositiveX(); } // For X From 942bb37981b1af22d65c721edfeb0e51d391fe25 Mon Sep 17 00:00:00 2001 From: David Williams Date: Fri, 29 May 2015 17:28:01 +0200 Subject: [PATCH 58/61] Revert "Passing sampled voxel." This reverts commit ebab89b9adac576b0d20fd8cbacf0154e7e74fe4. --- include/PolyVox/MarchingCubesSurfaceExtractor.inl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.inl b/include/PolyVox/MarchingCubesSurfaceExtractor.inl index 9dc24088..08564a35 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.inl +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.inl @@ -49,8 +49,9 @@ namespace PolyVox } template< typename VolumeType, typename MeshType, typename ControllerType > - void generateMeshForCell(Region& region, MeshType* result, ControllerType& controller, typename VolumeType::Sampler& sampler, Array<2, Vector3DInt32>& pIndices, Array<2, Vector3DInt32>& pPreviousIndices, uint8_t iCubeIndex, uint32_t uXRegSpace, uint32_t uYRegSpace, uint32_t uZRegSpace, typename ControllerType::DensityType tThreshold, typename VolumeType::VoxelType& v111) + void generateMeshForCell(Region& region, MeshType* result, ControllerType& controller, typename VolumeType::Sampler& sampler, Array<2, Vector3DInt32>& pIndices, Array<2, Vector3DInt32>& pPreviousIndices, uint8_t iCubeIndex, uint32_t uXRegSpace, uint32_t uYRegSpace, uint32_t uZRegSpace, typename ControllerType::DensityType tThreshold) { + auto v111 = sampler.getVoxel(); auto v111Density = controller.convertToDensity(v111); const Vector3DFloat n000 = computeCentralDifferenceGradient(sampler, controller); @@ -323,7 +324,7 @@ namespace PolyVox // occupied cells are really the bottleneck. The large number of parameters is messy though, so it // would be nice to reduce these if we can work out how. generateMeshForCell(region, result, controller, - sampler, pIndices, pPreviousIndices, iCubeIndex, uXRegSpace, uYRegSpace, uZRegSpace, tThreshold, v111); + sampler, pIndices, pPreviousIndices, iCubeIndex, uXRegSpace, uYRegSpace, uZRegSpace, tThreshold); } // For each cell sampler.movePositiveX(); } // For X From 96e747d0c38bdbfb9fd2b9cd9ae4bc1f236899aa Mon Sep 17 00:00:00 2001 From: David Williams Date: Fri, 29 May 2015 17:28:07 +0200 Subject: [PATCH 59/61] Revert "Split the code which generates vertices and indices for a single cell into a separate function." This reverts commit 2fa291d16f13adf039dc4fa636bfccde52377989. --- .../PolyVox/MarchingCubesSurfaceExtractor.inl | 378 +++++++++--------- 1 file changed, 182 insertions(+), 196 deletions(-) diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.inl b/include/PolyVox/MarchingCubesSurfaceExtractor.inl index 08564a35..b812d250 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.inl +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.inl @@ -48,192 +48,6 @@ namespace PolyVox ); } - template< typename VolumeType, typename MeshType, typename ControllerType > - void generateMeshForCell(Region& region, MeshType* result, ControllerType& controller, typename VolumeType::Sampler& sampler, Array<2, Vector3DInt32>& pIndices, Array<2, Vector3DInt32>& pPreviousIndices, uint8_t iCubeIndex, uint32_t uXRegSpace, uint32_t uYRegSpace, uint32_t uZRegSpace, typename ControllerType::DensityType tThreshold) - { - auto v111 = sampler.getVoxel(); - auto v111Density = controller.convertToDensity(v111); - const Vector3DFloat n000 = computeCentralDifferenceGradient(sampler, controller); - - uint16_t uEdge = edgeTable[iCubeIndex]; - /* Find the vertices where the surface intersects the cube */ - if ((uEdge & 64) && (uXRegSpace > 0)) - { - sampler.moveNegativeX(); - typename VolumeType::VoxelType v011 = sampler.getVoxel(); - auto v011Density = controller.convertToDensity(v011); - const float fInterp = static_cast(tThreshold - v011Density) / static_cast(v111Density - v011Density); - - // Compute the position - const Vector3DFloat v3dPosition(static_cast(uXRegSpace - 1) + fInterp, static_cast(uYRegSpace), static_cast(uZRegSpace)); - - // Compute the normal - const Vector3DFloat n100 = computeCentralDifferenceGradient(sampler, controller); - Vector3DFloat v3dNormal = (n100*fInterp) + (n000*(1 - fInterp)); - - // The gradient for a voxel can be zero (e.g. solid voxel surrounded by empty ones) and so - // the interpolated normal can also be zero (e.g. a grid of alternating solid and empty voxels). - if (v3dNormal.lengthSquared() > 0.000001f) - { - v3dNormal.normalise(); - } - - // Allow the controller to decide how the material should be derived from the voxels. - const typename VolumeType::VoxelType uMaterial = controller.blendMaterials(v011, v111, fInterp); - - MarchingCubesVertex surfaceVertex; - const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); - surfaceVertex.encodedPosition = v3dScaledPosition; - surfaceVertex.encodedNormal = encodeNormal(v3dNormal); - surfaceVertex.data = uMaterial; - - const uint32_t uLastVertexIndex = result->addVertex(surfaceVertex); - pIndices(uXRegSpace, uYRegSpace).setX(uLastVertexIndex); - - sampler.movePositiveX(); - } - if ((uEdge & 32) && (uYRegSpace > 0)) - { - sampler.moveNegativeY(); - typename VolumeType::VoxelType v101 = sampler.getVoxel(); - auto v101Density = controller.convertToDensity(v101); - const float fInterp = static_cast(tThreshold - v101Density) / static_cast(v111Density - v101Density); - - // Compute the position - const Vector3DFloat v3dPosition(static_cast(uXRegSpace), static_cast(uYRegSpace - 1) + fInterp, static_cast(uZRegSpace)); - - // Compute the normal - const Vector3DFloat n010 = computeCentralDifferenceGradient(sampler, controller); - Vector3DFloat v3dNormal = (n010*fInterp) + (n000*(1 - fInterp)); - - // The gradient for a voxel can be zero (e.g. solid voxel surrounded by empty ones) and so - // the interpolated normal can also be zero (e.g. a grid of alternating solid and empty voxels). - if (v3dNormal.lengthSquared() > 0.000001f) - { - v3dNormal.normalise(); - } - - // Allow the controller to decide how the material should be derived from the voxels. - const typename VolumeType::VoxelType uMaterial = controller.blendMaterials(v101, v111, fInterp); - - MarchingCubesVertex surfaceVertex; - const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); - surfaceVertex.encodedPosition = v3dScaledPosition; - surfaceVertex.encodedNormal = encodeNormal(v3dNormal); - surfaceVertex.data = uMaterial; - - uint32_t uLastVertexIndex = result->addVertex(surfaceVertex); - pIndices(uXRegSpace, uYRegSpace).setY(uLastVertexIndex); - - sampler.movePositiveY(); - } - if ((uEdge & 1024) && (uZRegSpace > 0)) - { - sampler.moveNegativeZ(); - typename VolumeType::VoxelType v110 = sampler.getVoxel(); - auto v110Density = controller.convertToDensity(v110); - const float fInterp = static_cast(tThreshold - v110Density) / static_cast(v111Density - v110Density); - - // Compute the position - const Vector3DFloat v3dPosition(static_cast(uXRegSpace), static_cast(uYRegSpace), static_cast(uZRegSpace - 1) + fInterp); - - // Compute the normal - const Vector3DFloat n001 = computeCentralDifferenceGradient(sampler, controller); - Vector3DFloat v3dNormal = (n001*fInterp) + (n000*(1 - fInterp)); - - // The gradient for a voxel can be zero (e.g. solid voxel surrounded by empty ones) and so - // the interpolated normal can also be zero (e.g. a grid of alternating solid and empty voxels). - if (v3dNormal.lengthSquared() > 0.000001f) - { - v3dNormal.normalise(); - } - - // Allow the controller to decide how the material should be derived from the voxels. - const typename VolumeType::VoxelType uMaterial = controller.blendMaterials(v110, v111, fInterp); - - MarchingCubesVertex surfaceVertex; - const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); - surfaceVertex.encodedPosition = v3dScaledPosition; - surfaceVertex.encodedNormal = encodeNormal(v3dNormal); - surfaceVertex.data = uMaterial; - - const uint32_t uLastVertexIndex = result->addVertex(surfaceVertex); - pIndices(uXRegSpace, uYRegSpace).setZ(uLastVertexIndex); - - sampler.movePositiveZ(); - } - - // Now output the indices. For the first row, column or slice there aren't - // any (the region size in cells is one less than the region size in voxels) - if ((uXRegSpace != 0) && (uYRegSpace != 0) && (uZRegSpace != 0)) - { - - int32_t indlist[12]; - - /* Find the vertices where the surface intersects the cube */ - if (uEdge & 1) - { - indlist[0] = pPreviousIndices(uXRegSpace, uYRegSpace - 1).getX(); - } - if (uEdge & 2) - { - indlist[1] = pPreviousIndices(uXRegSpace, uYRegSpace).getY(); - } - if (uEdge & 4) - { - indlist[2] = pPreviousIndices(uXRegSpace, uYRegSpace).getX(); - } - if (uEdge & 8) - { - indlist[3] = pPreviousIndices(uXRegSpace - 1, uYRegSpace).getY(); - } - if (uEdge & 16) - { - indlist[4] = pIndices(uXRegSpace, uYRegSpace - 1).getX(); - } - if (uEdge & 32) - { - indlist[5] = pIndices(uXRegSpace, uYRegSpace).getY(); - } - if (uEdge & 64) - { - indlist[6] = pIndices(uXRegSpace, uYRegSpace).getX(); - } - if (uEdge & 128) - { - indlist[7] = pIndices(uXRegSpace - 1, uYRegSpace).getY(); - } - if (uEdge & 256) - { - indlist[8] = pIndices(uXRegSpace - 1, uYRegSpace - 1).getZ(); - } - if (uEdge & 512) - { - indlist[9] = pIndices(uXRegSpace, uYRegSpace - 1).getZ(); - } - if (uEdge & 1024) - { - indlist[10] = pIndices(uXRegSpace, uYRegSpace).getZ(); - } - if (uEdge & 2048) - { - indlist[11] = pIndices(uXRegSpace - 1, uYRegSpace).getZ(); - } - - for (int i = 0; triTable[iCubeIndex][i] != -1; i += 3) - { - const int32_t ind0 = indlist[triTable[iCubeIndex][i]]; - const int32_t ind1 = indlist[triTable[iCubeIndex][i + 1]]; - const int32_t ind2 = indlist[triTable[iCubeIndex][i + 2]]; - - if ((ind0 != -1) && (ind1 != -1) && (ind2 != -1)) - { - result->addTriangle(ind0, ind1, ind2); - } - } // For each triangle - } - } - template< typename VolumeType, typename MeshType, typename ControllerType > void extractMarchingCubesMeshCustom(VolumeType* volData, Region region, MeshType* result, ControllerType controller) { @@ -314,17 +128,189 @@ namespace PolyVox pPreviousRowBitmask(uXRegSpace) = iCubeIndex; pPreviousSliceBitmask(uXRegSpace, uYRegSpace) = iCubeIndex; - /* Cube is entirely in/out of the surface */ - if (edgeTable[iCubeIndex] != 0) + /* Cube is entirely in/out of the surface */ + uint16_t uEdge = edgeTable[iCubeIndex]; + if (uEdge != 0) { - // This is a rather ugly function call and appears to have some cost compared to inlining the code. - // As a result the case when a cell contains vertices/indices is slightly slower, but the (more common) - // case where a cell is empty is slightly faster, probably because the main loop is a lot more compact. - // Having a seperate function will also make it easier to profile in the future and see whether empty or - // occupied cells are really the bottleneck. The large number of parameters is messy though, so it - // would be nice to reduce these if we can work out how. - generateMeshForCell(region, result, controller, - sampler, pIndices, pPreviousIndices, iCubeIndex, uXRegSpace, uYRegSpace, uZRegSpace, tThreshold); + auto v111Density = controller.convertToDensity(v111); + const Vector3DFloat n000 = computeCentralDifferenceGradient(sampler, controller); + + /* Find the vertices where the surface intersects the cube */ + if ((uEdge & 64) && (uXRegSpace > 0)) + { + sampler.moveNegativeX(); + typename VolumeType::VoxelType v011 = sampler.getVoxel(); + auto v011Density = controller.convertToDensity(v011); + const float fInterp = static_cast(tThreshold - v011Density) / static_cast(v111Density - v011Density); + + // Compute the position + const Vector3DFloat v3dPosition(static_cast(uXRegSpace - 1) + fInterp, static_cast(uYRegSpace), static_cast(uZRegSpace)); + + // Compute the normal + const Vector3DFloat n100 = computeCentralDifferenceGradient(sampler, controller); + Vector3DFloat v3dNormal = (n100*fInterp) + (n000*(1 - fInterp)); + + // The gradient for a voxel can be zero (e.g. solid voxel surrounded by empty ones) and so + // the interpolated normal can also be zero (e.g. a grid of alternating solid and empty voxels). + if (v3dNormal.lengthSquared() > 0.000001f) + { + v3dNormal.normalise(); + } + + // Allow the controller to decide how the material should be derived from the voxels. + const typename VolumeType::VoxelType uMaterial = controller.blendMaterials(v011, v111, fInterp); + + MarchingCubesVertex surfaceVertex; + const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); + surfaceVertex.encodedPosition = v3dScaledPosition; + surfaceVertex.encodedNormal = encodeNormal(v3dNormal); + surfaceVertex.data = uMaterial; + + const uint32_t uLastVertexIndex = result->addVertex(surfaceVertex); + pIndices(uXRegSpace, uYRegSpace).setX(uLastVertexIndex); + + sampler.movePositiveX(); + } + if ((uEdge & 32) && (uYRegSpace > 0)) + { + sampler.moveNegativeY(); + typename VolumeType::VoxelType v101 = sampler.getVoxel(); + auto v101Density = controller.convertToDensity(v101); + const float fInterp = static_cast(tThreshold - v101Density) / static_cast(v111Density - v101Density); + + // Compute the position + const Vector3DFloat v3dPosition(static_cast(uXRegSpace), static_cast(uYRegSpace - 1) + fInterp, static_cast(uZRegSpace)); + + // Compute the normal + const Vector3DFloat n010 = computeCentralDifferenceGradient(sampler, controller); + Vector3DFloat v3dNormal = (n010*fInterp) + (n000*(1 - fInterp)); + + // The gradient for a voxel can be zero (e.g. solid voxel surrounded by empty ones) and so + // the interpolated normal can also be zero (e.g. a grid of alternating solid and empty voxels). + if (v3dNormal.lengthSquared() > 0.000001f) + { + v3dNormal.normalise(); + } + + // Allow the controller to decide how the material should be derived from the voxels. + const typename VolumeType::VoxelType uMaterial = controller.blendMaterials(v101, v111, fInterp); + + MarchingCubesVertex surfaceVertex; + const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); + surfaceVertex.encodedPosition = v3dScaledPosition; + surfaceVertex.encodedNormal = encodeNormal(v3dNormal); + surfaceVertex.data = uMaterial; + + uint32_t uLastVertexIndex = result->addVertex(surfaceVertex); + pIndices(uXRegSpace, uYRegSpace).setY(uLastVertexIndex); + + sampler.movePositiveY(); + } + if ((uEdge & 1024) && (uZRegSpace > 0)) + { + sampler.moveNegativeZ(); + typename VolumeType::VoxelType v110 = sampler.getVoxel(); + auto v110Density = controller.convertToDensity(v110); + const float fInterp = static_cast(tThreshold - v110Density) / static_cast(v111Density - v110Density); + + // Compute the position + const Vector3DFloat v3dPosition(static_cast(uXRegSpace), static_cast(uYRegSpace), static_cast(uZRegSpace - 1) + fInterp); + + // Compute the normal + const Vector3DFloat n001 = computeCentralDifferenceGradient(sampler, controller); + Vector3DFloat v3dNormal = (n001*fInterp) + (n000*(1 - fInterp)); + + // The gradient for a voxel can be zero (e.g. solid voxel surrounded by empty ones) and so + // the interpolated normal can also be zero (e.g. a grid of alternating solid and empty voxels). + if (v3dNormal.lengthSquared() > 0.000001f) + { + v3dNormal.normalise(); + } + + // Allow the controller to decide how the material should be derived from the voxels. + const typename VolumeType::VoxelType uMaterial = controller.blendMaterials(v110, v111, fInterp); + + MarchingCubesVertex surfaceVertex; + const Vector3DUint16 v3dScaledPosition(static_cast(v3dPosition.getX() * 256.0f), static_cast(v3dPosition.getY() * 256.0f), static_cast(v3dPosition.getZ() * 256.0f)); + surfaceVertex.encodedPosition = v3dScaledPosition; + surfaceVertex.encodedNormal = encodeNormal(v3dNormal); + surfaceVertex.data = uMaterial; + + const uint32_t uLastVertexIndex = result->addVertex(surfaceVertex); + pIndices(uXRegSpace, uYRegSpace).setZ(uLastVertexIndex); + + sampler.movePositiveZ(); + } + + // Now output the indices. For the first row, column or slice there aren't + // any (the region size in cells is one less than the region size in voxels) + if ((uXRegSpace != 0) && (uYRegSpace != 0) && (uZRegSpace != 0)) + { + + int32_t indlist[12]; + + /* Find the vertices where the surface intersects the cube */ + if (uEdge & 1) + { + indlist[0] = pPreviousIndices(uXRegSpace, uYRegSpace - 1).getX(); + } + if (uEdge & 2) + { + indlist[1] = pPreviousIndices(uXRegSpace, uYRegSpace).getY(); + } + if (uEdge & 4) + { + indlist[2] = pPreviousIndices(uXRegSpace, uYRegSpace).getX(); + } + if (uEdge & 8) + { + indlist[3] = pPreviousIndices(uXRegSpace - 1, uYRegSpace).getY(); + } + if (uEdge & 16) + { + indlist[4] = pIndices(uXRegSpace, uYRegSpace - 1).getX(); + } + if (uEdge & 32) + { + indlist[5] = pIndices(uXRegSpace, uYRegSpace).getY(); + } + if (uEdge & 64) + { + indlist[6] = pIndices(uXRegSpace, uYRegSpace).getX(); + } + if (uEdge & 128) + { + indlist[7] = pIndices(uXRegSpace - 1, uYRegSpace).getY(); + } + if (uEdge & 256) + { + indlist[8] = pIndices(uXRegSpace - 1, uYRegSpace - 1).getZ(); + } + if (uEdge & 512) + { + indlist[9] = pIndices(uXRegSpace, uYRegSpace - 1).getZ(); + } + if (uEdge & 1024) + { + indlist[10] = pIndices(uXRegSpace, uYRegSpace).getZ(); + } + if (uEdge & 2048) + { + indlist[11] = pIndices(uXRegSpace - 1, uYRegSpace).getZ(); + } + + for (int i = 0; triTable[iCubeIndex][i] != -1; i += 3) + { + const int32_t ind0 = indlist[triTable[iCubeIndex][i]]; + const int32_t ind1 = indlist[triTable[iCubeIndex][i + 1]]; + const int32_t ind2 = indlist[triTable[iCubeIndex][i + 2]]; + + if ((ind0 != -1) && (ind1 != -1) && (ind2 != -1)) + { + result->addTriangle(ind0, ind1, ind2); + } + } // For each triangle + } } // For each cell sampler.movePositiveX(); } // For X From a0c32e22b74f5975c61ae93941b8e362b62218db Mon Sep 17 00:00:00 2001 From: David Williams Date: Fri, 29 May 2015 17:41:40 +0200 Subject: [PATCH 60/61] Added comment. --- .../PolyVox/MarchingCubesSurfaceExtractor.inl | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.inl b/include/PolyVox/MarchingCubesSurfaceExtractor.inl index b812d250..066e2447 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.inl +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.inl @@ -128,8 +128,23 @@ namespace PolyVox pPreviousRowBitmask(uXRegSpace) = iCubeIndex; pPreviousSliceBitmask(uXRegSpace, uYRegSpace) = iCubeIndex; - /* Cube is entirely in/out of the surface */ uint16_t uEdge = edgeTable[iCubeIndex]; + + // Test whether any vertices and indices should be generated for the current cell (i.e. it is occupied). + // Performance note: This condition is usually false because most cells in a volume are completely above + // or below the threshold and hence unoccupied. However, even when it is always false (testing on an empty + // volume) it still incurs significant overhead, probably because the code is large and bloats the for loop + // which contains it. On my empty volume test case the code as given runs in 34ms, but if I replace the + // condition with 'false' it runs in 24ms and gives the same output (i.e. none). + // + // An improvement is to move the code into a seperate function which does speed things up (30ms), but this + // is messy as the function needs to be passed about 10 differnt parameters, probably adding some overhead + // in its self. This does indeed seem to slow down the case when cells are occupied, by about 10-20%. + // + // Overall I don't know the right solution, but I'm leaving the code as-is to avoid making it messy. If we + // can reduce the number of parameters which need to be passed then it might be worth moving it into a + // function, or otherwise it may simply be worth trying to shorten the code (e.g. adding other function + // calls). For now we will leave it as-is, until we have more information from real-world profiling. if (uEdge != 0) { auto v111Density = controller.convertToDensity(v111); From 8c35399fc629542d3d7b0501783e7fd37d6a7363 Mon Sep 17 00:00:00 2001 From: David Williams Date: Fri, 29 May 2015 20:34:03 +0200 Subject: [PATCH 61/61] Comments and renaming variables. --- .../PolyVox/MarchingCubesSurfaceExtractor.inl | 72 +++++++++++-------- 1 file changed, 42 insertions(+), 30 deletions(-) diff --git a/include/PolyVox/MarchingCubesSurfaceExtractor.inl b/include/PolyVox/MarchingCubesSurfaceExtractor.inl index 066e2447..e349e726 100644 --- a/include/PolyVox/MarchingCubesSurfaceExtractor.inl +++ b/include/PolyVox/MarchingCubesSurfaceExtractor.inl @@ -51,31 +51,41 @@ namespace PolyVox template< typename VolumeType, typename MeshType, typename ControllerType > void extractMarchingCubesMeshCustom(VolumeType* volData, Region region, MeshType* result, ControllerType controller) { + // Validate parameters + POLYVOX_THROW_IF(volData == nullptr, std::invalid_argument, "Provided volume cannot be null"); POLYVOX_THROW_IF(result == nullptr, std::invalid_argument, "Provided mesh cannot be null"); + // For profiling this function Timer timer; result->clear(); - typename ControllerType::DensityType tThreshold = controller.getThreshold(); - + // Store some commonly used values for performance and convienience const uint32_t uRegionWidthInVoxels = region.getWidthInVoxels(); const uint32_t uRegionHeightInVoxels = region.getHeightInVoxels(); const uint32_t uRegionDepthInVoxels = region.getDepthInVoxels(); - // No need to clear memory because we only read from elements we have written to. + typename ControllerType::DensityType tThreshold = controller.getThreshold(); + + // A naive implemetation of Marching Cubes might sample the eight corner voxels of every cell to determine the cell index. + // However, when processing the cells sequentially we cn observe that many of the voxels are shared with previous adjacent + // cells, and so we can obtain these by careful bit-shifting. These variables keep track of previous cells for this purpose. + // We don't clear the arrays because the algorithm ensures that we only read from elements we have previously written to. + uint8_t uPreviousCellIndex = 0; + Array1DUint8 pPreviousRowCellIndices(uRegionWidthInVoxels); + Array2DUint8 pPreviousSliceCellIndices(uRegionWidthInVoxels, uRegionHeightInVoxels); + + // A given vertex may be shared by multiple triangles, so we need to keep track of the indices into the vertex array. + // We don't clear the arrays because the algorithm ensures that we only read from elements we have previously written to. Array<2, Vector3DInt32> pIndices(uRegionWidthInVoxels, uRegionHeightInVoxels); Array<2, Vector3DInt32> pPreviousIndices(uRegionWidthInVoxels, uRegionHeightInVoxels); - Array2DUint8 pPreviousSliceBitmask(uRegionWidthInVoxels, uRegionHeightInVoxels); - Array1DUint8 pPreviousRowBitmask(uRegionWidthInVoxels); - - uint8_t uPreviousCell = 0; - + // A sampler pointing at the beginning of the region, which gets incremented to always point at the beginning of a slice. typename VolumeType::Sampler startOfSlice(volData); startOfSlice.setPosition(region.getLowerX(), region.getLowerY(), region.getLowerZ()); for (uint32_t uZRegSpace = 0; uZRegSpace < uRegionDepthInVoxels; uZRegSpace++) { + // A sampler pointing at the beginning of the slice, which gets incremented to always point at the beginning of a row. typename VolumeType::Sampler startOfRow = startOfSlice; for (uint32_t uYRegSpace = 0; uYRegSpace < uRegionHeightInVoxels; uYRegSpace++) @@ -87,7 +97,7 @@ namespace PolyVox for (uint32_t uXRegSpace = 0; uXRegSpace < uRegionWidthInVoxels; uXRegSpace++) { // Note: In many cases the provided region will be (mostly) empty which means mesh vertices/indices - // are not generated and the only thing that is done for each cell is the computation of iCubeIndex. + // are not generated and the only thing that is done for each cell is the computation of uCellIndex. // It appears that retriving the voxel value is not so expensive and that it is the bitwise combining // which actually carries the cost. // @@ -96,39 +106,41 @@ namespace PolyVox // However, this complicates the code and there would still be the cost of packing/unpacking so it's // not clear if there is really a benefit. It's something to consider in the future. - uint8_t iCubeIndex = 0; + // Each bit of the cell index specifies whether a given corner of the cell is above or below the threshold. + uint8_t uCellIndex = 0; // Four bits of our cube index are obtained by looking at the cube index for // the previous slice and copying four of those bits into their new positions. - uint8_t iPreviousCubeIndexZ = pPreviousSliceBitmask(uXRegSpace, uYRegSpace); - iPreviousCubeIndexZ >>= 4; - iCubeIndex |= iPreviousCubeIndexZ; + uint8_t uPreviousCellIndexZ = pPreviousSliceCellIndices(uXRegSpace, uYRegSpace); + uPreviousCellIndexZ >>= 4; + uCellIndex |= uPreviousCellIndexZ; // Two bits of our cube index are obtained by looking at the cube index for // the previous row and copying two of those bits into their new positions. - uint8_t iPreviousCubeIndexY = pPreviousRowBitmask(uXRegSpace); - iPreviousCubeIndexY &= 204; //204 = 128+64+8+4 - iPreviousCubeIndexY >>= 2; - iCubeIndex |= iPreviousCubeIndexY; + uint8_t uPreviousCellIndexY = pPreviousRowCellIndices(uXRegSpace); + uPreviousCellIndexY &= 204; //204 = 128+64+8+4 + uPreviousCellIndexY >>= 2; + uCellIndex |= uPreviousCellIndexY; // One bit of our cube index are obtained by looking at the cube index for // the previous cell and copying one of those bits into it's new position. - uint8_t iPreviousCubeIndexX = uPreviousCell; - iPreviousCubeIndexX &= 170; //170 = 128+32+8+2 - iPreviousCubeIndexX >>= 1; - iCubeIndex |= iPreviousCubeIndexX; + uint8_t UPreviousCellIndexX = uPreviousCellIndex; + UPreviousCellIndexX &= 170; //170 = 128+32+8+2 + UPreviousCellIndexX >>= 1; + uCellIndex |= UPreviousCellIndexX; // The last bit of our cube index is obtained by looking // at the relevant voxel and comparing it to the threshold typename VolumeType::VoxelType v111 = sampler.getVoxel(); - if (controller.convertToDensity(v111) < tThreshold) iCubeIndex |= 128; + if (controller.convertToDensity(v111) < tThreshold) uCellIndex |= 128; // The current value becomes the previous value, ready for the next iteration. - uPreviousCell = iCubeIndex; - pPreviousRowBitmask(uXRegSpace) = iCubeIndex; - pPreviousSliceBitmask(uXRegSpace, uYRegSpace) = iCubeIndex; + uPreviousCellIndex = uCellIndex; + pPreviousRowCellIndices(uXRegSpace) = uCellIndex; + pPreviousSliceCellIndices(uXRegSpace, uYRegSpace) = uCellIndex; - uint16_t uEdge = edgeTable[iCubeIndex]; + // 12 bits of uEdge determine whether a vertex is placed on each of the 12 edges of the cell. + uint16_t uEdge = edgeTable[uCellIndex]; // Test whether any vertices and indices should be generated for the current cell (i.e. it is occupied). // Performance note: This condition is usually false because most cells in a volume are completely above @@ -314,11 +326,11 @@ namespace PolyVox indlist[11] = pIndices(uXRegSpace - 1, uYRegSpace).getZ(); } - for (int i = 0; triTable[iCubeIndex][i] != -1; i += 3) + for (int i = 0; triTable[uCellIndex][i] != -1; i += 3) { - const int32_t ind0 = indlist[triTable[iCubeIndex][i]]; - const int32_t ind1 = indlist[triTable[iCubeIndex][i + 1]]; - const int32_t ind2 = indlist[triTable[iCubeIndex][i + 2]]; + const int32_t ind0 = indlist[triTable[uCellIndex][i]]; + const int32_t ind1 = indlist[triTable[uCellIndex][i + 1]]; + const int32_t ind2 = indlist[triTable[uCellIndex][i + 2]]; if ((ind0 != -1) && (ind1 != -1) && (ind2 != -1)) {