• Main Page
  • Related Pages
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

PolyVoxCore/source/MeshDecimator.cpp

Go to the documentation of this file.
00001 /*******************************************************************************
00002 Copyright (c) 2005-2009 David Williams
00003 
00004 This software is provided 'as-is', without any express or implied
00005 warranty. In no event will the authors be held liable for any damages
00006 arising from the use of this software.
00007 
00008 Permission is granted to anyone to use this software for any purpose,
00009 including commercial applications, and to alter it and redistribute it
00010 freely, subject to the following restrictions:
00011 
00012     1. The origin of this software must not be misrepresented; you must not
00013     claim that you wrote the original software. If you use this software
00014     in a product, an acknowledgment in the product documentation would be
00015     appreciated but is not required.
00016 
00017     2. Altered source versions must be plainly marked as such, and must not be
00018     misrepresented as being the original software.
00019 
00020     3. This notice may not be removed or altered from any source
00021     distribution.   
00022 *******************************************************************************/
00023 
00024 #include "PolyVoxCore/MeshDecimator.h"
00025 #include "PolyVoxCore/SurfaceMesh.h"
00026 
00027 using namespace std;
00028 
00029 namespace PolyVox
00030 {
00031     template<>
00032     POLYVOX_API void MeshDecimator<PositionMaterial>::fillInitialVertexMetadata(std::vector<InitialVertexMetadata>& vecVertexMetadata)
00033     {
00034         vecVertexMetadata.clear();
00035         vecVertexMetadata.resize(m_pOutputMesh->m_vecVertices.size());
00036         //Initialise the metadata
00037         for(uint32_t ct = 0; ct < vecVertexMetadata.size(); ct++)
00038         {
00039             vecVertexMetadata[ct].normal.setElements(0,0,0);
00040             vecVertexMetadata[ct].isOnMaterialEdge = false;
00041             vecVertexMetadata[ct].isOnRegionFace.reset();
00042         }
00043 
00044         //Identify duplicate vertices, as they lie on the material edge. To do this we convert into integers and sort 
00045         //(first on z, then y, then x). They should be mostly in order as this is the order they come out of the
00046         //CubicSurfaceExtractor in. Duplicates are now neighbours in the resulting list so just scan through for pairs.
00047         std::vector<IntVertex> intVertices;
00048         intVertices.reserve(m_pOutputMesh->m_vecVertices.size());
00049         for(uint32_t ct = 0; ct < m_pOutputMesh->m_vecVertices.size(); ct++)
00050         {
00051             const Vector3DFloat& floatPos = m_pOutputMesh->m_vecVertices[ct].position;
00052             IntVertex intVertex(static_cast<uint32_t>(floatPos.getX()), static_cast<uint32_t>(floatPos.getY()), static_cast<uint32_t>(floatPos.getZ()), ct);
00053             intVertices.push_back(intVertex);
00054         }
00055 
00056         //Do the sorting so that duplicate become neighbours
00057         sort(intVertices.begin(), intVertices.end());
00058 
00059         //Find neighbours which are duplicates.
00060         for(uint32_t ct = 0; ct < intVertices.size() - 1; ct++)
00061         {
00062             const IntVertex& v0 = intVertices[ct+0];
00063             const IntVertex& v1 = intVertices[ct+1];
00064 
00065             if((v0.x == v1.x) && (v0.y == v1.y) && (v0.z == v1.z))
00066             {
00067                 vecVertexMetadata[v0.index].isOnMaterialEdge = true;
00068                 vecVertexMetadata[v1.index].isOnMaterialEdge = true;
00069             }
00070         }
00071 
00072         //Compute an approcimation to the normal, used when deciding if an edge can collapse.
00073         for(uint32_t ct = 0; ct < m_pOutputMesh->m_vecVertices.size(); ct++)
00074         {
00075             Vector3DFloat sumOfNormals(0.0f,0.0f,0.0f);
00076             for(vector<uint32_t>::iterator iter = trianglesUsingVertex[ct].begin(); iter != trianglesUsingVertex[ct].end(); iter++)
00077             {
00078                 sumOfNormals += m_vecTriangles[*iter].normal;
00079             }
00080 
00081             vecVertexMetadata[ct].normal = sumOfNormals;
00082             vecVertexMetadata[ct].normal.normalise();
00083         }
00084 
00085         //Identify those vertices on the edge of a region. Care will need to be taken when moving them.
00086         for(uint32_t ct = 0; ct < vecVertexMetadata.size(); ct++)
00087         {
00088             Region regTransformed = m_pOutputMesh->m_Region;
00089             regTransformed.shift(regTransformed.getLowerCorner() * static_cast<int32_t>(-1));
00090 
00091             //Plus and minus X
00092             vecVertexMetadata[ct].isOnRegionFace.set(RFF_ON_REGION_FACE_NEG_X, m_pOutputMesh->m_vecVertices[ct].getPosition().getX() < regTransformed.getLowerCorner().getX() + 0.001f);
00093             vecVertexMetadata[ct].isOnRegionFace.set(RFF_ON_REGION_FACE_POS_X, m_pOutputMesh->m_vecVertices[ct].getPosition().getX() > regTransformed.getUpperCorner().getX() - 0.001f);
00094             //Plus and minus Y
00095             vecVertexMetadata[ct].isOnRegionFace.set(RFF_ON_REGION_FACE_NEG_Y, m_pOutputMesh->m_vecVertices[ct].getPosition().getY() < regTransformed.getLowerCorner().getY() + 0.001f);
00096             vecVertexMetadata[ct].isOnRegionFace.set(RFF_ON_REGION_FACE_POS_Y, m_pOutputMesh->m_vecVertices[ct].getPosition().getY() > regTransformed.getUpperCorner().getY() - 0.001f);
00097             //Plus and minus Z
00098             vecVertexMetadata[ct].isOnRegionFace.set(RFF_ON_REGION_FACE_NEG_Z, m_pOutputMesh->m_vecVertices[ct].getPosition().getZ() < regTransformed.getLowerCorner().getZ() + 0.001f);
00099             vecVertexMetadata[ct].isOnRegionFace.set(RFF_ON_REGION_FACE_POS_Z, m_pOutputMesh->m_vecVertices[ct].getPosition().getZ() > regTransformed.getUpperCorner().getZ() - 0.001f);
00100         }
00101     }
00102 
00103     template<>
00104     POLYVOX_API void MeshDecimator<PositionMaterialNormal>::fillInitialVertexMetadata(std::vector<InitialVertexMetadata>& vecVertexMetadata)
00105     {
00106         vecVertexMetadata.clear();
00107         vecVertexMetadata.resize(m_pOutputMesh->m_vecVertices.size());
00108 
00109         //Initialise the metadata
00110         for(uint32_t ct = 0; ct < vecVertexMetadata.size(); ct++)
00111         {           
00112             vecVertexMetadata[ct].isOnRegionFace.reset();
00113             vecVertexMetadata[ct].isOnMaterialEdge = false;
00114             vecVertexMetadata[ct].normal = m_pOutputMesh->m_vecVertices[ct].normal;
00115         }
00116 
00117         //Identify those vertices on the edge of a region. Care will need to be taken when moving them.
00118         for(uint32_t ct = 0; ct < vecVertexMetadata.size(); ct++)
00119         {
00120             Region regTransformed = m_pOutputMesh->m_Region;
00121             regTransformed.shift(regTransformed.getLowerCorner() * static_cast<int32_t>(-1));
00122 
00123             //Plus and minus X
00124             vecVertexMetadata[ct].isOnRegionFace.set(RFF_ON_REGION_FACE_NEG_X, m_pOutputMesh->m_vecVertices[ct].getPosition().getX() < regTransformed.getLowerCorner().getX() + 0.001f);
00125             vecVertexMetadata[ct].isOnRegionFace.set(RFF_ON_REGION_FACE_POS_X, m_pOutputMesh->m_vecVertices[ct].getPosition().getX() > regTransformed.getUpperCorner().getX() - 0.001f);
00126             //Plus and minus Y
00127             vecVertexMetadata[ct].isOnRegionFace.set(RFF_ON_REGION_FACE_NEG_Y, m_pOutputMesh->m_vecVertices[ct].getPosition().getY() < regTransformed.getLowerCorner().getY() + 0.001f);
00128             vecVertexMetadata[ct].isOnRegionFace.set(RFF_ON_REGION_FACE_POS_Y, m_pOutputMesh->m_vecVertices[ct].getPosition().getY() > regTransformed.getUpperCorner().getY() - 0.001f);
00129             //Plus and minus Z
00130             vecVertexMetadata[ct].isOnRegionFace.set(RFF_ON_REGION_FACE_NEG_Z, m_pOutputMesh->m_vecVertices[ct].getPosition().getZ() < regTransformed.getLowerCorner().getZ() + 0.001f);
00131             vecVertexMetadata[ct].isOnRegionFace.set(RFF_ON_REGION_FACE_POS_Z, m_pOutputMesh->m_vecVertices[ct].getPosition().getZ() > regTransformed.getUpperCorner().getZ() - 0.001f);
00132         }
00133 
00134         //If all three vertices have the same material then we are not on a material edge. If any vertex has a different
00135         //material then all three vertices are on a material edge. E.g. If one vertex has material 'a' and the other two 
00136         //have material 'b', then the two 'b's are still on an edge (with 'a') even though they are the same as eachother.
00137         for(uint32_t ct = 0; ct < m_vecTriangles.size(); ct++)
00138         {
00139             uint32_t v0 = m_vecTriangles[ct].v0;
00140             uint32_t v1 = m_vecTriangles[ct].v1;
00141             uint32_t v2 = m_vecTriangles[ct].v2;
00142 
00143             bool allMatch = 
00144                 (m_pOutputMesh->m_vecVertices[v0].material == m_pOutputMesh->m_vecVertices[v1].material) && 
00145                 (m_pOutputMesh->m_vecVertices[v1].material == m_pOutputMesh->m_vecVertices[v2].material);
00146 
00147             if(!allMatch)
00148             {
00149                 vecVertexMetadata[v0].isOnMaterialEdge = true;
00150                 vecVertexMetadata[v1].isOnMaterialEdge = true;
00151                 vecVertexMetadata[v2].isOnMaterialEdge = true;
00152             }
00153         }
00154     }
00155 
00156     template<> 
00157     POLYVOX_API bool MeshDecimator<PositionMaterialNormal>::canCollapseNormalEdge(uint32_t uSrc, uint32_t uDst)
00158     {
00159         if(m_vecInitialVertexMetadata[uSrc].normal.dot(m_vecInitialVertexMetadata[uDst].normal) < m_fMinDotProductForCollapse)
00160         {
00161             return false;
00162         }
00163 
00164         //With the marching cubes surface we honour the user specified threshold
00165         return !collapseChangesFaceNormals(uSrc, uDst, m_fMinDotProductForCollapse);
00166     }
00167 
00168     template<> 
00169     POLYVOX_API bool MeshDecimator<PositionMaterial>::canCollapseNormalEdge(uint32_t uSrc, uint32_t uDst)
00170     {
00171         //We don't actually use the normal here, because we want to allow face
00172         //vertices to collapse onto edge vertices. Simply checking whether anything
00173         //has flipped has proved to be the most robust approach, though rather slow.
00174         //It's not sufficient to just check the normals, there can be holes in the middle
00175         //of the mesh for example.
00176 
00177         //User specified threshold is not used for cubic surface, any
00178         //movement is too much (but allow for floating point error).
00179         return !collapseChangesFaceNormals(uSrc, uDst, 0.999f);
00180     }
00181 }

Generated on Sat Nov 19 2011 00:27:31 for PolyVox by  doxygen 1.7.1