Work on MeshDecimator.

This commit is contained in:
David Williams 2011-01-03 11:19:03 +00:00
parent 090e002ff1
commit 996dfac39c
2 changed files with 137 additions and 185 deletions

View File

@ -28,29 +28,27 @@ freely, subject to the following restrictions:
namespace PolyVox namespace PolyVox
{ {
enum POLYVOXCORE_API NormalFlags struct InitialVertexMetadata
{ {
NF_NORMAL_NEG_X,
NF_NORMAL_POS_X,
NF_NORMAL_NEG_Y,
NF_NORMAL_POS_Y,
NF_NORMAL_NEG_Z,
NF_NORMAL_POS_Z,
NF_NO_OF_FLAGS
};
struct VertexMetadata
{
bool hasDuplicate;
uint64_t materialKey;
list<uint32_t> trianglesUsingVertex; list<uint32_t> trianglesUsingVertex;
int noOfDifferentNormals;
Vector3DFloat normal; Vector3DFloat normal;
std::bitset<NF_NO_OF_FLAGS> m_bNormalFlags;
bool isOnRegionEdge; bool isOnRegionEdge;
bool isOnMaterialEdge; bool isOnMaterialEdge;
}; };
struct CurrentVertexMetadata
{
list<uint32_t> trianglesUsingVertex;
};
struct Triangle
{
uint32_t v0;
uint32_t v1;
uint32_t v2;
Vector3DFloat normal;
};
template <typename VertexType> template <typename VertexType>
class MeshDecimator class MeshDecimator
{ {
@ -61,7 +59,12 @@ namespace PolyVox
private: private:
void fillVertexMetadata(std::vector<VertexMetadata>& vecVertexMetadata); void fillInitialVertexMetadata(std::vector<InitialVertexMetadata>& vecInitialVertexMetadata);
void fillCurrentVertexMetadata(std::vector<CurrentVertexMetadata>& vecCurrentVertexMetadata);
void buildTriangles(void);
bool attemptEdgeCollapse(uint32_t uSrc, uint32_t uDest);
SurfaceMesh<VertexType>* m_pInputMesh; SurfaceMesh<VertexType>* m_pInputMesh;
//SurfaceMesh<PositionMaterial>* pMeshOutput; //SurfaceMesh<PositionMaterial>* pMeshOutput;
@ -69,7 +72,6 @@ namespace PolyVox
void countNoOfNeighboursUsingMaterial(void); void countNoOfNeighboursUsingMaterial(void);
uint32_t performDecimationPass(float fMinDotProductForCollapse); uint32_t performDecimationPass(float fMinDotProductForCollapse);
bool isSubset(std::bitset<VF_NO_OF_FLAGS> a, std::bitset<VF_NO_OF_FLAGS> b); bool isSubset(std::bitset<VF_NO_OF_FLAGS> a, std::bitset<VF_NO_OF_FLAGS> b);
bool isSubsetCubic(std::bitset<NF_NO_OF_FLAGS> a, std::bitset<NF_NO_OF_FLAGS> b);
bool canCollapseEdge(uint32_t uSrc, uint32_t uDest); bool canCollapseEdge(uint32_t uSrc, uint32_t uDest);
bool canCollapseNormalEdge(uint32_t uSrc, uint32_t uDst); bool canCollapseNormalEdge(uint32_t uSrc, uint32_t uDst);
@ -80,18 +82,17 @@ namespace PolyVox
//Data structures used during decimation //Data structures used during decimation
std::vector<uint8_t> m_vecNoOfNeighboursUsingMaterial; std::vector<uint8_t> m_vecNoOfNeighboursUsingMaterial;
vector<bool> vertexLocked; std::vector<bool> vertexLocked;
vector<uint32_t> vertexMapper; std::vector<uint32_t> vertexMapper;
//vector< list<uint32_t> > trianglesUsingVertexCurrently; //vector< list<uint32_t> > trianglesUsingVertexCurrently;
vector<int> vecOfTriCts; std::vector<int> vecOfTriCts;
vector<Vector3DFloat> vecOfTriNormals; std::vector<Vector3DFloat> vecOfTriNormals;
std::vector<Triangle> m_vecTriangles;
//vector<int> noOfDifferentNormals; std::vector<InitialVertexMetadata> m_vecInitialVertexMetadata;
std::vector<CurrentVertexMetadata> m_vecCurrentVertexMetadata;
vector<VertexMetadata> m_vecInitialVertexMetadata;
vector<VertexMetadata> m_vecCurrentVertexMetadata;
float fMinDotProductForCollapse; float fMinDotProductForCollapse;
}; };

View File

@ -38,7 +38,8 @@ namespace PolyVox
// determine when material boundary edges can collapse. // determine when material boundary edges can collapse.
countNoOfNeighboursUsingMaterial(); countNoOfNeighboursUsingMaterial();
fillVertexMetadata(m_vecInitialVertexMetadata); buildTriangles();
fillInitialVertexMetadata(m_vecInitialVertexMetadata);
uint32_t noOfEdgesCollapsed; uint32_t noOfEdgesCollapsed;
do do
@ -57,64 +58,8 @@ namespace PolyVox
} }
template <typename VertexType> template <typename VertexType>
void MeshDecimator<VertexType>::fillVertexMetadata(std::vector<VertexMetadata>& vecVertexMetadata) void MeshDecimator<VertexType>::buildTriangles(void)
{ {
vecVertexMetadata.clear();
vecVertexMetadata.resize(m_pInputMesh->m_vecVertices.size());
//Initialise the metadata
for(int ct = 0; ct < vecVertexMetadata.size(); ct++)
{
vecVertexMetadata[ct].hasDuplicate = false;
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
/*trianglesUsingVertex.clear();
trianglesUsingVertex.resize(m_pInputMesh->m_vecVertices.size());*/
for(int ct = 0; ct < m_pInputMesh->m_vecTriangleIndices.size(); ct++)
{
int triangle = ct / 3;
vecVertexMetadata[m_pInputMesh->m_vecTriangleIndices[ct]].trianglesUsingVertex.push_back(triangle);
}
/*hasDuplicate.clear();
hasDuplicate.resize(m_pInputMesh->m_vecVertices.size());
std::fill(hasDuplicate.begin(), hasDuplicate.end(), false);*/
for(int outerCt = 0; outerCt < m_pInputMesh->m_vecVertices.size()-1; outerCt++)
{
for(int innerCt = outerCt+1; innerCt < m_pInputMesh->m_vecVertices.size(); innerCt++)
{
if((m_pInputMesh->m_vecVertices[innerCt].position - m_pInputMesh->m_vecVertices[outerCt].position).lengthSquared() < 0.001f)
{
vecVertexMetadata[innerCt].hasDuplicate = true;
vecVertexMetadata[outerCt].hasDuplicate = true;
vecVertexMetadata[innerCt].isOnMaterialEdge = true;
vecVertexMetadata[outerCt].isOnMaterialEdge = true;
}
}
}
/*materialKey.clear();
materialKey.resize(m_pInputMesh->m_vecVertices.size());
std::fill(materialKey.begin(), materialKey.end(), 0);*/
for(int ct = 0; ct < m_pInputMesh->m_vecTriangleIndices.size(); ct++)
{
uint32_t vertex = m_pInputMesh->m_vecTriangleIndices[ct];
//NOTE: uint8_t may not always be large engouh?
uint8_t uMaterial = m_pInputMesh->m_vecVertices[vertex].material;
vecVertexMetadata[vertex].materialKey <<= 8;
vecVertexMetadata[vertex].materialKey |= uMaterial;
}
// Each triangle exists in this vector once. // Each triangle exists in this vector once.
vecOfTriCts.clear(); vecOfTriCts.clear();
vecOfTriCts.resize(m_pInputMesh->m_vecTriangleIndices.size() / 3); vecOfTriCts.resize(m_pInputMesh->m_vecTriangleIndices.size() / 3);
@ -143,6 +88,58 @@ namespace PolyVox
vecOfTriNormals[ct] = normal; vecOfTriNormals[ct] = normal;
} }
m_vecTriangles.clear();
m_vecTriangles.resize(m_pInputMesh->m_vecTriangleIndices.size() / 3);
for(int triCt = 0; triCt < m_vecTriangles.size(); triCt++)
{
m_vecTriangles[triCt].v0 = m_pInputMesh->m_vecTriangleIndices[triCt * 3 + 0];
m_vecTriangles[triCt].v1 = m_pInputMesh->m_vecTriangleIndices[triCt * 3 + 1];
m_vecTriangles[triCt].v2 = m_pInputMesh->m_vecTriangleIndices[triCt * 3 + 2];
Vector3DFloat v0Pos = m_pInputMesh->m_vecVertices[m_vecTriangles[triCt].v0].position;
Vector3DFloat v1Pos = m_pInputMesh->m_vecVertices[m_vecTriangles[triCt].v1].position;
Vector3DFloat v2Pos = m_pInputMesh->m_vecVertices[m_vecTriangles[triCt].v2].position;
Vector3DFloat v0v1 = v1Pos - v0Pos;
Vector3DFloat v0v2 = v2Pos - v0Pos;
Vector3DFloat normal = v0v1.cross(v0v2);
normal.normalise();
m_vecTriangles[triCt].normal = normal;
}
}
template <typename VertexType>
void MeshDecimator<VertexType>::fillInitialVertexMetadata(std::vector<InitialVertexMetadata>& vecVertexMetadata)
{
vecVertexMetadata.clear();
vecVertexMetadata.resize(m_pInputMesh->m_vecVertices.size());
//Initialise the metadata
for(int ct = 0; ct < vecVertexMetadata.size(); ct++)
{
vecVertexMetadata[ct].trianglesUsingVertex.clear();
vecVertexMetadata[ct].normal.setElements(0,0,0);
vecVertexMetadata[ct].isOnRegionEdge = false;
vecVertexMetadata[ct].isOnMaterialEdge = false;
}
for(int ct = 0; ct < m_vecTriangles.size(); ct++)
{
vecVertexMetadata[m_vecTriangles[ct].v0].trianglesUsingVertex.push_back(ct);
}
for(int outerCt = 0; outerCt < m_pInputMesh->m_vecVertices.size()-1; outerCt++)
{
for(int innerCt = outerCt+1; innerCt < m_pInputMesh->m_vecVertices.size(); innerCt++)
{
if((m_pInputMesh->m_vecVertices[innerCt].position - m_pInputMesh->m_vecVertices[outerCt].position).lengthSquared() < 0.001f)
{
vecVertexMetadata[innerCt].isOnMaterialEdge = true;
vecVertexMetadata[outerCt].isOnMaterialEdge = true;
}
}
}
//noOfDifferentNormals.clear(); //noOfDifferentNormals.clear();
//noOfDifferentNormals.resize(m_pInputMesh->m_vecVertices.size()); //noOfDifferentNormals.resize(m_pInputMesh->m_vecVertices.size());
//std::fill(vecVertexMetadata.noOfDifferentNormals.begin(), vecVertexMetadata.noOfDifferentNormals.end(), 0); //std::fill(vecVertexMetadata.noOfDifferentNormals.begin(), vecVertexMetadata.noOfDifferentNormals.end(), 0);
@ -151,30 +148,9 @@ namespace PolyVox
Vector3DFloat sumOfNormals(0.0f,0.0f,0.0f); Vector3DFloat sumOfNormals(0.0f,0.0f,0.0f);
for(list<uint32_t>::const_iterator iter = vecVertexMetadata[ct].trianglesUsingVertex.cbegin(); iter != vecVertexMetadata[ct].trianglesUsingVertex.cend(); iter++) for(list<uint32_t>::const_iterator iter = vecVertexMetadata[ct].trianglesUsingVertex.cbegin(); iter != vecVertexMetadata[ct].trianglesUsingVertex.cend(); iter++)
{ {
sumOfNormals += vecOfTriNormals[*iter]; sumOfNormals += m_vecTriangles[*iter].normal;
} }
vecVertexMetadata[ct].noOfDifferentNormals = 0;
if(abs(sumOfNormals.getX()) > 0.001)
vecVertexMetadata[ct].noOfDifferentNormals++;
if(abs(sumOfNormals.getY()) > 0.001)
vecVertexMetadata[ct].noOfDifferentNormals++;
if(abs(sumOfNormals.getZ()) > 0.001)
vecVertexMetadata[ct].noOfDifferentNormals++;
if(sumOfNormals.getX() < -0.001)
vecVertexMetadata[ct].m_bNormalFlags.set(NF_NORMAL_NEG_X);
if(sumOfNormals.getX() > 0.001)
vecVertexMetadata[ct].m_bNormalFlags.set(NF_NORMAL_POS_X);
if(sumOfNormals.getY() < -0.001)
vecVertexMetadata[ct].m_bNormalFlags.set(NF_NORMAL_NEG_Y);
if(sumOfNormals.getY() > 0.001)
vecVertexMetadata[ct].m_bNormalFlags.set(NF_NORMAL_POS_Y);
if(sumOfNormals.getZ() < -0.001)
vecVertexMetadata[ct].m_bNormalFlags.set(NF_NORMAL_NEG_Z);
if(sumOfNormals.getZ() > 0.001)
vecVertexMetadata[ct].m_bNormalFlags.set(NF_NORMAL_POS_Z);
vecVertexMetadata[ct].normal = sumOfNormals; vecVertexMetadata[ct].normal = sumOfNormals;
vecVertexMetadata[ct].normal.normalise(); vecVertexMetadata[ct].normal.normalise();
} }
@ -185,8 +161,28 @@ namespace PolyVox
bool bInside = m_pInputMesh->m_Region.containsPoint(m_pInputMesh->m_vecVertices[ct].getPosition() + offset); bool bInside = m_pInputMesh->m_Region.containsPoint(m_pInputMesh->m_vecVertices[ct].getPosition() + offset);
vecVertexMetadata[ct].isOnRegionEdge = !bInside; vecVertexMetadata[ct].isOnRegionEdge = !bInside;
} }
}
//std::cout << "----------" <<std::endl; template <typename VertexType>
void MeshDecimator<VertexType>::fillCurrentVertexMetadata(std::vector<CurrentVertexMetadata>& vecVertexMetadata)
{
vecVertexMetadata.clear();
vecVertexMetadata.resize(m_pInputMesh->m_vecVertices.size());
//Initialise the metadata
for(int ct = 0; ct < vecVertexMetadata.size(); ct++)
{
vecVertexMetadata[ct].trianglesUsingVertex.clear();
}
//Determine triangles using each vertex
/*trianglesUsingVertex.clear();
trianglesUsingVertex.resize(m_pInputMesh->m_vecVertices.size());*/
for(int ct = 0; ct < m_pInputMesh->m_vecTriangleIndices.size(); ct++)
{
int triangle = ct / 3;
vecVertexMetadata[m_pInputMesh->m_vecTriangleIndices[ct]].trianglesUsingVertex.push_back(triangle);
}
} }
template <typename VertexType> template <typename VertexType>
@ -227,33 +223,26 @@ namespace PolyVox
vertexLocked[ct] = false; vertexLocked[ct] = false;
} }
fillVertexMetadata(m_vecCurrentVertexMetadata); buildTriangles();
fillCurrentVertexMetadata(m_vecCurrentVertexMetadata);
//For each triange... //For each triange...
for(int ctIter = 0; ctIter < vecOfTriCts.size(); ctIter++) for(int ctIter = 0; ctIter < m_vecTriangles.size(); ctIter++)
{ {
int triCt = vecOfTriCts[ctIter];
//For each edge in each triangle if(attemptEdgeCollapse(m_vecTriangles[ctIter].v0, m_vecTriangles[ctIter].v1))
for(int edgeCt = 0; edgeCt < 3; edgeCt++)
{ {
int v0 = m_pInputMesh->m_vecTriangleIndices[triCt * 3 + (edgeCt)]; ++noOfEdgesCollapsed;
int v1 = m_pInputMesh->m_vecTriangleIndices[triCt * 3 + ((edgeCt +1) % 3)]; }
bool bCanCollapseEdge = canCollapseEdge(v0, v1); if(attemptEdgeCollapse(m_vecTriangles[ctIter].v1, m_vecTriangles[ctIter].v2))
{
++noOfEdgesCollapsed;
}
//////////////////////////////////////////////////////////////////////////////// if(attemptEdgeCollapse(m_vecTriangles[ctIter].v2, m_vecTriangles[ctIter].v0))
{
if(bCanCollapseEdge) ++noOfEdgesCollapsed;
{
//Move v0 onto v1
vertexMapper[v0] = v1; //vertexMapper[v1];
vertexLocked[v0] = true;
vertexLocked[v1] = true;
//Increment the counter
++noOfEdgesCollapsed;
}
} }
} }
@ -274,6 +263,23 @@ namespace PolyVox
return noOfEdgesCollapsed; return noOfEdgesCollapsed;
} }
template <typename VertexType>
bool MeshDecimator<VertexType>::attemptEdgeCollapse(uint32_t uSrc, uint32_t uDst)
{
if(canCollapseEdge(uSrc, uDst))
{
//Move v0 onto v1
vertexMapper[uSrc] = uDst; //vertexMapper[v1];
vertexLocked[uSrc] = true;
vertexLocked[uDst] = true;
//Increment the counter
return true;
}
return false;
}
//This function looks at every vertex in the mesh and determines //This function looks at every vertex in the mesh and determines
//how many of it's neighbours have the same material. //how many of it's neighbours have the same material.
template <typename VertexType> template <typename VertexType>
@ -333,26 +339,6 @@ namespace PolyVox
return result; return result;
} }
template <typename VertexType>
bool MeshDecimator<VertexType>::isSubsetCubic(std::bitset<NF_NO_OF_FLAGS> a, std::bitset<NF_NO_OF_FLAGS> b)
{
bool result = true;
for(int ct = 0; ct < NF_NO_OF_FLAGS; ct++) //Start at '1' to skip material flag
{
if(a.test(ct))
{
if(b.test(ct) == false)
{
result = false;
break;
}
}
}
return result;
}
//template <typename VertexType> //template <typename VertexType>
bool MeshDecimator<PositionMaterialNormal>::canCollapseEdge(uint32_t uSrc, uint32_t uDst) bool MeshDecimator<PositionMaterialNormal>::canCollapseEdge(uint32_t uSrc, uint32_t uDst)
{ {
@ -519,38 +505,13 @@ namespace PolyVox
template <typename VertexType> template <typename VertexType>
bool MeshDecimator<VertexType>::canCollapseNormalEdge(uint32_t uSrc, uint32_t uDst) bool MeshDecimator<VertexType>::canCollapseNormalEdge(uint32_t uSrc, uint32_t uDst)
{ {
if(m_vecInitialVertexMetadata[uSrc].m_bNormalFlags.count() == 1) //Face return !collapseChangesFaceNormals(uSrc, uDst, 0.999f);
{
return true;
}
if(m_vecInitialVertexMetadata[uSrc].m_bNormalFlags.count() == 3) //Corner
{
return false;
}
if(m_vecInitialVertexMetadata[uSrc].m_bNormalFlags.count() == 2) //Edge
{
if(isSubsetCubic(m_vecInitialVertexMetadata[uSrc].m_bNormalFlags, m_vecInitialVertexMetadata[uDst].m_bNormalFlags) == false)
{
return false;
}
if(collapseChangesFaceNormals(uSrc, uDst, 0.999f))
{
return false;
}
return true;
}
return true;
} }
template <typename VertexType> template <typename VertexType>
bool MeshDecimator<VertexType>::canCollapseRegionEdge(uint32_t uSrc, uint32_t uDst) bool MeshDecimator<VertexType>::canCollapseRegionEdge(uint32_t uSrc, uint32_t uDst)
{ {
//return false; return false;
if(m_vecInitialVertexMetadata[uDst].isOnRegionEdge) if(m_vecInitialVertexMetadata[uDst].isOnRegionEdge)
{ {
@ -573,22 +534,12 @@ namespace PolyVox
return false; return false;
} }
if(m_vecInitialVertexMetadata[uSrc].m_bNormalFlags.count() == 3) //Corner
{
return false;
}
if(m_vecInitialVertexMetadata[uSrc].trianglesUsingVertex.size() != m_vecInitialVertexMetadata[uDst].trianglesUsingVertex.size()) //Corner if(m_vecInitialVertexMetadata[uSrc].trianglesUsingVertex.size() != m_vecInitialVertexMetadata[uDst].trianglesUsingVertex.size()) //Corner
{ {
return false; return false;
} }
if(m_vecInitialVertexMetadata[uSrc].m_bNormalFlags.count() != m_vecInitialVertexMetadata[uDst].m_bNormalFlags.count()) //Corner if(m_vecInitialVertexMetadata[uSrc].normal.dot(m_vecInitialVertexMetadata[uDst].normal) < 0.999f)
{
return false;
}
if(isSubsetCubic(m_vecInitialVertexMetadata[uSrc].m_bNormalFlags, m_vecInitialVertexMetadata[uDst].m_bNormalFlags) == false)
{ {
return false; return false;
} }