diff --git a/CMakeLists.txt b/CMakeLists.txt index 3d997e49..6e63a0fc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,8 @@ SET(SRC_FILES source/IndexedSurfacePatch.cpp source/MarchingCubesTables.cpp source/PolyVoxSceneManager.cpp - source/RegionGeometry.cpp + source/RegionGeometry.cpp + source/SurfaceExtractors.cpp source/SurfaceVertex.cpp source/Utility.cpp ) @@ -17,6 +18,7 @@ SET(INC_FILES include/BlockVolume.h include/BlockVolume.inl include/Constants.h + include/Enums.h include/GradientEstimators.h include/GradientEstimators.inl include/LinearVolume.h @@ -26,6 +28,7 @@ SET(INC_FILES include/PolyVoxForwardDeclarations.h include/PolyVoxSceneManager.h include/RegionGeometry.h + include/SurfaceExtractors.h include/SurfaceVertex.h include/TypeDef.h include/Utility.h diff --git a/include/Enums.h b/include/Enums.h new file mode 100644 index 00000000..fd2e8722 --- /dev/null +++ b/include/Enums.h @@ -0,0 +1,35 @@ +#pragma region License +/****************************************************************************** +This file is part of the PolyVox library +Copyright (C) 2006 David Williams + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +******************************************************************************/ +#pragma endregion + +#ifndef __PolyVox_Enums_H__ +#define __PolyVox_Enums_H__ + +namespace PolyVox +{ + enum NormalGenerationMethod + { + SIMPLE, + CENTRAL_DIFFERENCE, + SOBEL + }; +} + +#endif diff --git a/include/GradientEstimators.h b/include/GradientEstimators.h index 9a0fd9d8..506e93fd 100644 --- a/include/GradientEstimators.h +++ b/include/GradientEstimators.h @@ -26,7 +26,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. namespace PolyVox { - //FIXME - gradient can be expressed with ints. template Vector3DFloat computeCentralDifferenceGradient(const VolumeIterator& volIter); diff --git a/include/PolyVoxForwardDeclarations.h b/include/PolyVoxForwardDeclarations.h index 6209c4e8..8f6d7c3a 100644 --- a/include/PolyVoxForwardDeclarations.h +++ b/include/PolyVoxForwardDeclarations.h @@ -22,6 +22,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #ifndef __PolyVox_ForwardDeclarations_H__ #define __PolyVox_ForwardDeclarations_H__ +#include "Enums.h" + #include "boost/cstdint.hpp" namespace PolyVox diff --git a/include/PolyVoxSceneManager.h b/include/PolyVoxSceneManager.h index a528bc3d..1091ce51 100644 --- a/include/PolyVoxSceneManager.h +++ b/include/PolyVoxSceneManager.h @@ -32,13 +32,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. namespace PolyVox { - enum NormalGenerationMethod - { - SIMPLE, - CENTRAL_DIFFERENCE, - SOBEL - }; - /// Voxel scene manager class POLYVOX_API PolyVoxSceneManager { @@ -67,8 +60,8 @@ namespace PolyVox //void generateLevelVolume(void); - void generateRoughMeshDataForRegion(boost::uint16_t regionX, boost::uint16_t regionY, boost::uint16_t regionZ, IndexedSurfacePatch* singleMaterialPatch, IndexedSurfacePatch* multiMaterialPatch) const; - void generateSmoothMeshDataForRegion(boost::uint16_t regionX, boost::uint16_t regionY, boost::uint16_t regionZ, IndexedSurfacePatch* singleMaterialPatch, IndexedSurfacePatch* multiMaterialPatch) const; + + //bool containsPoint(Vector3DFloat pos, float boundary); //bool containsPoint(Vector3DInt32 pos, boost::uint16_t boundary); @@ -76,8 +69,8 @@ namespace PolyVox LinearVolume* volSurfaceUpToDate; - Vector3DFloat computeNormal(const Vector3DFloat& position, NormalGenerationMethod normalGenerationMethod) const; - Vector3DFloat computeSmoothNormal(const Vector3DFloat& position, NormalGenerationMethod normalGenerationMethod) const; + + public: void markVoxelChanged(boost::uint16_t x, boost::uint16_t y, boost::uint16_t z); diff --git a/include/SurfaceExtractors.h b/include/SurfaceExtractors.h new file mode 100644 index 00000000..251ce977 --- /dev/null +++ b/include/SurfaceExtractors.h @@ -0,0 +1,40 @@ +#pragma region License +/****************************************************************************** +This file is part of the PolyVox library +Copyright (C) 2006 David Williams + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +******************************************************************************/ +#pragma endregion + +#ifndef __PolyVox_SurfaceExtractors_H__ +#define __PolyVox_SurfaceExtractors_H__ + +#pragma region Headers +#include "PolyVoxForwardDeclarations.h" + +#include "boost/cstdint.hpp" +#pragma endregion + +namespace PolyVox +{ + void generateRoughMeshDataForRegion(BlockVolume* volumeData, boost::uint16_t regionX, boost::uint16_t regionY, boost::uint16_t regionZ, IndexedSurfacePatch* singleMaterialPatch, IndexedSurfacePatch* multiMaterialPatch); + Vector3DFloat computeNormal(BlockVolume* volumeData, const Vector3DFloat& position, NormalGenerationMethod normalGenerationMethod); + + void generateSmoothMeshDataForRegion(BlockVolume* volumeData, boost::uint16_t regionX, boost::uint16_t regionY, boost::uint16_t regionZ, IndexedSurfacePatch* singleMaterialPatch, IndexedSurfacePatch* multiMaterialPatch); + Vector3DFloat computeSmoothNormal(BlockVolume* volumeData, const Vector3DFloat& position, NormalGenerationMethod normalGenerationMethod); +} + +#endif diff --git a/source/PolyVoxSceneManager.cpp b/source/PolyVoxSceneManager.cpp index 982398f3..9857afd7 100644 --- a/source/PolyVoxSceneManager.cpp +++ b/source/PolyVoxSceneManager.cpp @@ -25,6 +25,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "MarchingCubesTables.h" #include "PolyVoxSceneManager.h" #include "RegionGeometry.h" +#include "SurfaceExtractors.h" #include "SurfaceVertex.h" #include "Utility.h" #include "Vector.h" @@ -82,7 +83,7 @@ namespace PolyVox regionGeometry.m_patchMultiMaterial = new IndexedSurfacePatch(true); regionGeometry.m_v3dRegionPosition = Vector3DInt32(regionX, regionY, regionZ); - generateRoughMeshDataForRegion(regionX,regionY,regionZ, regionGeometry.m_patchSingleMaterial, regionGeometry.m_patchMultiMaterial); + generateRoughMeshDataForRegion(volumeData, regionX,regionY,regionZ, regionGeometry.m_patchSingleMaterial, regionGeometry.m_patchMultiMaterial); regionGeometry.m_bContainsSingleMaterialPatch = regionGeometry.m_patchSingleMaterial->getVertices().size() > 0; regionGeometry.m_bContainsMultiMaterialPatch = regionGeometry.m_patchMultiMaterial->getVertices().size() > 0; @@ -161,812 +162,6 @@ namespace PolyVox markRegionChanged(firstX,firstY,firstZ,lastX,lastY,lastZ); } - void PolyVoxSceneManager::generateRoughMeshDataForRegion(const uint16_t regionX, const uint16_t regionY, const uint16_t regionZ, IndexedSurfacePatch* singleMaterialPatch, IndexedSurfacePatch* multiMaterialPatch) const - { - //First and last voxels in the region - const uint16_t firstX = regionX * POLYVOX_REGION_SIDE_LENGTH; - const uint16_t firstY = regionY * POLYVOX_REGION_SIDE_LENGTH; - const uint16_t firstZ = regionZ * POLYVOX_REGION_SIDE_LENGTH; - const uint16_t lastX = (std::min)(firstX + POLYVOX_REGION_SIDE_LENGTH-1,volumeData->getSideLength()-2); - const uint16_t lastY = (std::min)(firstY + POLYVOX_REGION_SIDE_LENGTH-1,volumeData->getSideLength()-2); - const uint16_t lastZ = (std::min)(firstZ + POLYVOX_REGION_SIDE_LENGTH-1,volumeData->getSideLength()-2); - - //Offset from lower block corner - const Vector3DFloat offset(firstX,firstY,firstZ); - - Vector3DFloat vertlist[12]; - uint8_t vertMaterials[12]; - VolumeIterator volIter(*volumeData); - volIter.setValidRegion(firstX,firstY,firstZ,lastX,lastY,lastZ); - - ////////////////////////////////////////////////////////////////////////// - //Get mesh data - ////////////////////////////////////////////////////////////////////////// - - //Iterate over each cell in the region - for(volIter.setPosition(firstX,firstY,firstZ);volIter.isValidForRegion();volIter.moveForwardInRegion()) - { - //Current position - const uint16_t x = volIter.getPosX(); - const uint16_t y = volIter.getPosY(); - const uint16_t z = volIter.getPosZ(); - - //Voxels values - const uint8_t v000 = volIter.getVoxel(); - const uint8_t v100 = volIter.peekVoxel1px0py0pz(); - const uint8_t v010 = volIter.peekVoxel0px1py0pz(); - const uint8_t v110 = volIter.peekVoxel1px1py0pz(); - const uint8_t v001 = volIter.peekVoxel0px0py1pz(); - const uint8_t v101 = volIter.peekVoxel1px0py1pz(); - const uint8_t v011 = volIter.peekVoxel0px1py1pz(); - const uint8_t v111 = volIter.peekVoxel1px1py1pz(); - - //Determine the index into the edge table which tells us which vertices are inside of the surface - uint8_t iCubeIndex = 0; - - if (v000 == 0) iCubeIndex |= 1; - if (v100 == 0) iCubeIndex |= 2; - if (v110 == 0) iCubeIndex |= 4; - if (v010 == 0) iCubeIndex |= 8; - if (v001 == 0) iCubeIndex |= 16; - if (v101 == 0) iCubeIndex |= 32; - if (v111 == 0) iCubeIndex |= 64; - if (v011 == 0) iCubeIndex |= 128; - - /* 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) - { - vertlist[0].setX(x + 0.5f); - vertlist[0].setY(y); - vertlist[0].setZ(z); - vertMaterials[0] = v000 | v100; //Because one of these is 0, the or operation takes the max. - } - if (edgeTable[iCubeIndex] & 2) - { - vertlist[1].setX(x + 1.0f); - vertlist[1].setY(y + 0.5f); - vertlist[1].setZ(z); - vertMaterials[1] = v100 | v110; - } - if (edgeTable[iCubeIndex] & 4) - { - vertlist[2].setX(x + 0.5f); - vertlist[2].setY(y + 1.0f); - vertlist[2].setZ(z); - vertMaterials[2] = v010 | v110; - } - if (edgeTable[iCubeIndex] & 8) - { - vertlist[3].setX(x); - vertlist[3].setY(y + 0.5f); - vertlist[3].setZ(z); - vertMaterials[3] = v000 | v010; - } - if (edgeTable[iCubeIndex] & 16) - { - vertlist[4].setX(x + 0.5f); - vertlist[4].setY(y); - vertlist[4].setZ(z + 1.0f); - vertMaterials[4] = v001 | v101; - } - if (edgeTable[iCubeIndex] & 32) - { - vertlist[5].setX(x + 1.0f); - vertlist[5].setY(y + 0.5f); - vertlist[5].setZ(z + 1.0f); - vertMaterials[5] = v101 | v111; - } - if (edgeTable[iCubeIndex] & 64) - { - vertlist[6].setX(x + 0.5f); - vertlist[6].setY(y + 1.0f); - vertlist[6].setZ(z + 1.0f); - vertMaterials[6] = v011 | v111; - } - if (edgeTable[iCubeIndex] & 128) - { - vertlist[7].setX(x); - vertlist[7].setY(y + 0.5f); - vertlist[7].setZ(z + 1.0f); - vertMaterials[7] = v001 | v011; - } - if (edgeTable[iCubeIndex] & 256) - { - vertlist[8].setX(x); - vertlist[8].setY(y); - vertlist[8].setZ(z + 0.5f); - vertMaterials[8] = v000 | v001; - } - if (edgeTable[iCubeIndex] & 512) - { - vertlist[9].setX(x + 1.0f); - vertlist[9].setY(y); - vertlist[9].setZ(z + 0.5f); - vertMaterials[9] = v100 | v101; - } - if (edgeTable[iCubeIndex] & 1024) - { - vertlist[10].setX(x + 1.0f); - vertlist[10].setY(y + 1.0f); - vertlist[10].setZ(z + 0.5f); - vertMaterials[10] = v110 | v111; - } - if (edgeTable[iCubeIndex] & 2048) - { - vertlist[11].setX(x); - vertlist[11].setY(y + 1.0f); - vertlist[11].setZ(z + 0.5f); - vertMaterials[11] = v010 | v011; - } - - for (int i=0;triTable[iCubeIndex][i]!=-1;i+=3) - { - //The three vertices forming a triangle - const Vector3DFloat vertex0 = vertlist[triTable[iCubeIndex][i ]] - offset; - const Vector3DFloat vertex1 = vertlist[triTable[iCubeIndex][i+1]] - offset; - const Vector3DFloat vertex2 = vertlist[triTable[iCubeIndex][i+2]] - offset; - - //Cast to floats and divide by two. - //const Vector3DFloat vertex0AsFloat = (static_cast(vertex0) / 2.0f) - offset; - //const Vector3DFloat vertex1AsFloat = (static_cast(vertex1) / 2.0f) - offset; - //const Vector3DFloat vertex2AsFloat = (static_cast(vertex2) / 2.0f) - offset; - - const uint8_t material0 = vertMaterials[triTable[iCubeIndex][i ]]; - const uint8_t material1 = vertMaterials[triTable[iCubeIndex][i+1]]; - const uint8_t material2 = vertMaterials[triTable[iCubeIndex][i+2]]; - - - //If all the materials are the same, we just need one triangle for that material with all the alphas set high. - if((material0 == material1) && (material1 == material2)) - { - SurfaceVertex surfaceVertex0Alpha1(vertex0,material0 + 0.1f,1.0f); - SurfaceVertex surfaceVertex1Alpha1(vertex1,material1 + 0.1f,1.0f); - SurfaceVertex surfaceVertex2Alpha1(vertex2,material2 + 0.1f,1.0f); - singleMaterialPatch->addTriangle(surfaceVertex0Alpha1, surfaceVertex1Alpha1, surfaceVertex2Alpha1); - } - else if(material0 == material1) - { - { - SurfaceVertex surfaceVertex0Alpha1(vertex0,material0 + 0.1f,1.0f); - SurfaceVertex surfaceVertex1Alpha1(vertex1,material0 + 0.1f,1.0f); - SurfaceVertex surfaceVertex2Alpha1(vertex2,material0 + 0.1f,0.0f); - multiMaterialPatch->addTriangle(surfaceVertex0Alpha1, surfaceVertex1Alpha1, surfaceVertex2Alpha1); - } - - { - SurfaceVertex surfaceVertex0Alpha1(vertex0,material2 + 0.1f,0.0f); - SurfaceVertex surfaceVertex1Alpha1(vertex1,material2 + 0.1f,0.0f); - SurfaceVertex surfaceVertex2Alpha1(vertex2,material2 + 0.1f,1.0f); - multiMaterialPatch->addTriangle(surfaceVertex0Alpha1, surfaceVertex1Alpha1, surfaceVertex2Alpha1); - } - } - else if(material0 == material2) - { - { - SurfaceVertex surfaceVertex0Alpha1(vertex0,material0 + 0.1f,1.0f); - SurfaceVertex surfaceVertex1Alpha1(vertex1,material0 + 0.1f,0.0f); - SurfaceVertex surfaceVertex2Alpha1(vertex2,material0 + 0.1f,1.0f); - multiMaterialPatch->addTriangle(surfaceVertex0Alpha1, surfaceVertex1Alpha1, surfaceVertex2Alpha1); - } - - { - SurfaceVertex surfaceVertex0Alpha1(vertex0,material1 + 0.1f,0.0f); - SurfaceVertex surfaceVertex1Alpha1(vertex1,material1 + 0.1f,1.0f); - SurfaceVertex surfaceVertex2Alpha1(vertex2,material1 + 0.1f,0.0f); - multiMaterialPatch->addTriangle(surfaceVertex0Alpha1, surfaceVertex1Alpha1, surfaceVertex2Alpha1); - } - } - else if(material1 == material2) - { - { - SurfaceVertex surfaceVertex0Alpha1(vertex0,material1 + 0.1f,0.0f); - SurfaceVertex surfaceVertex1Alpha1(vertex1,material1 + 0.1f,1.0f); - SurfaceVertex surfaceVertex2Alpha1(vertex2,material1 + 0.1f,1.0f); - multiMaterialPatch->addTriangle(surfaceVertex0Alpha1, surfaceVertex1Alpha1, surfaceVertex2Alpha1); - } - - { - SurfaceVertex surfaceVertex0Alpha1(vertex0,material0 + 0.1f,1.0f); - SurfaceVertex surfaceVertex1Alpha1(vertex1,material0 + 0.1f,0.0f); - SurfaceVertex surfaceVertex2Alpha1(vertex2,material0 + 0.1f,0.0f); - multiMaterialPatch->addTriangle(surfaceVertex0Alpha1, surfaceVertex1Alpha1, surfaceVertex2Alpha1); - } - } - else - { - { - SurfaceVertex surfaceVertex0Alpha1(vertex0,material0 + 0.1f,1.0f); - SurfaceVertex surfaceVertex1Alpha1(vertex1,material0 + 0.1f,0.0f); - SurfaceVertex surfaceVertex2Alpha1(vertex2,material0 + 0.1f,0.0f); - multiMaterialPatch->addTriangle(surfaceVertex0Alpha1, surfaceVertex1Alpha1, surfaceVertex2Alpha1); - } - - { - SurfaceVertex surfaceVertex0Alpha1(vertex0,material1 + 0.1f,0.0f); - SurfaceVertex surfaceVertex1Alpha1(vertex1,material1 + 0.1f,1.0f); - SurfaceVertex surfaceVertex2Alpha1(vertex2,material1 + 0.1f,0.0f); - multiMaterialPatch->addTriangle(surfaceVertex0Alpha1, surfaceVertex1Alpha1, surfaceVertex2Alpha1); - } - - { - SurfaceVertex surfaceVertex0Alpha1(vertex0,material2 + 0.1f,0.0f); - SurfaceVertex surfaceVertex1Alpha1(vertex1,material2 + 0.1f,0.0f); - SurfaceVertex surfaceVertex2Alpha1(vertex2,material2 + 0.1f,1.0f); - multiMaterialPatch->addTriangle(surfaceVertex0Alpha1, surfaceVertex1Alpha1, surfaceVertex2Alpha1); - } - } - //If there not all the same, we need one triangle for each unique material. - //We'll also need some vertices with low alphas for blending. - /*else - { - SurfaceVertex surfaceVertex0Alpha0(vertex0,0.0); - SurfaceVertex surfaceVertex1Alpha0(vertex1,0.0); - SurfaceVertex surfaceVertex2Alpha0(vertex2,0.0); - - if(material0 == material1) - { - surfacePatchMapResult[material0]->addTriangle(surfaceVertex0Alpha1, surfaceVertex1Alpha1, surfaceVertex2Alpha0); - surfacePatchMapResult[material2]->addTriangle(surfaceVertex0Alpha0, surfaceVertex1Alpha0, surfaceVertex2Alpha1); - } - else if(material1 == material2) - { - surfacePatchMapResult[material1]->addTriangle(surfaceVertex0Alpha0, surfaceVertex1Alpha1, surfaceVertex2Alpha1); - surfacePatchMapResult[material0]->addTriangle(surfaceVertex0Alpha1, surfaceVertex1Alpha0, surfaceVertex2Alpha0); - } - else if(material2 == material0) - { - surfacePatchMapResult[material0]->addTriangle(surfaceVertex0Alpha1, surfaceVertex1Alpha0, surfaceVertex2Alpha1); - surfacePatchMapResult[material1]->addTriangle(surfaceVertex0Alpha0, surfaceVertex1Alpha1, surfaceVertex2Alpha0); - } - else - { - surfacePatchMapResult[material0]->addTriangle(surfaceVertex0Alpha1, surfaceVertex1Alpha0, surfaceVertex2Alpha0); - surfacePatchMapResult[material1]->addTriangle(surfaceVertex0Alpha0, surfaceVertex1Alpha1, surfaceVertex2Alpha0); - surfacePatchMapResult[material2]->addTriangle(surfaceVertex0Alpha0, surfaceVertex1Alpha0, surfaceVertex2Alpha1); - } - }*/ - }//For each triangle - }//For each cell - - //FIXME - can it happen that we have no vertices or triangles? Should exit early? - - - //for(std::map::iterator iterPatch = surfacePatchMapResult.begin(); iterPatch != surfacePatchMapResult.end(); ++iterPatch) - { - - std::vector::iterator iterSurfaceVertex = singleMaterialPatch->getVertices().begin(); - while(iterSurfaceVertex != singleMaterialPatch->getVertices().end()) - { - Vector3DFloat tempNormal = computeNormal(static_cast(iterSurfaceVertex->getPosition() + offset), CENTRAL_DIFFERENCE); - const_cast(*iterSurfaceVertex).setNormal(tempNormal); - ++iterSurfaceVertex; - } - - iterSurfaceVertex = multiMaterialPatch->getVertices().begin(); - while(iterSurfaceVertex != multiMaterialPatch->getVertices().end()) - { - Vector3DFloat tempNormal = computeNormal(static_cast(iterSurfaceVertex->getPosition() + offset), CENTRAL_DIFFERENCE); - const_cast(*iterSurfaceVertex).setNormal(tempNormal); - ++iterSurfaceVertex; - } - - uint16_t noOfRemovedVertices = 0; - //do - { - //noOfRemovedVertices = iterPatch->second.decimate(); - } - //while(noOfRemovedVertices > 10); //We don't worry about the last few vertices - it's not worth the overhead of calling the function. - } - - //return singleMaterialPatch; - } - - void PolyVoxSceneManager::generateSmoothMeshDataForRegion(const uint16_t regionX, const uint16_t regionY, const uint16_t regionZ, IndexedSurfacePatch* singleMaterialPatch, IndexedSurfacePatch* multiMaterialPatch) const - { - //First and last voxels in the region - const uint16_t firstX = regionX * POLYVOX_REGION_SIDE_LENGTH; - const uint16_t firstY = regionY * POLYVOX_REGION_SIDE_LENGTH; - const uint16_t firstZ = regionZ * POLYVOX_REGION_SIDE_LENGTH; - const uint16_t lastX = (std::min)(firstX + POLYVOX_REGION_SIDE_LENGTH-1,volumeData->getSideLength()-2); - const uint16_t lastY = (std::min)(firstY + POLYVOX_REGION_SIDE_LENGTH-1,volumeData->getSideLength()-2); - const uint16_t lastZ = (std::min)(firstZ + POLYVOX_REGION_SIDE_LENGTH-1,volumeData->getSideLength()-2); - - //Offset from lower block corner - const Vector3DFloat offset(firstX,firstY,firstZ); - - Vector3DFloat vertlist[12]; - uint8_t vertMaterials[12]; - VolumeIterator volIter(*volumeData); - volIter.setValidRegion(firstX,firstY,firstZ,lastX,lastY,lastZ); - - const float threshold = 0.5f; - - ////////////////////////////////////////////////////////////////////////// - //Get mesh data - ////////////////////////////////////////////////////////////////////////// - - //Iterate over each cell in the region - for(volIter.setPosition(firstX,firstY,firstZ);volIter.isValidForRegion();volIter.moveForwardInRegion()) - { - //Current position - const uint16_t x = volIter.getPosX(); - const uint16_t y = volIter.getPosY(); - const uint16_t z = volIter.getPosZ(); - - //Voxels values - VolumeIterator tempVolIter(*volumeData); - tempVolIter.setPosition(x,y,z); - const float v000 = tempVolIter.getAveragedVoxel(1); - tempVolIter.setPosition(x+1,y,z); - const float v100 = tempVolIter.getAveragedVoxel(1); - tempVolIter.setPosition(x,y+1,z); - const float v010 = tempVolIter.getAveragedVoxel(1); - tempVolIter.setPosition(x+1,y+1,z); - const float v110 = tempVolIter.getAveragedVoxel(1); - tempVolIter.setPosition(x,y,z+1); - const float v001 = tempVolIter.getAveragedVoxel(1); - tempVolIter.setPosition(x+1,y,z+1); - const float v101 = tempVolIter.getAveragedVoxel(1); - tempVolIter.setPosition(x,y+1,z+1); - const float v011 = tempVolIter.getAveragedVoxel(1); - tempVolIter.setPosition(x+1,y+1,z+1); - const float v111 = tempVolIter.getAveragedVoxel(1); - - //Determine the index into the edge table which tells us which vertices are inside of the surface - uint8_t iCubeIndex = 0; - - if (v000 < threshold) iCubeIndex |= 1; - if (v100 < threshold) iCubeIndex |= 2; - if (v110 < threshold) iCubeIndex |= 4; - if (v010 < threshold) iCubeIndex |= 8; - if (v001 < threshold) iCubeIndex |= 16; - if (v101 < threshold) iCubeIndex |= 32; - if (v111 < threshold) iCubeIndex |= 64; - if (v011 < threshold) iCubeIndex |= 128; - - /* 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) - { - float a = v000; - float b = v100; - float val = (threshold-a)/(b-a); - vertlist[0].setX(x + val); - vertlist[0].setY(y); - vertlist[0].setZ(z); - vertMaterials[0] = 1;//v000 | v100; //Because one of these is 0, the or operation takes the max. - } - if (edgeTable[iCubeIndex] & 2) - { - float a = v100; - float b = v110; - float val = (threshold-a)/(b-a); - vertlist[1].setX(x + 1.0f); - vertlist[1].setY(y + val); - vertlist[1].setZ(z); - vertMaterials[1] = 1;//v100 | v110; - } - if (edgeTable[iCubeIndex] & 4) - { - float a = v010; - float b = v110; - float val = (threshold-a)/(b-a); - vertlist[2].setX(x + val); - vertlist[2].setY(y + 1.0f); - vertlist[2].setZ(z); - vertMaterials[2] = 1;//v010 | v110; - } - if (edgeTable[iCubeIndex] & 8) - { - float a = v000; - float b = v010; - float val = (threshold-a)/(b-a); - vertlist[3].setX(x); - vertlist[3].setY(y + val); - vertlist[3].setZ(z); - vertMaterials[3] = 1;//v000 | v010; - } - if (edgeTable[iCubeIndex] & 16) - { - float a = v001; - float b = v101; - float val = (threshold-a)/(b-a); - vertlist[4].setX(x + val); - vertlist[4].setY(y); - vertlist[4].setZ(z + 1.0f); - vertMaterials[4] = 1;//v001 | v101; - } - if (edgeTable[iCubeIndex] & 32) - { - float a = v101; - float b = v111; - float val = (threshold-a)/(b-a); - vertlist[5].setX(x + 1.0f); - vertlist[5].setY(y + val); - vertlist[5].setZ(z + 1.0f); - vertMaterials[5] = 1;//v101 | v111; - } - if (edgeTable[iCubeIndex] & 64) - { - float a = v011; - float b = v111; - float val = (threshold-a)/(b-a); - vertlist[6].setX(x + val); - vertlist[6].setY(y + 1.0f); - vertlist[6].setZ(z + 1.0f); - vertMaterials[6] = 1;//v011 | v111; - } - if (edgeTable[iCubeIndex] & 128) - { - float a = v001; - float b = v011; - float val = (threshold-a)/(b-a); - vertlist[7].setX(x); - vertlist[7].setY(y + val); - vertlist[7].setZ(z + 1.0f); - vertMaterials[7] = 1;//v001 | v011; - } - if (edgeTable[iCubeIndex] & 256) - { - float a = v000; - float b = v001; - float val = (threshold-a)/(b-a); - vertlist[8].setX(x); - vertlist[8].setY(y); - vertlist[8].setZ(z + val); - vertMaterials[8] = 1;//v000 | v001; - } - if (edgeTable[iCubeIndex] & 512) - { - float a = v100; - float b = v101; - float val = (threshold-a)/(b-a); - vertlist[9].setX(x + 1.0f); - vertlist[9].setY(y); - vertlist[9].setZ(z + val); - vertMaterials[9] = 1;//v100 | v101; - } - if (edgeTable[iCubeIndex] & 1024) - { - float a = v110; - float b = v111; - float val = (threshold-a)/(b-a); - vertlist[10].setX(x + 1.0f); - vertlist[10].setY(y + 1.0f); - vertlist[10].setZ(z + val); - vertMaterials[10] = 1;//v110 | v111; - } - if (edgeTable[iCubeIndex] & 2048) - { - float a = v010; - float b = v011; - float val = (threshold-a)/(b-a); - vertlist[11].setX(x); - vertlist[11].setY(y + 1.0f); - vertlist[11].setZ(z + val); - vertMaterials[11] = 1;//v010 | v011; - } - - for (int i=0;triTable[iCubeIndex][i]!=-1;i+=3) - { - //The three vertices forming a triangle - const Vector3DFloat vertex0 = vertlist[triTable[iCubeIndex][i ]] - offset; - const Vector3DFloat vertex1 = vertlist[triTable[iCubeIndex][i+1]] - offset; - const Vector3DFloat vertex2 = vertlist[triTable[iCubeIndex][i+2]] - offset; - - const uint8_t material0 = vertMaterials[triTable[iCubeIndex][i ]]; - const uint8_t material1 = vertMaterials[triTable[iCubeIndex][i+1]]; - const uint8_t material2 = vertMaterials[triTable[iCubeIndex][i+2]]; - - //If all the materials are the same, we just need one triangle for that material with all the alphas set high. - /*if((material0 == material1) && (material1 == material2)) - {*/ - SurfaceVertex surfaceVertex0Alpha1(vertex0,material0 + 0.1f,1.0f); - SurfaceVertex surfaceVertex1Alpha1(vertex1,material1 + 0.1f,1.0f); - SurfaceVertex surfaceVertex2Alpha1(vertex2,material2 + 0.1f,1.0f); - singleMaterialPatch->addTriangle(surfaceVertex0Alpha1, surfaceVertex1Alpha1, surfaceVertex2Alpha1); - /*} - else if(material0 == material1) - { - { - SurfaceVertex surfaceVertex0Alpha1(vertex0,material0 + 0.1,1.0); - SurfaceVertex surfaceVertex1Alpha1(vertex1,material0 + 0.1,1.0); - SurfaceVertex surfaceVertex2Alpha1(vertex2,material0 + 0.1,0.0); - multiMaterialPatch->addTriangle(surfaceVertex0Alpha1, surfaceVertex1Alpha1, surfaceVertex2Alpha1); - } - - { - SurfaceVertex surfaceVertex0Alpha1(vertex0,material2 + 0.1,0.0); - SurfaceVertex surfaceVertex1Alpha1(vertex1,material2 + 0.1,0.0); - SurfaceVertex surfaceVertex2Alpha1(vertex2,material2 + 0.1,1.0); - multiMaterialPatch->addTriangle(surfaceVertex0Alpha1, surfaceVertex1Alpha1, surfaceVertex2Alpha1); - } - } - else if(material0 == material2) - { - { - SurfaceVertex surfaceVertex0Alpha1(vertex0,material0 + 0.1,1.0); - SurfaceVertex surfaceVertex1Alpha1(vertex1,material0 + 0.1,0.0); - SurfaceVertex surfaceVertex2Alpha1(vertex2,material0 + 0.1,1.0); - multiMaterialPatch->addTriangle(surfaceVertex0Alpha1, surfaceVertex1Alpha1, surfaceVertex2Alpha1); - } - - { - SurfaceVertex surfaceVertex0Alpha1(vertex0,material1 + 0.1,0.0); - SurfaceVertex surfaceVertex1Alpha1(vertex1,material1 + 0.1,1.0); - SurfaceVertex surfaceVertex2Alpha1(vertex2,material1 + 0.1,0.0); - multiMaterialPatch->addTriangle(surfaceVertex0Alpha1, surfaceVertex1Alpha1, surfaceVertex2Alpha1); - } - } - else if(material1 == material2) - { - { - SurfaceVertex surfaceVertex0Alpha1(vertex0,material1 + 0.1,0.0); - SurfaceVertex surfaceVertex1Alpha1(vertex1,material1 + 0.1,1.0); - SurfaceVertex surfaceVertex2Alpha1(vertex2,material1 + 0.1,1.0); - multiMaterialPatch->addTriangle(surfaceVertex0Alpha1, surfaceVertex1Alpha1, surfaceVertex2Alpha1); - } - - { - SurfaceVertex surfaceVertex0Alpha1(vertex0,material0 + 0.1,1.0); - SurfaceVertex surfaceVertex1Alpha1(vertex1,material0 + 0.1,0.0); - SurfaceVertex surfaceVertex2Alpha1(vertex2,material0 + 0.1,0.0); - multiMaterialPatch->addTriangle(surfaceVertex0Alpha1, surfaceVertex1Alpha1, surfaceVertex2Alpha1); - } - } - else - { - { - SurfaceVertex surfaceVertex0Alpha1(vertex0,material0 + 0.1,1.0); - SurfaceVertex surfaceVertex1Alpha1(vertex1,material0 + 0.1,0.0); - SurfaceVertex surfaceVertex2Alpha1(vertex2,material0 + 0.1,0.0); - multiMaterialPatch->addTriangle(surfaceVertex0Alpha1, surfaceVertex1Alpha1, surfaceVertex2Alpha1); - } - - { - SurfaceVertex surfaceVertex0Alpha1(vertex0,material1 + 0.1,0.0); - SurfaceVertex surfaceVertex1Alpha1(vertex1,material1 + 0.1,1.0); - SurfaceVertex surfaceVertex2Alpha1(vertex2,material1 + 0.1,0.0); - multiMaterialPatch->addTriangle(surfaceVertex0Alpha1, surfaceVertex1Alpha1, surfaceVertex2Alpha1); - } - - { - SurfaceVertex surfaceVertex0Alpha1(vertex0,material2 + 0.1,0.0); - SurfaceVertex surfaceVertex1Alpha1(vertex1,material2 + 0.1,0.0); - SurfaceVertex surfaceVertex2Alpha1(vertex2,material2 + 0.1,1.0); - multiMaterialPatch->addTriangle(surfaceVertex0Alpha1, surfaceVertex1Alpha1, surfaceVertex2Alpha1); - } - }*/ - }//For each triangle - }//For each cell - - //FIXME - can it happen that we have no vertices or triangles? Should exit early? - - - //for(std::map::iterator iterPatch = surfacePatchMapResult.begin(); iterPatch != surfacePatchMapResult.end(); ++iterPatch) - { - - std::vector::iterator iterSurfaceVertex = singleMaterialPatch->getVertices().begin(); - while(iterSurfaceVertex != singleMaterialPatch->getVertices().end()) - { - Vector3DFloat tempNormal = computeSmoothNormal(static_cast(iterSurfaceVertex->getPosition() + offset), CENTRAL_DIFFERENCE); - const_cast(*iterSurfaceVertex).setNormal(tempNormal); - ++iterSurfaceVertex; - } - - iterSurfaceVertex = multiMaterialPatch->getVertices().begin(); - while(iterSurfaceVertex != multiMaterialPatch->getVertices().end()) - { - Vector3DFloat tempNormal = computeSmoothNormal(static_cast(iterSurfaceVertex->getPosition() + offset), CENTRAL_DIFFERENCE); - const_cast(*iterSurfaceVertex).setNormal(tempNormal); - ++iterSurfaceVertex; - } - } - } - - Vector3DFloat PolyVoxSceneManager::computeNormal(const Vector3DFloat& position, NormalGenerationMethod normalGenerationMethod) const - { - - - const float posX = position.x(); - const float posY = position.y(); - const float posZ = position.z(); - - const uint16_t floorX = static_cast(posX); - const uint16_t floorY = static_cast(posY); - const uint16_t floorZ = static_cast(posZ); - - //Check all corners are within the volume, allowing a boundary for gradient estimation - bool lowerCornerInside = volumeData->containsPoint(Vector3DInt32(floorX, floorY, floorZ),1); - bool upperCornerInside = volumeData->containsPoint(Vector3DInt32(floorX+1, floorY+1, floorZ+1),1); - if((!lowerCornerInside) || (!upperCornerInside)) - { - normalGenerationMethod = SIMPLE; - } - - Vector3DFloat result; - - VolumeIterator volIter(*volumeData); //FIXME - save this somewhere - could be expensive to create? - - - if(normalGenerationMethod == SOBEL) - { - volIter.setPosition(static_cast(posX),static_cast(posY),static_cast(posZ)); - const Vector3DFloat gradFloor = computeSobelGradient(volIter); - if((posX - floorX) > 0.25) //The result should be 0.0 or 0.5 - { - volIter.setPosition(static_cast(posX+1.0),static_cast(posY),static_cast(posZ)); - } - if((posY - floorY) > 0.25) //The result should be 0.0 or 0.5 - { - volIter.setPosition(static_cast(posX),static_cast(posY+1.0),static_cast(posZ)); - } - if((posZ - floorZ) > 0.25) //The result should be 0.0 or 0.5 - { - volIter.setPosition(static_cast(posX),static_cast(posY),static_cast(posZ+1.0)); - } - const Vector3DFloat gradCeil = computeSobelGradient(volIter); - result = ((gradFloor + gradCeil) * -1.0); - if(result.lengthSquared() < 0.0001) - { - //Operation failed - fall back on simple gradient estimation - normalGenerationMethod = SIMPLE; - } - } - if(normalGenerationMethod == CENTRAL_DIFFERENCE) - { - volIter.setPosition(static_cast(posX),static_cast(posY),static_cast(posZ)); - const Vector3DFloat gradFloor = computeCentralDifferenceGradient(volIter); - if((posX - floorX) > 0.25) //The result should be 0.0 or 0.5 - { - volIter.setPosition(static_cast(posX+1.0),static_cast(posY),static_cast(posZ)); - } - if((posY - floorY) > 0.25) //The result should be 0.0 or 0.5 - { - volIter.setPosition(static_cast(posX),static_cast(posY+1.0),static_cast(posZ)); - } - if((posZ - floorZ) > 0.25) //The result should be 0.0 or 0.5 - { - volIter.setPosition(static_cast(posX),static_cast(posY),static_cast(posZ+1.0)); - } - const Vector3DFloat gradCeil = computeCentralDifferenceGradient(volIter); - result = ((gradFloor + gradCeil) * -1.0); - if(result.lengthSquared() < 0.0001) - { - //Operation failed - fall back on simple gradient estimation - normalGenerationMethod = SIMPLE; - } - } - if(normalGenerationMethod == SIMPLE) - { - volIter.setPosition(static_cast(posX),static_cast(posY),static_cast(posZ)); - const uint8_t uFloor = volIter.getVoxel() > 0 ? 1 : 0; - if((posX - floorX) > 0.25) //The result should be 0.0 or 0.5 - { - uint8_t uCeil = volIter.peekVoxel1px0py0pz() > 0 ? 1 : 0; - result = Vector3DFloat(static_cast(uFloor - uCeil),0.0,0.0); - } - else if((posY - floorY) > 0.25) //The result should be 0.0 or 0.5 - { - uint8_t uCeil = volIter.peekVoxel0px1py0pz() > 0 ? 1 : 0; - result = Vector3DFloat(0.0,static_cast(uFloor - uCeil),0.0); - } - else if((posZ - floorZ) > 0.25) //The result should be 0.0 or 0.5 - { - uint8_t uCeil = volIter.peekVoxel0px0py1pz() > 0 ? 1 : 0; - result = Vector3DFloat(0.0, 0.0,static_cast(uFloor - uCeil)); - } - } - return result; - } - - Vector3DFloat PolyVoxSceneManager::computeSmoothNormal(const Vector3DFloat& position, NormalGenerationMethod normalGenerationMethod) const - { - - - const float posX = position.x(); - const float posY = position.y(); - const float posZ = position.z(); - - const uint16_t floorX = static_cast(posX); - const uint16_t floorY = static_cast(posY); - const uint16_t floorZ = static_cast(posZ); - - //Check all corners are within the volume, allowing a boundary for gradient estimation - bool lowerCornerInside = volumeData->containsPoint(Vector3DInt32(floorX, floorY, floorZ),1); - bool upperCornerInside = volumeData->containsPoint(Vector3DInt32(floorX+1, floorY+1, floorZ+1),1); - if((!lowerCornerInside) || (!upperCornerInside)) - { - normalGenerationMethod = SIMPLE; - } - - Vector3DFloat result; - - VolumeIterator volIter(*volumeData); //FIXME - save this somewhere - could be expensive to create? - - - if(normalGenerationMethod == SOBEL) - { - volIter.setPosition(static_cast(posX),static_cast(posY),static_cast(posZ)); - const Vector3DFloat gradFloor = computeSobelGradient(volIter); - if((posX - floorX) > 0.25) //The result should be 0.0 or 0.5 - { - volIter.setPosition(static_cast(posX+1.0),static_cast(posY),static_cast(posZ)); - } - if((posY - floorY) > 0.25) //The result should be 0.0 or 0.5 - { - volIter.setPosition(static_cast(posX),static_cast(posY+1.0),static_cast(posZ)); - } - if((posZ - floorZ) > 0.25) //The result should be 0.0 or 0.5 - { - volIter.setPosition(static_cast(posX),static_cast(posY),static_cast(posZ+1.0)); - } - const Vector3DFloat gradCeil = computeSobelGradient(volIter); - result = ((gradFloor + gradCeil) * -1.0); - if(result.lengthSquared() < 0.0001) - { - //Operation failed - fall back on simple gradient estimation - normalGenerationMethod = SIMPLE; - } - } - if(normalGenerationMethod == CENTRAL_DIFFERENCE) - { - volIter.setPosition(static_cast(posX),static_cast(posY),static_cast(posZ)); - const Vector3DFloat gradFloor = computeSmoothCentralDifferenceGradient(volIter); - if((posX - floorX) > 0.25) //The result should be 0.0 or 0.5 - { - volIter.setPosition(static_cast(posX+1.0),static_cast(posY),static_cast(posZ)); - } - if((posY - floorY) > 0.25) //The result should be 0.0 or 0.5 - { - volIter.setPosition(static_cast(posX),static_cast(posY+1.0),static_cast(posZ)); - } - if((posZ - floorZ) > 0.25) //The result should be 0.0 or 0.5 - { - volIter.setPosition(static_cast(posX),static_cast(posY),static_cast(posZ+1.0)); - } - const Vector3DFloat gradCeil = computeSmoothCentralDifferenceGradient(volIter); - result = ((gradFloor + gradCeil) * -1.0); - if(result.lengthSquared() < 0.0001) - { - //Operation failed - fall back on simple gradient estimation - normalGenerationMethod = SIMPLE; - } - } - if(normalGenerationMethod == SIMPLE) - { - volIter.setPosition(static_cast(posX),static_cast(posY),static_cast(posZ)); - const uint8_t uFloor = volIter.getVoxel() > 0 ? 1 : 0; - if((posX - floorX) > 0.25) //The result should be 0.0 or 0.5 - { - uint8_t uCeil = volIter.peekVoxel1px0py0pz() > 0 ? 1 : 0; - result = Vector3DFloat(static_cast(uFloor - uCeil),0.0,0.0); - } - else if((posY - floorY) > 0.25) //The result should be 0.0 or 0.5 - { - uint8_t uCeil = volIter.peekVoxel0px1py0pz() > 0 ? 1 : 0; - result = Vector3DFloat(0.0,static_cast(uFloor - uCeil),0.0); - } - else if((posZ - floorZ) > 0.25) //The result should be 0.0 or 0.5 - { - uint8_t uCeil = volIter.peekVoxel0px0py1pz() > 0 ? 1 : 0; - result = Vector3DFloat(0.0, 0.0,static_cast(uFloor - uCeil)); - } - } - return result; - } - void PolyVoxSceneManager::markVoxelChanged(uint16_t x, uint16_t y, uint16_t z) { //If we are not on a boundary, just mark one region. diff --git a/source/SurfaceExtractors.cpp b/source/SurfaceExtractors.cpp new file mode 100644 index 00000000..7559b0e0 --- /dev/null +++ b/source/SurfaceExtractors.cpp @@ -0,0 +1,816 @@ +#include "SurfaceExtractors.h" + +#include "BlockVolume.h" +#include "GradientEstimators.h" +#include "IndexedSurfacePatch.h" +#include "MarchingCubesTables.h" +#include "VolumeIterator.h" + +using namespace boost; + +namespace PolyVox +{ + void generateRoughMeshDataForRegion(BlockVolume* volumeData, uint16_t regionX, uint16_t regionY, uint16_t regionZ, IndexedSurfacePatch* singleMaterialPatch, IndexedSurfacePatch* multiMaterialPatch) + { + //First and last voxels in the region + const uint16_t firstX = regionX * POLYVOX_REGION_SIDE_LENGTH; + const uint16_t firstY = regionY * POLYVOX_REGION_SIDE_LENGTH; + const uint16_t firstZ = regionZ * POLYVOX_REGION_SIDE_LENGTH; + const uint16_t lastX = (std::min)(firstX + POLYVOX_REGION_SIDE_LENGTH-1,volumeData->getSideLength()-2); + const uint16_t lastY = (std::min)(firstY + POLYVOX_REGION_SIDE_LENGTH-1,volumeData->getSideLength()-2); + const uint16_t lastZ = (std::min)(firstZ + POLYVOX_REGION_SIDE_LENGTH-1,volumeData->getSideLength()-2); + + //Offset from lower block corner + const Vector3DFloat offset(firstX,firstY,firstZ); + + Vector3DFloat vertlist[12]; + uint8_t vertMaterials[12]; + VolumeIterator volIter(*volumeData); + volIter.setValidRegion(firstX,firstY,firstZ,lastX,lastY,lastZ); + + ////////////////////////////////////////////////////////////////////////// + //Get mesh data + ////////////////////////////////////////////////////////////////////////// + + //Iterate over each cell in the region + for(volIter.setPosition(firstX,firstY,firstZ);volIter.isValidForRegion();volIter.moveForwardInRegion()) + { + //Current position + const uint16_t x = volIter.getPosX(); + const uint16_t y = volIter.getPosY(); + const uint16_t z = volIter.getPosZ(); + + //Voxels values + const uint8_t v000 = volIter.getVoxel(); + const uint8_t v100 = volIter.peekVoxel1px0py0pz(); + const uint8_t v010 = volIter.peekVoxel0px1py0pz(); + const uint8_t v110 = volIter.peekVoxel1px1py0pz(); + const uint8_t v001 = volIter.peekVoxel0px0py1pz(); + const uint8_t v101 = volIter.peekVoxel1px0py1pz(); + const uint8_t v011 = volIter.peekVoxel0px1py1pz(); + const uint8_t v111 = volIter.peekVoxel1px1py1pz(); + + //Determine the index into the edge table which tells us which vertices are inside of the surface + uint8_t iCubeIndex = 0; + + if (v000 == 0) iCubeIndex |= 1; + if (v100 == 0) iCubeIndex |= 2; + if (v110 == 0) iCubeIndex |= 4; + if (v010 == 0) iCubeIndex |= 8; + if (v001 == 0) iCubeIndex |= 16; + if (v101 == 0) iCubeIndex |= 32; + if (v111 == 0) iCubeIndex |= 64; + if (v011 == 0) iCubeIndex |= 128; + + /* 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) + { + vertlist[0].setX(x + 0.5f); + vertlist[0].setY(y); + vertlist[0].setZ(z); + vertMaterials[0] = v000 | v100; //Because one of these is 0, the or operation takes the max. + } + if (edgeTable[iCubeIndex] & 2) + { + vertlist[1].setX(x + 1.0f); + vertlist[1].setY(y + 0.5f); + vertlist[1].setZ(z); + vertMaterials[1] = v100 | v110; + } + if (edgeTable[iCubeIndex] & 4) + { + vertlist[2].setX(x + 0.5f); + vertlist[2].setY(y + 1.0f); + vertlist[2].setZ(z); + vertMaterials[2] = v010 | v110; + } + if (edgeTable[iCubeIndex] & 8) + { + vertlist[3].setX(x); + vertlist[3].setY(y + 0.5f); + vertlist[3].setZ(z); + vertMaterials[3] = v000 | v010; + } + if (edgeTable[iCubeIndex] & 16) + { + vertlist[4].setX(x + 0.5f); + vertlist[4].setY(y); + vertlist[4].setZ(z + 1.0f); + vertMaterials[4] = v001 | v101; + } + if (edgeTable[iCubeIndex] & 32) + { + vertlist[5].setX(x + 1.0f); + vertlist[5].setY(y + 0.5f); + vertlist[5].setZ(z + 1.0f); + vertMaterials[5] = v101 | v111; + } + if (edgeTable[iCubeIndex] & 64) + { + vertlist[6].setX(x + 0.5f); + vertlist[6].setY(y + 1.0f); + vertlist[6].setZ(z + 1.0f); + vertMaterials[6] = v011 | v111; + } + if (edgeTable[iCubeIndex] & 128) + { + vertlist[7].setX(x); + vertlist[7].setY(y + 0.5f); + vertlist[7].setZ(z + 1.0f); + vertMaterials[7] = v001 | v011; + } + if (edgeTable[iCubeIndex] & 256) + { + vertlist[8].setX(x); + vertlist[8].setY(y); + vertlist[8].setZ(z + 0.5f); + vertMaterials[8] = v000 | v001; + } + if (edgeTable[iCubeIndex] & 512) + { + vertlist[9].setX(x + 1.0f); + vertlist[9].setY(y); + vertlist[9].setZ(z + 0.5f); + vertMaterials[9] = v100 | v101; + } + if (edgeTable[iCubeIndex] & 1024) + { + vertlist[10].setX(x + 1.0f); + vertlist[10].setY(y + 1.0f); + vertlist[10].setZ(z + 0.5f); + vertMaterials[10] = v110 | v111; + } + if (edgeTable[iCubeIndex] & 2048) + { + vertlist[11].setX(x); + vertlist[11].setY(y + 1.0f); + vertlist[11].setZ(z + 0.5f); + vertMaterials[11] = v010 | v011; + } + + for (int i=0;triTable[iCubeIndex][i]!=-1;i+=3) + { + //The three vertices forming a triangle + const Vector3DFloat vertex0 = vertlist[triTable[iCubeIndex][i ]] - offset; + const Vector3DFloat vertex1 = vertlist[triTable[iCubeIndex][i+1]] - offset; + const Vector3DFloat vertex2 = vertlist[triTable[iCubeIndex][i+2]] - offset; + + //Cast to floats and divide by two. + //const Vector3DFloat vertex0AsFloat = (static_cast(vertex0) / 2.0f) - offset; + //const Vector3DFloat vertex1AsFloat = (static_cast(vertex1) / 2.0f) - offset; + //const Vector3DFloat vertex2AsFloat = (static_cast(vertex2) / 2.0f) - offset; + + const uint8_t material0 = vertMaterials[triTable[iCubeIndex][i ]]; + const uint8_t material1 = vertMaterials[triTable[iCubeIndex][i+1]]; + const uint8_t material2 = vertMaterials[triTable[iCubeIndex][i+2]]; + + + //If all the materials are the same, we just need one triangle for that material with all the alphas set high. + if((material0 == material1) && (material1 == material2)) + { + SurfaceVertex surfaceVertex0Alpha1(vertex0,material0 + 0.1f,1.0f); + SurfaceVertex surfaceVertex1Alpha1(vertex1,material1 + 0.1f,1.0f); + SurfaceVertex surfaceVertex2Alpha1(vertex2,material2 + 0.1f,1.0f); + singleMaterialPatch->addTriangle(surfaceVertex0Alpha1, surfaceVertex1Alpha1, surfaceVertex2Alpha1); + } + else if(material0 == material1) + { + { + SurfaceVertex surfaceVertex0Alpha1(vertex0,material0 + 0.1f,1.0f); + SurfaceVertex surfaceVertex1Alpha1(vertex1,material0 + 0.1f,1.0f); + SurfaceVertex surfaceVertex2Alpha1(vertex2,material0 + 0.1f,0.0f); + multiMaterialPatch->addTriangle(surfaceVertex0Alpha1, surfaceVertex1Alpha1, surfaceVertex2Alpha1); + } + + { + SurfaceVertex surfaceVertex0Alpha1(vertex0,material2 + 0.1f,0.0f); + SurfaceVertex surfaceVertex1Alpha1(vertex1,material2 + 0.1f,0.0f); + SurfaceVertex surfaceVertex2Alpha1(vertex2,material2 + 0.1f,1.0f); + multiMaterialPatch->addTriangle(surfaceVertex0Alpha1, surfaceVertex1Alpha1, surfaceVertex2Alpha1); + } + } + else if(material0 == material2) + { + { + SurfaceVertex surfaceVertex0Alpha1(vertex0,material0 + 0.1f,1.0f); + SurfaceVertex surfaceVertex1Alpha1(vertex1,material0 + 0.1f,0.0f); + SurfaceVertex surfaceVertex2Alpha1(vertex2,material0 + 0.1f,1.0f); + multiMaterialPatch->addTriangle(surfaceVertex0Alpha1, surfaceVertex1Alpha1, surfaceVertex2Alpha1); + } + + { + SurfaceVertex surfaceVertex0Alpha1(vertex0,material1 + 0.1f,0.0f); + SurfaceVertex surfaceVertex1Alpha1(vertex1,material1 + 0.1f,1.0f); + SurfaceVertex surfaceVertex2Alpha1(vertex2,material1 + 0.1f,0.0f); + multiMaterialPatch->addTriangle(surfaceVertex0Alpha1, surfaceVertex1Alpha1, surfaceVertex2Alpha1); + } + } + else if(material1 == material2) + { + { + SurfaceVertex surfaceVertex0Alpha1(vertex0,material1 + 0.1f,0.0f); + SurfaceVertex surfaceVertex1Alpha1(vertex1,material1 + 0.1f,1.0f); + SurfaceVertex surfaceVertex2Alpha1(vertex2,material1 + 0.1f,1.0f); + multiMaterialPatch->addTriangle(surfaceVertex0Alpha1, surfaceVertex1Alpha1, surfaceVertex2Alpha1); + } + + { + SurfaceVertex surfaceVertex0Alpha1(vertex0,material0 + 0.1f,1.0f); + SurfaceVertex surfaceVertex1Alpha1(vertex1,material0 + 0.1f,0.0f); + SurfaceVertex surfaceVertex2Alpha1(vertex2,material0 + 0.1f,0.0f); + multiMaterialPatch->addTriangle(surfaceVertex0Alpha1, surfaceVertex1Alpha1, surfaceVertex2Alpha1); + } + } + else + { + { + SurfaceVertex surfaceVertex0Alpha1(vertex0,material0 + 0.1f,1.0f); + SurfaceVertex surfaceVertex1Alpha1(vertex1,material0 + 0.1f,0.0f); + SurfaceVertex surfaceVertex2Alpha1(vertex2,material0 + 0.1f,0.0f); + multiMaterialPatch->addTriangle(surfaceVertex0Alpha1, surfaceVertex1Alpha1, surfaceVertex2Alpha1); + } + + { + SurfaceVertex surfaceVertex0Alpha1(vertex0,material1 + 0.1f,0.0f); + SurfaceVertex surfaceVertex1Alpha1(vertex1,material1 + 0.1f,1.0f); + SurfaceVertex surfaceVertex2Alpha1(vertex2,material1 + 0.1f,0.0f); + multiMaterialPatch->addTriangle(surfaceVertex0Alpha1, surfaceVertex1Alpha1, surfaceVertex2Alpha1); + } + + { + SurfaceVertex surfaceVertex0Alpha1(vertex0,material2 + 0.1f,0.0f); + SurfaceVertex surfaceVertex1Alpha1(vertex1,material2 + 0.1f,0.0f); + SurfaceVertex surfaceVertex2Alpha1(vertex2,material2 + 0.1f,1.0f); + multiMaterialPatch->addTriangle(surfaceVertex0Alpha1, surfaceVertex1Alpha1, surfaceVertex2Alpha1); + } + } + //If there not all the same, we need one triangle for each unique material. + //We'll also need some vertices with low alphas for blending. + /*else + { + SurfaceVertex surfaceVertex0Alpha0(vertex0,0.0); + SurfaceVertex surfaceVertex1Alpha0(vertex1,0.0); + SurfaceVertex surfaceVertex2Alpha0(vertex2,0.0); + + if(material0 == material1) + { + surfacePatchMapResult[material0]->addTriangle(surfaceVertex0Alpha1, surfaceVertex1Alpha1, surfaceVertex2Alpha0); + surfacePatchMapResult[material2]->addTriangle(surfaceVertex0Alpha0, surfaceVertex1Alpha0, surfaceVertex2Alpha1); + } + else if(material1 == material2) + { + surfacePatchMapResult[material1]->addTriangle(surfaceVertex0Alpha0, surfaceVertex1Alpha1, surfaceVertex2Alpha1); + surfacePatchMapResult[material0]->addTriangle(surfaceVertex0Alpha1, surfaceVertex1Alpha0, surfaceVertex2Alpha0); + } + else if(material2 == material0) + { + surfacePatchMapResult[material0]->addTriangle(surfaceVertex0Alpha1, surfaceVertex1Alpha0, surfaceVertex2Alpha1); + surfacePatchMapResult[material1]->addTriangle(surfaceVertex0Alpha0, surfaceVertex1Alpha1, surfaceVertex2Alpha0); + } + else + { + surfacePatchMapResult[material0]->addTriangle(surfaceVertex0Alpha1, surfaceVertex1Alpha0, surfaceVertex2Alpha0); + surfacePatchMapResult[material1]->addTriangle(surfaceVertex0Alpha0, surfaceVertex1Alpha1, surfaceVertex2Alpha0); + surfacePatchMapResult[material2]->addTriangle(surfaceVertex0Alpha0, surfaceVertex1Alpha0, surfaceVertex2Alpha1); + } + }*/ + }//For each triangle + }//For each cell + + //FIXME - can it happen that we have no vertices or triangles? Should exit early? + + + //for(std::map::iterator iterPatch = surfacePatchMapResult.begin(); iterPatch != surfacePatchMapResult.end(); ++iterPatch) + { + + std::vector::iterator iterSurfaceVertex = singleMaterialPatch->getVertices().begin(); + while(iterSurfaceVertex != singleMaterialPatch->getVertices().end()) + { + Vector3DFloat tempNormal = computeNormal(volumeData, static_cast(iterSurfaceVertex->getPosition() + offset), CENTRAL_DIFFERENCE); + const_cast(*iterSurfaceVertex).setNormal(tempNormal); + ++iterSurfaceVertex; + } + + iterSurfaceVertex = multiMaterialPatch->getVertices().begin(); + while(iterSurfaceVertex != multiMaterialPatch->getVertices().end()) + { + Vector3DFloat tempNormal = computeNormal(volumeData, static_cast(iterSurfaceVertex->getPosition() + offset), CENTRAL_DIFFERENCE); + const_cast(*iterSurfaceVertex).setNormal(tempNormal); + ++iterSurfaceVertex; + } + + uint16_t noOfRemovedVertices = 0; + //do + { + //noOfRemovedVertices = iterPatch->second.decimate(); + } + //while(noOfRemovedVertices > 10); //We don't worry about the last few vertices - it's not worth the overhead of calling the function. + } + + //return singleMaterialPatch; + } + + Vector3DFloat computeNormal(BlockVolume* volumeData, const Vector3DFloat& position, NormalGenerationMethod normalGenerationMethod) + { + const float posX = position.x(); + const float posY = position.y(); + const float posZ = position.z(); + + const uint16_t floorX = static_cast(posX); + const uint16_t floorY = static_cast(posY); + const uint16_t floorZ = static_cast(posZ); + + //Check all corners are within the volume, allowing a boundary for gradient estimation + bool lowerCornerInside = volumeData->containsPoint(Vector3DInt32(floorX, floorY, floorZ),1); + bool upperCornerInside = volumeData->containsPoint(Vector3DInt32(floorX+1, floorY+1, floorZ+1),1); + if((!lowerCornerInside) || (!upperCornerInside)) + { + normalGenerationMethod = SIMPLE; + } + + Vector3DFloat result; + + VolumeIterator volIter(*volumeData); //FIXME - save this somewhere - could be expensive to create? + + + if(normalGenerationMethod == SOBEL) + { + volIter.setPosition(static_cast(posX),static_cast(posY),static_cast(posZ)); + const Vector3DFloat gradFloor = computeSobelGradient(volIter); + if((posX - floorX) > 0.25) //The result should be 0.0 or 0.5 + { + volIter.setPosition(static_cast(posX+1.0),static_cast(posY),static_cast(posZ)); + } + if((posY - floorY) > 0.25) //The result should be 0.0 or 0.5 + { + volIter.setPosition(static_cast(posX),static_cast(posY+1.0),static_cast(posZ)); + } + if((posZ - floorZ) > 0.25) //The result should be 0.0 or 0.5 + { + volIter.setPosition(static_cast(posX),static_cast(posY),static_cast(posZ+1.0)); + } + const Vector3DFloat gradCeil = computeSobelGradient(volIter); + result = ((gradFloor + gradCeil) * -1.0); + if(result.lengthSquared() < 0.0001) + { + //Operation failed - fall back on simple gradient estimation + normalGenerationMethod = SIMPLE; + } + } + if(normalGenerationMethod == CENTRAL_DIFFERENCE) + { + volIter.setPosition(static_cast(posX),static_cast(posY),static_cast(posZ)); + const Vector3DFloat gradFloor = computeCentralDifferenceGradient(volIter); + if((posX - floorX) > 0.25) //The result should be 0.0 or 0.5 + { + volIter.setPosition(static_cast(posX+1.0),static_cast(posY),static_cast(posZ)); + } + if((posY - floorY) > 0.25) //The result should be 0.0 or 0.5 + { + volIter.setPosition(static_cast(posX),static_cast(posY+1.0),static_cast(posZ)); + } + if((posZ - floorZ) > 0.25) //The result should be 0.0 or 0.5 + { + volIter.setPosition(static_cast(posX),static_cast(posY),static_cast(posZ+1.0)); + } + const Vector3DFloat gradCeil = computeCentralDifferenceGradient(volIter); + result = ((gradFloor + gradCeil) * -1.0); + if(result.lengthSquared() < 0.0001) + { + //Operation failed - fall back on simple gradient estimation + normalGenerationMethod = SIMPLE; + } + } + if(normalGenerationMethod == SIMPLE) + { + volIter.setPosition(static_cast(posX),static_cast(posY),static_cast(posZ)); + const uint8_t uFloor = volIter.getVoxel() > 0 ? 1 : 0; + if((posX - floorX) > 0.25) //The result should be 0.0 or 0.5 + { + uint8_t uCeil = volIter.peekVoxel1px0py0pz() > 0 ? 1 : 0; + result = Vector3DFloat(static_cast(uFloor - uCeil),0.0,0.0); + } + else if((posY - floorY) > 0.25) //The result should be 0.0 or 0.5 + { + uint8_t uCeil = volIter.peekVoxel0px1py0pz() > 0 ? 1 : 0; + result = Vector3DFloat(0.0,static_cast(uFloor - uCeil),0.0); + } + else if((posZ - floorZ) > 0.25) //The result should be 0.0 or 0.5 + { + uint8_t uCeil = volIter.peekVoxel0px0py1pz() > 0 ? 1 : 0; + result = Vector3DFloat(0.0, 0.0,static_cast(uFloor - uCeil)); + } + } + return result; + } + + void generateSmoothMeshDataForRegion(BlockVolume* volumeData, uint16_t regionX, uint16_t regionY, uint16_t regionZ, IndexedSurfacePatch* singleMaterialPatch, IndexedSurfacePatch* multiMaterialPatch) + { + //First and last voxels in the region + const uint16_t firstX = regionX * POLYVOX_REGION_SIDE_LENGTH; + const uint16_t firstY = regionY * POLYVOX_REGION_SIDE_LENGTH; + const uint16_t firstZ = regionZ * POLYVOX_REGION_SIDE_LENGTH; + const uint16_t lastX = (std::min)(firstX + POLYVOX_REGION_SIDE_LENGTH-1,volumeData->getSideLength()-2); + const uint16_t lastY = (std::min)(firstY + POLYVOX_REGION_SIDE_LENGTH-1,volumeData->getSideLength()-2); + const uint16_t lastZ = (std::min)(firstZ + POLYVOX_REGION_SIDE_LENGTH-1,volumeData->getSideLength()-2); + + //Offset from lower block corner + const Vector3DFloat offset(firstX,firstY,firstZ); + + Vector3DFloat vertlist[12]; + uint8_t vertMaterials[12]; + VolumeIterator volIter(*volumeData); + volIter.setValidRegion(firstX,firstY,firstZ,lastX,lastY,lastZ); + + const float threshold = 0.5f; + + ////////////////////////////////////////////////////////////////////////// + //Get mesh data + ////////////////////////////////////////////////////////////////////////// + + //Iterate over each cell in the region + for(volIter.setPosition(firstX,firstY,firstZ);volIter.isValidForRegion();volIter.moveForwardInRegion()) + { + //Current position + const uint16_t x = volIter.getPosX(); + const uint16_t y = volIter.getPosY(); + const uint16_t z = volIter.getPosZ(); + + //Voxels values + VolumeIterator tempVolIter(*volumeData); + tempVolIter.setPosition(x,y,z); + const float v000 = tempVolIter.getAveragedVoxel(1); + tempVolIter.setPosition(x+1,y,z); + const float v100 = tempVolIter.getAveragedVoxel(1); + tempVolIter.setPosition(x,y+1,z); + const float v010 = tempVolIter.getAveragedVoxel(1); + tempVolIter.setPosition(x+1,y+1,z); + const float v110 = tempVolIter.getAveragedVoxel(1); + tempVolIter.setPosition(x,y,z+1); + const float v001 = tempVolIter.getAveragedVoxel(1); + tempVolIter.setPosition(x+1,y,z+1); + const float v101 = tempVolIter.getAveragedVoxel(1); + tempVolIter.setPosition(x,y+1,z+1); + const float v011 = tempVolIter.getAveragedVoxel(1); + tempVolIter.setPosition(x+1,y+1,z+1); + const float v111 = tempVolIter.getAveragedVoxel(1); + + //Determine the index into the edge table which tells us which vertices are inside of the surface + uint8_t iCubeIndex = 0; + + if (v000 < threshold) iCubeIndex |= 1; + if (v100 < threshold) iCubeIndex |= 2; + if (v110 < threshold) iCubeIndex |= 4; + if (v010 < threshold) iCubeIndex |= 8; + if (v001 < threshold) iCubeIndex |= 16; + if (v101 < threshold) iCubeIndex |= 32; + if (v111 < threshold) iCubeIndex |= 64; + if (v011 < threshold) iCubeIndex |= 128; + + /* 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) + { + float a = v000; + float b = v100; + float val = (threshold-a)/(b-a); + vertlist[0].setX(x + val); + vertlist[0].setY(y); + vertlist[0].setZ(z); + vertMaterials[0] = 1;//v000 | v100; //Because one of these is 0, the or operation takes the max. + } + if (edgeTable[iCubeIndex] & 2) + { + float a = v100; + float b = v110; + float val = (threshold-a)/(b-a); + vertlist[1].setX(x + 1.0f); + vertlist[1].setY(y + val); + vertlist[1].setZ(z); + vertMaterials[1] = 1;//v100 | v110; + } + if (edgeTable[iCubeIndex] & 4) + { + float a = v010; + float b = v110; + float val = (threshold-a)/(b-a); + vertlist[2].setX(x + val); + vertlist[2].setY(y + 1.0f); + vertlist[2].setZ(z); + vertMaterials[2] = 1;//v010 | v110; + } + if (edgeTable[iCubeIndex] & 8) + { + float a = v000; + float b = v010; + float val = (threshold-a)/(b-a); + vertlist[3].setX(x); + vertlist[3].setY(y + val); + vertlist[3].setZ(z); + vertMaterials[3] = 1;//v000 | v010; + } + if (edgeTable[iCubeIndex] & 16) + { + float a = v001; + float b = v101; + float val = (threshold-a)/(b-a); + vertlist[4].setX(x + val); + vertlist[4].setY(y); + vertlist[4].setZ(z + 1.0f); + vertMaterials[4] = 1;//v001 | v101; + } + if (edgeTable[iCubeIndex] & 32) + { + float a = v101; + float b = v111; + float val = (threshold-a)/(b-a); + vertlist[5].setX(x + 1.0f); + vertlist[5].setY(y + val); + vertlist[5].setZ(z + 1.0f); + vertMaterials[5] = 1;//v101 | v111; + } + if (edgeTable[iCubeIndex] & 64) + { + float a = v011; + float b = v111; + float val = (threshold-a)/(b-a); + vertlist[6].setX(x + val); + vertlist[6].setY(y + 1.0f); + vertlist[6].setZ(z + 1.0f); + vertMaterials[6] = 1;//v011 | v111; + } + if (edgeTable[iCubeIndex] & 128) + { + float a = v001; + float b = v011; + float val = (threshold-a)/(b-a); + vertlist[7].setX(x); + vertlist[7].setY(y + val); + vertlist[7].setZ(z + 1.0f); + vertMaterials[7] = 1;//v001 | v011; + } + if (edgeTable[iCubeIndex] & 256) + { + float a = v000; + float b = v001; + float val = (threshold-a)/(b-a); + vertlist[8].setX(x); + vertlist[8].setY(y); + vertlist[8].setZ(z + val); + vertMaterials[8] = 1;//v000 | v001; + } + if (edgeTable[iCubeIndex] & 512) + { + float a = v100; + float b = v101; + float val = (threshold-a)/(b-a); + vertlist[9].setX(x + 1.0f); + vertlist[9].setY(y); + vertlist[9].setZ(z + val); + vertMaterials[9] = 1;//v100 | v101; + } + if (edgeTable[iCubeIndex] & 1024) + { + float a = v110; + float b = v111; + float val = (threshold-a)/(b-a); + vertlist[10].setX(x + 1.0f); + vertlist[10].setY(y + 1.0f); + vertlist[10].setZ(z + val); + vertMaterials[10] = 1;//v110 | v111; + } + if (edgeTable[iCubeIndex] & 2048) + { + float a = v010; + float b = v011; + float val = (threshold-a)/(b-a); + vertlist[11].setX(x); + vertlist[11].setY(y + 1.0f); + vertlist[11].setZ(z + val); + vertMaterials[11] = 1;//v010 | v011; + } + + for (int i=0;triTable[iCubeIndex][i]!=-1;i+=3) + { + //The three vertices forming a triangle + const Vector3DFloat vertex0 = vertlist[triTable[iCubeIndex][i ]] - offset; + const Vector3DFloat vertex1 = vertlist[triTable[iCubeIndex][i+1]] - offset; + const Vector3DFloat vertex2 = vertlist[triTable[iCubeIndex][i+2]] - offset; + + const uint8_t material0 = vertMaterials[triTable[iCubeIndex][i ]]; + const uint8_t material1 = vertMaterials[triTable[iCubeIndex][i+1]]; + const uint8_t material2 = vertMaterials[triTable[iCubeIndex][i+2]]; + + //If all the materials are the same, we just need one triangle for that material with all the alphas set high. + /*if((material0 == material1) && (material1 == material2)) + {*/ + SurfaceVertex surfaceVertex0Alpha1(vertex0,material0 + 0.1f,1.0f); + SurfaceVertex surfaceVertex1Alpha1(vertex1,material1 + 0.1f,1.0f); + SurfaceVertex surfaceVertex2Alpha1(vertex2,material2 + 0.1f,1.0f); + singleMaterialPatch->addTriangle(surfaceVertex0Alpha1, surfaceVertex1Alpha1, surfaceVertex2Alpha1); + /*} + else if(material0 == material1) + { + { + SurfaceVertex surfaceVertex0Alpha1(vertex0,material0 + 0.1,1.0); + SurfaceVertex surfaceVertex1Alpha1(vertex1,material0 + 0.1,1.0); + SurfaceVertex surfaceVertex2Alpha1(vertex2,material0 + 0.1,0.0); + multiMaterialPatch->addTriangle(surfaceVertex0Alpha1, surfaceVertex1Alpha1, surfaceVertex2Alpha1); + } + + { + SurfaceVertex surfaceVertex0Alpha1(vertex0,material2 + 0.1,0.0); + SurfaceVertex surfaceVertex1Alpha1(vertex1,material2 + 0.1,0.0); + SurfaceVertex surfaceVertex2Alpha1(vertex2,material2 + 0.1,1.0); + multiMaterialPatch->addTriangle(surfaceVertex0Alpha1, surfaceVertex1Alpha1, surfaceVertex2Alpha1); + } + } + else if(material0 == material2) + { + { + SurfaceVertex surfaceVertex0Alpha1(vertex0,material0 + 0.1,1.0); + SurfaceVertex surfaceVertex1Alpha1(vertex1,material0 + 0.1,0.0); + SurfaceVertex surfaceVertex2Alpha1(vertex2,material0 + 0.1,1.0); + multiMaterialPatch->addTriangle(surfaceVertex0Alpha1, surfaceVertex1Alpha1, surfaceVertex2Alpha1); + } + + { + SurfaceVertex surfaceVertex0Alpha1(vertex0,material1 + 0.1,0.0); + SurfaceVertex surfaceVertex1Alpha1(vertex1,material1 + 0.1,1.0); + SurfaceVertex surfaceVertex2Alpha1(vertex2,material1 + 0.1,0.0); + multiMaterialPatch->addTriangle(surfaceVertex0Alpha1, surfaceVertex1Alpha1, surfaceVertex2Alpha1); + } + } + else if(material1 == material2) + { + { + SurfaceVertex surfaceVertex0Alpha1(vertex0,material1 + 0.1,0.0); + SurfaceVertex surfaceVertex1Alpha1(vertex1,material1 + 0.1,1.0); + SurfaceVertex surfaceVertex2Alpha1(vertex2,material1 + 0.1,1.0); + multiMaterialPatch->addTriangle(surfaceVertex0Alpha1, surfaceVertex1Alpha1, surfaceVertex2Alpha1); + } + + { + SurfaceVertex surfaceVertex0Alpha1(vertex0,material0 + 0.1,1.0); + SurfaceVertex surfaceVertex1Alpha1(vertex1,material0 + 0.1,0.0); + SurfaceVertex surfaceVertex2Alpha1(vertex2,material0 + 0.1,0.0); + multiMaterialPatch->addTriangle(surfaceVertex0Alpha1, surfaceVertex1Alpha1, surfaceVertex2Alpha1); + } + } + else + { + { + SurfaceVertex surfaceVertex0Alpha1(vertex0,material0 + 0.1,1.0); + SurfaceVertex surfaceVertex1Alpha1(vertex1,material0 + 0.1,0.0); + SurfaceVertex surfaceVertex2Alpha1(vertex2,material0 + 0.1,0.0); + multiMaterialPatch->addTriangle(surfaceVertex0Alpha1, surfaceVertex1Alpha1, surfaceVertex2Alpha1); + } + + { + SurfaceVertex surfaceVertex0Alpha1(vertex0,material1 + 0.1,0.0); + SurfaceVertex surfaceVertex1Alpha1(vertex1,material1 + 0.1,1.0); + SurfaceVertex surfaceVertex2Alpha1(vertex2,material1 + 0.1,0.0); + multiMaterialPatch->addTriangle(surfaceVertex0Alpha1, surfaceVertex1Alpha1, surfaceVertex2Alpha1); + } + + { + SurfaceVertex surfaceVertex0Alpha1(vertex0,material2 + 0.1,0.0); + SurfaceVertex surfaceVertex1Alpha1(vertex1,material2 + 0.1,0.0); + SurfaceVertex surfaceVertex2Alpha1(vertex2,material2 + 0.1,1.0); + multiMaterialPatch->addTriangle(surfaceVertex0Alpha1, surfaceVertex1Alpha1, surfaceVertex2Alpha1); + } + }*/ + }//For each triangle + }//For each cell + + //FIXME - can it happen that we have no vertices or triangles? Should exit early? + + + //for(std::map::iterator iterPatch = surfacePatchMapResult.begin(); iterPatch != surfacePatchMapResult.end(); ++iterPatch) + { + + std::vector::iterator iterSurfaceVertex = singleMaterialPatch->getVertices().begin(); + while(iterSurfaceVertex != singleMaterialPatch->getVertices().end()) + { + Vector3DFloat tempNormal = computeSmoothNormal(volumeData, static_cast(iterSurfaceVertex->getPosition() + offset), CENTRAL_DIFFERENCE); + const_cast(*iterSurfaceVertex).setNormal(tempNormal); + ++iterSurfaceVertex; + } + + iterSurfaceVertex = multiMaterialPatch->getVertices().begin(); + while(iterSurfaceVertex != multiMaterialPatch->getVertices().end()) + { + Vector3DFloat tempNormal = computeSmoothNormal(volumeData, static_cast(iterSurfaceVertex->getPosition() + offset), CENTRAL_DIFFERENCE); + const_cast(*iterSurfaceVertex).setNormal(tempNormal); + ++iterSurfaceVertex; + } + } + } + + Vector3DFloat computeSmoothNormal(BlockVolume* volumeData, const Vector3DFloat& position, NormalGenerationMethod normalGenerationMethod) + { + + + const float posX = position.x(); + const float posY = position.y(); + const float posZ = position.z(); + + const uint16_t floorX = static_cast(posX); + const uint16_t floorY = static_cast(posY); + const uint16_t floorZ = static_cast(posZ); + + //Check all corners are within the volume, allowing a boundary for gradient estimation + bool lowerCornerInside = volumeData->containsPoint(Vector3DInt32(floorX, floorY, floorZ),1); + bool upperCornerInside = volumeData->containsPoint(Vector3DInt32(floorX+1, floorY+1, floorZ+1),1); + if((!lowerCornerInside) || (!upperCornerInside)) + { + normalGenerationMethod = SIMPLE; + } + + Vector3DFloat result; + + VolumeIterator volIter(*volumeData); //FIXME - save this somewhere - could be expensive to create? + + + if(normalGenerationMethod == SOBEL) + { + volIter.setPosition(static_cast(posX),static_cast(posY),static_cast(posZ)); + const Vector3DFloat gradFloor = computeSobelGradient(volIter); + if((posX - floorX) > 0.25) //The result should be 0.0 or 0.5 + { + volIter.setPosition(static_cast(posX+1.0),static_cast(posY),static_cast(posZ)); + } + if((posY - floorY) > 0.25) //The result should be 0.0 or 0.5 + { + volIter.setPosition(static_cast(posX),static_cast(posY+1.0),static_cast(posZ)); + } + if((posZ - floorZ) > 0.25) //The result should be 0.0 or 0.5 + { + volIter.setPosition(static_cast(posX),static_cast(posY),static_cast(posZ+1.0)); + } + const Vector3DFloat gradCeil = computeSobelGradient(volIter); + result = ((gradFloor + gradCeil) * -1.0); + if(result.lengthSquared() < 0.0001) + { + //Operation failed - fall back on simple gradient estimation + normalGenerationMethod = SIMPLE; + } + } + if(normalGenerationMethod == CENTRAL_DIFFERENCE) + { + volIter.setPosition(static_cast(posX),static_cast(posY),static_cast(posZ)); + const Vector3DFloat gradFloor = computeSmoothCentralDifferenceGradient(volIter); + if((posX - floorX) > 0.25) //The result should be 0.0 or 0.5 + { + volIter.setPosition(static_cast(posX+1.0),static_cast(posY),static_cast(posZ)); + } + if((posY - floorY) > 0.25) //The result should be 0.0 or 0.5 + { + volIter.setPosition(static_cast(posX),static_cast(posY+1.0),static_cast(posZ)); + } + if((posZ - floorZ) > 0.25) //The result should be 0.0 or 0.5 + { + volIter.setPosition(static_cast(posX),static_cast(posY),static_cast(posZ+1.0)); + } + const Vector3DFloat gradCeil = computeSmoothCentralDifferenceGradient(volIter); + result = ((gradFloor + gradCeil) * -1.0); + if(result.lengthSquared() < 0.0001) + { + //Operation failed - fall back on simple gradient estimation + normalGenerationMethod = SIMPLE; + } + } + if(normalGenerationMethod == SIMPLE) + { + volIter.setPosition(static_cast(posX),static_cast(posY),static_cast(posZ)); + const uint8_t uFloor = volIter.getVoxel() > 0 ? 1 : 0; + if((posX - floorX) > 0.25) //The result should be 0.0 or 0.5 + { + uint8_t uCeil = volIter.peekVoxel1px0py0pz() > 0 ? 1 : 0; + result = Vector3DFloat(static_cast(uFloor - uCeil),0.0,0.0); + } + else if((posY - floorY) > 0.25) //The result should be 0.0 or 0.5 + { + uint8_t uCeil = volIter.peekVoxel0px1py0pz() > 0 ? 1 : 0; + result = Vector3DFloat(0.0,static_cast(uFloor - uCeil),0.0); + } + else if((posZ - floorZ) > 0.25) //The result should be 0.0 or 0.5 + { + uint8_t uCeil = volIter.peekVoxel0px0py1pz() > 0 ? 1 : 0; + result = Vector3DFloat(0.0, 0.0,static_cast(uFloor - uCeil)); + } + } + return result; + } +} \ No newline at end of file