diff --git a/library/PolyVoxCore/include/MeshDecimator.h b/library/PolyVoxCore/include/MeshDecimator.h index 158ea6b1..82f3d849 100644 --- a/library/PolyVoxCore/include/MeshDecimator.h +++ b/library/PolyVoxCore/include/MeshDecimator.h @@ -92,6 +92,48 @@ namespace PolyVox uint32_t v2; Vector3DFloat normal; }; + + struct IntVertex + { + int32_t x; + int32_t y; + int32_t z; + uint32_t index; + + IntVertex(int32_t xVal, int32_t yVal, int32_t zVal, uint32_t indexVal) + :x(xVal) + ,y(yVal) + ,z(zVal) + ,index(indexVal) + { + } + + bool operator==(const IntVertex& rhs) const + { + return (x == rhs.x) && (y == rhs.y) && (z == rhs.z); + } + + bool operator<(const IntVertex& rhs) const + { + if (z < rhs.z) + return true; + if (rhs.z < z) + return false; + + if (y < rhs.y) + return true; + if (rhs.y < y) + return false; + + if (x < rhs.x) + return true; + if (rhs.x < x) + return false; + + return false; + } + }; + public: ///Constructor MeshDecimator(const SurfaceMesh* pInputMesh, SurfaceMesh* pOutputMesh, float fEdgeCollapseThreshold = 0.95f); @@ -125,7 +167,7 @@ namespace PolyVox std::vector vertexMapper; std::vector m_vecTriangles; - std::vector< list > trianglesUsingVertex; //Should probably use vector of vectors, and resise in advance. + std::vector< std::vector > trianglesUsingVertex; //Should probably use vector of vectors, and resise in advance. std::vector m_vecInitialVertexMetadata; diff --git a/library/PolyVoxCore/include/MeshDecimator.inl b/library/PolyVoxCore/include/MeshDecimator.inl index bedfbbdf..501211f5 100644 --- a/library/PolyVoxCore/include/MeshDecimator.inl +++ b/library/PolyVoxCore/include/MeshDecimator.inl @@ -104,6 +104,10 @@ namespace PolyVox //For each vertex, determine which triangles are using it. trianglesUsingVertex.clear(); trianglesUsingVertex.resize(m_pOutputMesh->m_vecVertices.size()); + for(int ct = 0; ct < trianglesUsingVertex.size(); ct++) + { + trianglesUsingVertex[ct].reserve(6); + } for(int ct = 0; ct < m_vecTriangles.size(); ct++) { trianglesUsingVertex[m_vecTriangles[ct].v0].push_back(ct); @@ -125,19 +129,31 @@ namespace PolyVox vecVertexMetadata[ct].isOnRegionFace.reset(); } - //Identify duplicate vertices, as they lie on the material edge. Note that this is a particularly slow way of - //findong the duplicates. Better to hash into integer (with upper bits being z and lower bits being x) and sort - //the resulting integers. The should be mostly in order as this is the order they come out of the + //Identify duplicate vertices, as they lie on the material edge. To do this we convert into integers and sort + //(first on z, then y, then x). They should be mostly in order as this is the order they come out of the //CubicSurfaceExtractor in. Duplicates are now neighbours in the resulting list so just scan through for pairs. - for(int outerCt = 0; outerCt < m_pOutputMesh->m_vecVertices.size()-1; outerCt++) + std::vector intVertices; + intVertices.reserve(m_pOutputMesh->m_vecVertices.size()); + for(int ct = 0; ct < m_pOutputMesh->m_vecVertices.size(); ct++) { - for(int innerCt = outerCt+1; innerCt < m_pOutputMesh->m_vecVertices.size(); innerCt++) + const Vector3DFloat& floatPos = m_pOutputMesh->m_vecVertices[ct].position; + IntVertex intVertex(static_cast(floatPos.getX()), static_cast(floatPos.getY()), static_cast(floatPos.getZ()), ct); + intVertices.push_back(intVertex); + } + + //Do the sorting so that duplicate become neighbours + sort(intVertices.begin(), intVertices.end()); + + //Find neighbours which are duplicates. + for(int ct = 0; ct < intVertices.size() - 1; ct++) + { + const IntVertex& v0 = intVertices[ct+0]; + const IntVertex& v1 = intVertices[ct+1]; + + if((v0.x == v1.x) && (v0.y == v1.y) && (v0.z == v1.z)) { - if((m_pOutputMesh->m_vecVertices[innerCt].position - m_pOutputMesh->m_vecVertices[outerCt].position).lengthSquared() < 0.001f) - { - vecVertexMetadata[innerCt].isOnMaterialEdge = true; - vecVertexMetadata[outerCt].isOnMaterialEdge = true; - } + vecVertexMetadata[v0.index].isOnMaterialEdge = true; + vecVertexMetadata[v1.index].isOnMaterialEdge = true; } } @@ -145,7 +161,7 @@ namespace PolyVox for(int ct = 0; ct < m_pOutputMesh->m_vecVertices.size(); ct++) { Vector3DFloat sumOfNormals(0.0f,0.0f,0.0f); - for(list::const_iterator iter = trianglesUsingVertex[ct].cbegin(); iter != trianglesUsingVertex[ct].cend(); iter++) + for(vector::const_iterator iter = trianglesUsingVertex[ct].cbegin(); iter != trianglesUsingVertex[ct].cend(); iter++) { sumOfNormals += m_vecTriangles[*iter].normal; } @@ -392,15 +408,15 @@ namespace PolyVox bool MeshDecimator::collapseChangesFaceNormals(uint32_t uSrc, uint32_t uDst, float fThreshold) { bool faceFlipped = false; - list& triangles = trianglesUsingVertex[uSrc]; + vector& triangles = trianglesUsingVertex[uSrc]; - for(list::iterator triIter = triangles.begin(); triIter != triangles.end(); triIter++) + for(vector::iterator triIter = triangles.begin(); triIter != triangles.end(); triIter++) { uint32_t tri = *triIter; - uint32_t v0Old = m_pOutputMesh->m_vecTriangleIndices[tri * 3]; - uint32_t v1Old = m_pOutputMesh->m_vecTriangleIndices[tri * 3 + 1]; - uint32_t v2Old = m_pOutputMesh->m_vecTriangleIndices[tri * 3 + 2]; + const uint32_t& v0Old = m_pOutputMesh->m_vecTriangleIndices[tri * 3]; + const uint32_t& v1Old = m_pOutputMesh->m_vecTriangleIndices[tri * 3 + 1]; + const uint32_t& v2Old = m_pOutputMesh->m_vecTriangleIndices[tri * 3 + 2]; //Check if degenerate if((v0Old == v1Old) || (v1Old == v2Old) || (v2Old == v0Old)) @@ -425,13 +441,13 @@ namespace PolyVox continue; } - Vector3DFloat v0OldPos = m_pOutputMesh->m_vecVertices[vertexMapper[v0Old]].getPosition(); //Note: we need the vertex mapper here. These neighbouring vertices may have been moved. - Vector3DFloat v1OldPos = m_pOutputMesh->m_vecVertices[vertexMapper[v1Old]].getPosition(); - Vector3DFloat v2OldPos = m_pOutputMesh->m_vecVertices[vertexMapper[v2Old]].getPosition(); + const Vector3DFloat& v0OldPos = m_pOutputMesh->m_vecVertices[vertexMapper[v0Old]].getPosition(); //Note: we need the vertex mapper here. These neighbouring vertices may have been moved. + const Vector3DFloat& v1OldPos = m_pOutputMesh->m_vecVertices[vertexMapper[v1Old]].getPosition(); + const Vector3DFloat& v2OldPos = m_pOutputMesh->m_vecVertices[vertexMapper[v2Old]].getPosition(); - Vector3DFloat v0NewPos = m_pOutputMesh->m_vecVertices[vertexMapper[v0New]].getPosition(); - Vector3DFloat v1NewPos = m_pOutputMesh->m_vecVertices[vertexMapper[v1New]].getPosition(); - Vector3DFloat v2NewPos = m_pOutputMesh->m_vecVertices[vertexMapper[v2New]].getPosition(); + const Vector3DFloat& v0NewPos = m_pOutputMesh->m_vecVertices[vertexMapper[v0New]].getPosition(); + const Vector3DFloat& v1NewPos = m_pOutputMesh->m_vecVertices[vertexMapper[v1New]].getPosition(); + const Vector3DFloat& v2NewPos = m_pOutputMesh->m_vecVertices[vertexMapper[v2New]].getPosition(); Vector3DFloat OldNormal = (v1OldPos - v0OldPos).cross(v2OldPos - v1OldPos); Vector3DFloat NewNormal = (v1NewPos - v0NewPos).cross(v2NewPos - v1NewPos);