From fff36662a5a9fba9e46f46afc1d7ec4be094ff54 Mon Sep 17 00:00:00 2001 From: David Williams Date: Sun, 2 Jan 2011 15:28:02 +0000 Subject: [PATCH] Work on MeshDecimator. --- library/PolyVoxCore/include/MeshDecimator.h | 19 +- library/PolyVoxCore/include/MeshDecimator.inl | 323 +++++------------- 2 files changed, 94 insertions(+), 248 deletions(-) diff --git a/library/PolyVoxCore/include/MeshDecimator.h b/library/PolyVoxCore/include/MeshDecimator.h index 7c422b61..f384cc61 100644 --- a/library/PolyVoxCore/include/MeshDecimator.h +++ b/library/PolyVoxCore/include/MeshDecimator.h @@ -39,13 +39,6 @@ namespace PolyVox NF_NO_OF_FLAGS }; - enum Stages - { - STAGE_FACE, - STAGE_EDGE, - NO_OF_STAGES - }; - struct VertexMetadata { bool hasDuplicate; @@ -54,6 +47,8 @@ namespace PolyVox int noOfDifferentNormals; Vector3DFloat normal; std::bitset m_bNormalFlags; + bool isOnRegionEdge; + bool isOnMaterialEdge; }; template @@ -68,8 +63,6 @@ namespace PolyVox void fillVertexMetadata(std::vector& vecVertexMetadata); - int countZeros(void); - SurfaceMesh* m_pInputMesh; //SurfaceMesh* pMeshOutput; @@ -79,6 +72,10 @@ namespace PolyVox bool isSubsetCubic(std::bitset a, std::bitset b); bool canCollapseEdge(uint32_t uSrc, uint32_t uDest); + bool canCollapseNormalEdge(uint32_t uSrc, uint32_t uDest); + bool canCollapseRegionEdge(uint32_t uSrc, uint32_t uDest); + bool canCollapseMaterialEdge(uint32_t uSrc, uint32_t uDest); + bool collapseCausesFaceFlip(uint32_t uSrc, uint32_t uDest); //Data structures used during decimation std::vector m_vecNoOfNeighboursUsingMaterial; @@ -91,16 +88,12 @@ namespace PolyVox vector vecOfTriCts; vector vecOfTriNormals; - int m_NoOfZeros; - //vector noOfDifferentNormals; vector m_vecInitialVertexMetadata; vector m_vecCurrentVertexMetadata; float fMinDotProductForCollapse; - - uint8_t m_uStage; }; } diff --git a/library/PolyVoxCore/include/MeshDecimator.inl b/library/PolyVoxCore/include/MeshDecimator.inl index d87e6a50..e5d70566 100644 --- a/library/PolyVoxCore/include/MeshDecimator.inl +++ b/library/PolyVoxCore/include/MeshDecimator.inl @@ -40,7 +40,6 @@ namespace PolyVox fillVertexMetadata(m_vecInitialVertexMetadata); - m_uStage = STAGE_FACE; uint32_t noOfEdgesCollapsed; do { @@ -69,6 +68,10 @@ namespace PolyVox vecVertexMetadata[ct].materialKey = 0; vecVertexMetadata[ct].trianglesUsingVertex.clear(); vecVertexMetadata[ct].noOfDifferentNormals = 0; + vecVertexMetadata[ct].normal.setElements(0,0,0); + vecVertexMetadata[ct].m_bNormalFlags.reset(); + vecVertexMetadata[ct].isOnRegionEdge = false; + vecVertexMetadata[ct].isOnMaterialEdge = false; } //Determine triangles using each vertex @@ -92,6 +95,9 @@ namespace PolyVox { vecVertexMetadata[innerCt].hasDuplicate = true; vecVertexMetadata[outerCt].hasDuplicate = true; + + vecVertexMetadata[innerCt].isOnMaterialEdge = true; + vecVertexMetadata[outerCt].isOnMaterialEdge = true; } } } @@ -171,12 +177,13 @@ namespace PolyVox vecVertexMetadata[ct].normal = sumOfNormals; vecVertexMetadata[ct].normal.normalise(); + } - - /*if(vecVertexMetadata[ct].noOfDifferentNormals == 3) - std::cout << "CORNER at " << ct < 0); + Vector3DFloat offset = static_cast(m_pInputMesh->m_Region.getLowerCorner()); + for(int ct = 0; ct < m_pInputMesh->m_vecVertices.size(); ct++) + { + bool bInside = m_pInputMesh->m_Region.containsPoint(m_pInputMesh->m_vecVertices[ct].getPosition() + offset); + vecVertexMetadata[ct].isOnRegionEdge = !bInside; } //std::cout << "----------" < 0) { //Fix up the indices @@ -266,8 +271,6 @@ namespace PolyVox } } - m_NoOfZeros = countZeros(); - return noOfEdgesCollapsed; } @@ -351,21 +354,21 @@ namespace PolyVox } //template - bool MeshDecimator::canCollapseEdge(uint32_t v0, uint32_t v1) + bool MeshDecimator::canCollapseEdge(uint32_t uSrc, uint32_t uDst) { //A vertex will be locked if it has already been involved in a collapse this pass. - if(vertexLocked[v0] || vertexLocked[v1]) + if(vertexLocked[uSrc] || vertexLocked[uDst]) { return false; } - if(m_pInputMesh->m_vecVertices[v0].getMaterial() != m_pInputMesh->m_vecVertices[v1].getMaterial()) + if(m_pInputMesh->m_vecVertices[uSrc].getMaterial() != m_pInputMesh->m_vecVertices[uDst].getMaterial()) { return false; } //For now, don't collapse vertices on material edges... - if(m_pInputMesh->m_vecVertices[v0].isOnMaterialEdge() || m_pInputMesh->m_vecVertices[v1].isOnMaterialEdge()) + if(m_pInputMesh->m_vecVertices[uSrc].isOnMaterialEdge() || m_pInputMesh->m_vecVertices[uDst].isOnMaterialEdge()) { if(true) { @@ -377,16 +380,16 @@ namespace PolyVox // have four neighbours with the same material. If it's on a corner it will have a // different number. We only collapse straight edges to avoid changingthe shape of the // material boundary. - if(m_vecNoOfNeighboursUsingMaterial[v0] == m_vecNoOfNeighboursUsingMaterial[v1]) + if(m_vecNoOfNeighboursUsingMaterial[uSrc] == m_vecNoOfNeighboursUsingMaterial[uDst]) { - if(m_vecNoOfNeighboursUsingMaterial[v0] == 4) + if(m_vecNoOfNeighboursUsingMaterial[uSrc] == 4) { allMatch = true; } } bool movementValid = false; - Vector3DFloat movement = m_pInputMesh->m_vecVertices[v1].getPosition() - m_pInputMesh->m_vecVertices[v0].getPosition(); + Vector3DFloat movement = m_pInputMesh->m_vecVertices[uDst].getPosition() - m_pInputMesh->m_vecVertices[uSrc].getPosition(); movement.normalise(); if(movement.dot(Vector3DFloat(0,0,1)) > 0.999) { @@ -436,7 +439,7 @@ namespace PolyVox // Vertices on the geometrical edge of surface meshes need special handling. // We check for this by whether any of the edge flags are set. - if(m_pInputMesh->m_vecVertices[v0].m_bFlags.any() || m_pInputMesh->m_vecVertices[v1].m_bFlags.any()) + if(m_pInputMesh->m_vecVertices[uSrc].m_bFlags.any() || m_pInputMesh->m_vecVertices[uDst].m_bFlags.any()) { // Assume we can't collapse until we prove otherwise... bool bCollapseGeometryEdgePair = false; @@ -444,13 +447,13 @@ namespace PolyVox // We can collapse normal vertices onto edge vertices, and edge vertices // onto corner vertices, but not vice-versa. Hence we check whether all // the edge flags in the source vertex are also set in the destination vertex. - if(isSubset(m_pInputMesh->m_vecVertices[v0].m_bFlags, m_pInputMesh->m_vecVertices[v1].m_bFlags)) + if(isSubset(m_pInputMesh->m_vecVertices[uSrc].m_bFlags, m_pInputMesh->m_vecVertices[uDst].m_bFlags)) { // In general adjacent regions surface meshes may collapse differently // and this can cause cracks. We solve this by only allowing the collapse // is the normals are exactly the same. We do not use the user provided // tolerence here (but do allow for floating point error). - if(m_pInputMesh->m_vecVertices[v0].getNormal().dot(m_pInputMesh->m_vecVertices[v1].getNormal()) > 0.999) + if(m_pInputMesh->m_vecVertices[uSrc].getNormal().dot(m_pInputMesh->m_vecVertices[uDst].getNormal()) > 0.999) { // Ok, this pair can collapse. bCollapseGeometryEdgePair = true; @@ -465,93 +468,14 @@ namespace PolyVox } //Check the normals are within the threashold. - if(m_pInputMesh->m_vecVertices[v0].getNormal().dot(m_pInputMesh->m_vecVertices[v1].getNormal()) < fMinDotProductForCollapse) + if(m_pInputMesh->m_vecVertices[uSrc].getNormal().dot(m_pInputMesh->m_vecVertices[uDst].getNormal()) < fMinDotProductForCollapse) { return false; } //////////////////////////////////////////////////////////////////////////////// //The last test is whether we will flip any of the faces - - bool faceFlipped = false; - //list triangles = trianglesUsingVertexCurrently[v0]; - list triangles = m_vecCurrentVertexMetadata[v0].trianglesUsingVertex; - /*set triangles; - std::set_union(trianglesUsingVertex[v0].begin(), trianglesUsingVertex[v0].end(), - trianglesUsingVertex[v1].begin(), trianglesUsingVertex[v1].end(), - std::inserter(triangles, triangles.begin()));*/ - - for(list::iterator triIter = triangles.begin(); triIter != triangles.end(); triIter++) - { - uint32_t tri = *triIter; - - uint32_t v0Old = m_pInputMesh->m_vecTriangleIndices[tri * 3]; - uint32_t v1Old = m_pInputMesh->m_vecTriangleIndices[tri * 3 + 1]; - uint32_t v2Old = m_pInputMesh->m_vecTriangleIndices[tri * 3 + 2]; - - //Check if degenerate - if((v0Old == v1Old) || (v1Old == v2Old) || (v2Old == v0Old)) - { - continue; - } - - uint32_t v0New = v0Old; - uint32_t v1New = v1Old; - uint32_t v2New = v2Old; - - if(v0New == v0) - v0New = v1; - if(v1New == v0) - v1New = v1; - if(v2New == v0) - v2New = v1; - - //Check if degenerate - if((v0New == v1New) || (v1New == v2New) || (v2New == v0New)) - { - continue; - } - - Vector3DFloat v0OldPos = m_pInputMesh->m_vecVertices[vertexMapper[v0Old]].getPosition(); - Vector3DFloat v1OldPos = m_pInputMesh->m_vecVertices[vertexMapper[v1Old]].getPosition(); - Vector3DFloat v2OldPos = m_pInputMesh->m_vecVertices[vertexMapper[v2Old]].getPosition(); - - Vector3DFloat v0NewPos = m_pInputMesh->m_vecVertices[vertexMapper[v0New]].getPosition(); - Vector3DFloat v1NewPos = m_pInputMesh->m_vecVertices[vertexMapper[v1New]].getPosition(); - Vector3DFloat v2NewPos = m_pInputMesh->m_vecVertices[vertexMapper[v2New]].getPosition(); - - /*Vector3DFloat v0OldPos = m_vecVertices[v0Old].getPosition(); - Vector3DFloat v1OldPos = m_vecVertices[v1Old].getPosition(); - Vector3DFloat v2OldPos = m_vecVertices[v2Old].getPosition(); - - Vector3DFloat v0NewPos = m_vecVertices[v0New].getPosition(); - Vector3DFloat v1NewPos = m_vecVertices[v1New].getPosition(); - Vector3DFloat v2NewPos = m_vecVertices[v2New].getPosition();*/ - - Vector3DFloat OldNormal = (v1OldPos - v0OldPos).cross(v2OldPos - v1OldPos); - Vector3DFloat NewNormal = (v1NewPos - v0NewPos).cross(v2NewPos - v1NewPos); - - OldNormal.normalise(); - NewNormal.normalise(); - - // Note for after holiday - We are still getting faces flipping despite the following test. I tried changing - // the 0.0 to 0.9 (which should still let coplanar faces merge) but oddly nothing then merged. Investigate this. - float dotProduct = OldNormal.dot(NewNormal); - //cout << dotProduct << endl; - if(dotProduct < 0.9f) - { - //cout << " Face flipped!!" << endl; - - faceFlipped = true; - - /*vertexLocked[v0] = true; - vertexLocked[v1] = true;*/ - - break; - } - } - - if(faceFlipped == true) + if(collapseCausesFaceFlip(uSrc,uDst)) { return false; } @@ -559,75 +483,83 @@ namespace PolyVox } //template - bool MeshDecimator::canCollapseEdge(uint32_t v0, uint32_t v1) + bool MeshDecimator::canCollapseEdge(uint32_t uSrc, uint32_t uDst) { //A vertex will be locked if it has already been involved in a collapse this pass. - if(vertexLocked[v0] || vertexLocked[v1]) + if(vertexLocked[uSrc] || vertexLocked[uDst]) { return false; - } + } - if(m_pInputMesh->m_vecVertices[v0].getMaterial() != m_pInputMesh->m_vecVertices[v1].getMaterial()) + if(m_vecInitialVertexMetadata[uSrc].isOnMaterialEdge) { - return false; - } - - if(m_vecInitialVertexMetadata[v0].m_bNormalFlags.count() == 3) //Corner - { - return false; - } - - if(m_vecInitialVertexMetadata[v0].m_bNormalFlags.count() == 2) //Edge - { - if(isSubsetCubic(m_vecInitialVertexMetadata[v0].m_bNormalFlags, m_vecInitialVertexMetadata[v1].m_bNormalFlags) == false) + if(m_vecInitialVertexMetadata[uSrc].isOnRegionEdge) { + assert(false); //Shouldn't be on both edge types. return false; } - } - - if(m_vecInitialVertexMetadata[v0].m_bNormalFlags.count() == 1) //Face - { - if(isSubsetCubic(m_vecInitialVertexMetadata[v0].m_bNormalFlags, m_vecInitialVertexMetadata[v1].m_bNormalFlags) == false) + else { - return false; + return canCollapseMaterialEdge(uSrc, uDst); } } + else + { + if(m_vecInitialVertexMetadata[uSrc].isOnRegionEdge) + { + return canCollapseRegionEdge(uSrc, uDst); + } + else + { + return canCollapseNormalEdge(uSrc, uDst); + } + } + } - /*if(m_vecInitialVertexMetadata[v0].normal.dot(m_vecInitialVertexMetadata[v1].normal) < 0.999f) + template + bool MeshDecimator::canCollapseNormalEdge(uint32_t uSrc, uint32_t uDst) + { + if(m_vecInitialVertexMetadata[uSrc].m_bNormalFlags.count() == 3) //Corner + { + return false; + } + + if(isSubsetCubic(m_vecInitialVertexMetadata[uSrc].m_bNormalFlags, m_vecInitialVertexMetadata[uDst].m_bNormalFlags) == false) + { + return false; + } + + if(collapseCausesFaceFlip(uSrc, uDst)) + { + return false; + } + + /*if(m_vecInitialVertexMetadata[uSrc].normal.dot(m_vecInitialVertexMetadata[v1].normal) < 0.999f) { return false; }*/ - if(m_vecInitialVertexMetadata[v0].hasDuplicate) - { - bool canMerge = false; + return true; + } - /*if(m_vecInitialVertexMetadata[v1].hasDuplicate) - { - if(isSubsetCubic(m_vecInitialVertexMetadata[v0].m_bNormalFlags, m_vecInitialVertexMetadata[v1].m_bNormalFlags)) - { - canMerge = true; - } - }*/ + template + bool MeshDecimator::canCollapseRegionEdge(uint32_t uSrc, uint32_t uDst) + { + return false; + } - return canMerge; - } - - Vector3DFloat offset = static_cast(m_pInputMesh->m_Region.getLowerCorner()); - bool v0Inside = m_pInputMesh->m_Region.containsPoint(m_pInputMesh->m_vecVertices[v0].getPosition() + offset); - bool v1Inside = m_pInputMesh->m_Region.containsPoint(m_pInputMesh->m_vecVertices[v1].getPosition() + offset); - if(v0Inside == false) - { - return false; - } - - - //////////////////////////////////////////////////////////////////////////////// - //The last test is whether we will flip any of the faces + template + bool MeshDecimator::canCollapseMaterialEdge(uint32_t uSrc, uint32_t uDst) + { + return false; + } + template + bool MeshDecimator::collapseCausesFaceFlip(uint32_t uSrc, uint32_t uDst) + { bool faceFlipped = false; //list triangles = trianglesUsingVertexCurrently[v0]; - list triangles = m_vecCurrentVertexMetadata[v0].trianglesUsingVertex; + list triangles = m_vecCurrentVertexMetadata[uSrc].trianglesUsingVertex; /*set triangles; std::set_union(trianglesUsingVertex[v0].begin(), trianglesUsingVertex[v0].end(), trianglesUsingVertex[v1].begin(), trianglesUsingVertex[v1].end(), @@ -651,12 +583,12 @@ namespace PolyVox uint32_t v1New = v1Old; uint32_t v2New = v2Old; - if(v0New == v0) - v0New = v1; - if(v1New == v0) - v1New = v1; - if(v2New == v0) - v2New = v1; + if(v0New == uSrc) + v0New = uDst; + if(v1New == uSrc) + v1New = uDst; + if(v2New == uSrc) + v2New = uDst; //Check if degenerate if((v0New == v1New) || (v1New == v2New) || (v2New == v0New)) @@ -703,85 +635,6 @@ namespace PolyVox } } - if(faceFlipped == true) - { - return false; - } - - - /*if(m_vecInitialVertexMetadata[v0].trianglesUsingVertex.size() != m_vecInitialVertexMetadata[v1].trianglesUsingVertex.size()) - { - return false; - }*/ - - /*if(m_vecInitialVertexMetadata[v0].noOfDifferentNormals == 3) - { - return false; - }*/ - - /*if(m_vecInitialVertexMetadata[v1].noOfDifferentNormals == 3) - { - return false; - }*/ - - /*if(m_vecInitialVertexMetadata[v0].noOfDifferentNormals > m_vecInitialVertexMetadata[v1].noOfDifferentNormals) - { - return false; - }*/ - - /*if(m_vecInitialVertexMetadata[v0].materialKey != m_vecInitialVertexMetadata[v1].materialKey) - { - return false; - }*/ - - /*if((hasDuplicate[v0]) || (hasDuplicate[v1])) - { - return false; - }*/ - - /*if(m_vecInitialVertexMetadata[v0].hasDuplicate) - { - //if(!hasDuplicate[v1]) - { - return false; - } - }*/ - return true; + return faceFlipped; } - - template - int MeshDecimator::countZeros(void) - { - int total = 0; - for(int ct = 0; ct < m_pInputMesh->m_vecTriangleIndices.size(); ct++) - { - if(m_pInputMesh->m_vecTriangleIndices[ct] == 0) - { - total++; - } - } - return total; - } -} - -#ifdef BLAH - Vector3DFloat offset = static_cast(m_pInputMesh->m_Region.getLowerCorner()); - bool v0Inside = m_pInputMesh->m_Region.containsPoint(m_pInputMesh->m_vecVertices[v0].getPosition() + offset); - bool v1Inside = m_pInputMesh->m_Region.containsPoint(m_pInputMesh->m_vecVertices[v1].getPosition() + offset); - if(v0Inside == false) - { - /*if(v1Inside == false) - { - //if(noOfDifferentNormals[v0] > 1) - if(trianglesUsingVertex[v0].size() != trianglesUsingVertex[v1].size()) - //if(materialKey[v0] != materialKey[v1]) - { - return false; - } - } - else*/ - { - return false; - } - } -#endif \ No newline at end of file +} \ No newline at end of file