David Williams 89c48cdc27 Working version of mesh decimation code which acts directly on vertex/index buffers.
Also initial work on a 'dynamic' mesh for simplification... but this probably won't be needed now.
2010-02-02 23:18:17 +00:00

448 lines
13 KiB
C++

#pragma region License
/*******************************************************************************
Copyright (c) 2005-2009 David Williams
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*******************************************************************************/
#pragma endregion
#include "Mesh.h"
#include "IndexedSurfacePatch.h"
#include <vector>
namespace PolyVox
{
void Mesh::buildFromISP(IndexedSurfacePatch* pIsp)
{
//First we copy the vertices across.
//We also keep track of where each vertex went
std::vector< std::set<MeshVertex*>::iterator > vertexMapper(pIsp->getNoOfVertices());
for(int ct = 0; ct < pIsp->getNoOfVertices(); ct++)
{
MeshVertex* pMeshVertex = new MeshVertex;
pMeshVertex->m_vertexData = pIsp->m_vecVertices[ct];
vertexMapper[ct] = m_vertices.insert(pMeshVertex).first;
}
//Next, we add each triangle to the mesh
for(int triCt = 0; triCt < pIsp->getNoOfIndices() / 3; triCt++)
{
int index0 = pIsp->m_vecTriangleIndices[triCt * 3];
int index1 = pIsp->m_vecTriangleIndices[triCt * 3 + 1];
int index2 = pIsp->m_vecTriangleIndices[triCt * 3 + 2];
MeshVertex* meshVertex0 = *(vertexMapper[index0]);
MeshVertex* meshVertex1 = *(vertexMapper[index1]);
MeshVertex* meshVertex2 = *(vertexMapper[index2]);
MeshEdge* v0v1 = new MeshEdge;
v0v1->m_pSrc = meshVertex0;
v0v1->m_pDest = meshVertex1;
//meshVertex0->m_edges.insert(v0v1);
MeshEdge* v1v2 = new MeshEdge;
v1v2->m_pSrc = meshVertex1;
v1v2->m_pDest = meshVertex2;
//meshVertex1->m_edges.insert(v1v2);
MeshEdge* v2v0 = new MeshEdge;
v2v0->m_pSrc = meshVertex2;
v2v0->m_pDest = meshVertex0;
//meshVertex2->m_edges.insert(v2v0);
v0v1->m_pNextEdge = v1v2;
v1v2->m_pNextEdge = v2v0;
v2v0->m_pNextEdge = v0v1;
v0v1->m_pPreviousEdge = v2v0;
v1v2->m_pPreviousEdge = v0v1;
v2v0->m_pPreviousEdge = v1v2;
v0v1->m_pOtherEdge = 0;
v1v2->m_pOtherEdge = 0;
v2v0->m_pOtherEdge = 0;
m_edges.insert(v0v1);
m_edges.insert(v1v2);
m_edges.insert(v2v0);
//Create the face
MeshFace* meshFace = new MeshFace;
v0v1->m_pFace = meshFace;
v1v2->m_pFace = meshFace;
v2v0->m_pFace = meshFace;
meshFace->m_pEdge = v0v1; //Just use the first edge
m_faces.insert(meshFace);
//The the vertices they are used by the face
//meshVertex0->m_faces.insert(meshFace);
//meshVertex1->m_faces.insert(meshFace);
//meshVertex2->m_faces.insert(meshFace);
}
//Loop over the edges and try to match up any pairs.
/*for(std::set<MeshEdge*>::iterator edgeIter = m_edges.begin(); edgeIter != m_edges.end(); edgeIter++)
{
MeshEdge* pMeshEdge = *edgeIter;
if(pMeshEdge->m_pOtherEdge == 0)
{
//Let's see if we can find the other edge somewhere.
//Create an example of what we are looking for...
MeshEdge otherEdgeExample;
otherEdgeExample.m_pSrc = pMeshEdge->m_pDest;
otherEdgeExample.m_pDest = pMeshEdge->m_pSrc;
m_edges.find(
}
}*/
/*int counter = 0;
//Lastly, we loop over the edges and determine all those which should be adjacent
for(std::set<MeshEdge*>::iterator outerIter = m_edges.begin(); outerIter != m_edges.end(); outerIter++)
{
std::cout << counter++ << std::endl;
for(std::set<MeshEdge*>::iterator innerIter = m_edges.begin(); innerIter != m_edges.end(); innerIter++)
{
MeshEdge* edge0 = *outerIter;
MeshEdge* edge1 = *innerIter;
if((edge0->m_pSrc == edge1->m_pDest) && (edge0->m_pDest == edge1->m_pSrc))
{
edge0->m_pOtherEdge = edge1;
edge1->m_pOtherEdge = edge0;
}
}
}*/
//Match up the edge pains
matchEdgePairs();
//Compute the edge costs
computeEdgeCosts();
//Check sanity
isSane();
}
void Mesh::matchEdgePairs(void)
{
std::set<MeshEdge*> matchedEdges;
while(m_edges.empty() == false)
{
std::set<MeshEdge*>::iterator firstEdgeIter = m_edges.begin();
MeshEdge* firstEdgePtr = *firstEdgeIter;
m_edges.erase(firstEdgeIter);
matchedEdges.insert(firstEdgePtr);
//Attempt to find the opposite edge
for(std::set<MeshEdge*>::iterator edgeIter = m_edges.begin(); edgeIter != m_edges.end(); edgeIter++)
{
MeshEdge* candidate = *edgeIter;
if((firstEdgePtr->m_pSrc == candidate->m_pDest) && (firstEdgePtr->m_pDest == candidate->m_pSrc))
{
m_edges.erase(edgeIter);
matchedEdges.insert(candidate);
firstEdgePtr->m_pOtherEdge = candidate;
candidate->m_pOtherEdge = firstEdgePtr;
break;
}
}
}
m_edges = matchedEdges;
}
void Mesh::computeEdgeCosts(void)
{
for(std::set<MeshEdge*>::iterator edgeIter = m_edges.begin(); edgeIter != m_edges.end(); edgeIter++)
{
(*edgeIter)->computeEdgeCost(this);
}
}
void Mesh::fillISP(IndexedSurfacePatch* pIsp)
{
pIsp->clear();
for(std::set<MeshVertex*>::iterator vertItor = m_vertices.begin(); vertItor != m_vertices.end(); vertItor++)
{
MeshVertex* meshVertex = *vertItor;
meshVertex->m_index = pIsp->addVertex(meshVertex->m_vertexData);
}
for(std::set<MeshFace*>::iterator faceItor = m_faces.begin(); faceItor != m_faces.end(); faceItor++)
{
MeshFace* meshFace = *faceItor;
MeshVertex* v0 = meshFace->m_pEdge->m_pSrc;
MeshVertex* v1 = meshFace->m_pEdge->m_pNextEdge->m_pSrc;
MeshVertex* v2 = meshFace->m_pEdge->m_pNextEdge->m_pNextEdge->m_pSrc;
pIsp->addTriangle(v0->m_index, v1->m_index, v2->m_index);
}
pIsp->m_vecLodRecords.clear();
LodRecord lodRecord;
lodRecord.beginIndex = 0;
lodRecord.endIndex = pIsp->getNoOfIndices();
pIsp->m_vecLodRecords.push_back(lodRecord);
}
void Mesh::removeEdge(MeshEdge* pMeshEdge)
{
//Get the src and dest vertices
MeshVertex* pSrc = pMeshEdge->m_pSrc;
MeshVertex* pDest = pMeshEdge->m_pDest;
//Get the other half of the edge
MeshEdge* pOtherEdge = pMeshEdge->m_pOtherEdge;
//Get the faces
MeshFace* pMeshFace = pMeshEdge->m_pFace;
MeshFace* pOtherFace = 0;
if(pOtherEdge != 0)
{
pOtherFace = pOtherEdge->m_pFace;
}
//Remove the faces (the edges keep pointers to the faces, but those edges will be deleted soon anyway...)
m_faces.erase(pMeshFace);
delete pMeshFace;
pMeshFace = 0;
if(pOtherFace)
{
m_faces.erase(pOtherFace);
delete pOtherFace;
pOtherFace = 0;
}
//Erase the edges
m_edges.erase(pMeshEdge);
m_edges.erase(pMeshEdge->m_pNextEdge);
m_edges.erase(pMeshEdge->m_pPreviousEdge);
/*pMeshEdge->m_pSrc->m_edges.erase(pMeshEdge);
pMeshEdge->m_pNextEdge->m_pSrc->m_edges.erase(pMeshEdge->m_pNextEdge);
pMeshEdge->m_pPreviousEdge->m_pSrc->m_edges.erase(pMeshEdge->m_pPreviousEdge);*/
delete pMeshEdge->m_pNextEdge;
pMeshEdge->m_pNextEdge = 0;
delete pMeshEdge->m_pPreviousEdge;
pMeshEdge->m_pPreviousEdge = 0;
delete pMeshEdge;
//pMeshEdge = 0;
if(pOtherEdge)
{
m_edges.erase(pOtherEdge);
m_edges.erase(pOtherEdge->m_pNextEdge);
m_edges.erase(pOtherEdge->m_pPreviousEdge);
/*pOtherEdge->m_pSrc->m_edges.erase(pOtherEdge);
pOtherEdge->m_pNextEdge->m_pSrc->m_edges.erase(pOtherEdge->m_pNextEdge);
pOtherEdge->m_pPreviousEdge->m_pSrc->m_edges.erase(pOtherEdge->m_pPreviousEdge);*/
delete pOtherEdge->m_pNextEdge;
pOtherEdge->m_pNextEdge = 0;
delete pOtherEdge->m_pPreviousEdge;
pOtherEdge->m_pPreviousEdge = 0;
delete pOtherEdge;
//pOtherEdge = 0;
}
//Find the affected edges
/*std::set<MeshEdge*> affectedEdges = edgesStartingatEitherVertex;
for(std::set<MeshEdge*>::iterator edgeIter = edgesStartingatEitherVertex.begin(); edgeIter != edgesStartingatEitherVertex.end(); edgeIter++)
{
affectedEdges.insert((*edgeIter)->m_pNextEdge);
affectedEdges.insert((*edgeIter)->m_pPreviousEdge);
//if((*edgeIter)->m_pOtherEdge != 0)
//{
// affectedEdges.insert((*edgeIter)->m_pOtherEdge);
//}
}*/
//Update the source and destinations
for(std::set<MeshEdge*>::iterator edgeIter = m_edges.begin(); edgeIter != m_edges.end(); edgeIter++)
{
MeshEdge* pEdge = *edgeIter;
if(pEdge->m_pSrc == pSrc)
{
pEdge->m_pSrc = pDest;
}
if(pEdge->m_pDest == pSrc)
{
pEdge->m_pDest = pDest;
}
}
/*for(std::set<MeshVertex*>::iterator vertexIter = m_vertices.begin(); vertexIter != m_vertices.end(); vertexIter++)
{
(*vertexIter)->m_edges.clear();
}
for(std::set<MeshEdge*>::iterator edgeIter = m_edges.begin(); edgeIter != m_edges.end(); edgeIter++)
{
MeshEdge* pEdge = *edgeIter;
pEdge->m_pSrc->m_edges.insert(pEdge);
}*/
/*for(std::set<MeshEdge*>::iterator edgeIter = affectedEdges.begin(); edgeIter != affectedEdges.end(); edgeIter++)
{
MeshEdge* pEdge = *edgeIter;
if(pEdge->m_pSrc == pSrc)
{
pEdge->m_pSrc = pDest;
}
if(pEdge->m_pDest == pSrc)
{
pEdge->m_pDest = pDest;
}
}*/
//Deal with the vertices
/*pSrc->m_edges.erase(pMeshEdge);
if(pOtherEdge)
{
pDest->m_edges.erase(pOtherEdge);
}*/
//Find the edges starting at either vertex
/*std::set<MeshEdge*> edgesStartingatEitherVertex;
std::set_union(pSrc->m_edges.begin(), pSrc->m_edges.end(),
pDest->m_edges.begin(), pDest->m_edges.end(),
std::inserter(edgesStartingatEitherVertex, edgesStartingatEitherVertex.begin()));*/
//Remove the old vertex
//pDest->m_edges = edgesStartingatEitherVertex;
m_vertices.erase(pSrc);
delete pSrc; //Don't set to 0 yet as we will use the value
//Update any pairings
matchEdgePairs();
/*for(std::set<MeshEdge*>::iterator outerIter = affectedEdges.begin(); outerIter != affectedEdges.end(); outerIter++)
{
for(std::set<MeshEdge*>::iterator innerIter = affectedEdges.begin(); innerIter != affectedEdges.end(); innerIter++)
{
MeshEdge* edge0 = *outerIter;
MeshEdge* edge1 = *innerIter;
if((edge0->m_pSrc == edge1->m_pDest) && (edge0->m_pDest == edge1->m_pSrc))
{
edge0->m_pOtherEdge = edge1;
edge1->m_pOtherEdge = edge0;
}
}
}*/
//Recompute the affected edge costs
computeEdgeCosts();
/*for(std::set<MeshEdge*>::iterator edgeIter = affectedEdges.begin(); edgeIter != affectedEdges.end(); edgeIter++)
{
(*edgeIter)->computeEdgeCost();
}*/
}
void Mesh::decimateAll(void)
{
for(int ct = 0; ct < 100; ct++)
{
std::cout << ct << std::endl;
decimateOne();
//isSane();
}
/*int ct = 0;
while(decimateOne())
{
std::cout << ct++ << std::endl;
}*/
//decimateOne();
}
bool Mesh::decimateOne(void)
{
for(std::set<MeshEdge*>::iterator edgeIter = m_edges.begin(); edgeIter != m_edges.end(); edgeIter++)
{
/*for(int ct = 0; ct < 30; ct++)
{
edgeIter++;
}*/
MeshEdge* pMeshEdge = *edgeIter;
if(pMeshEdge->m_fCost < 1.0)
{
removeEdge(pMeshEdge);
return true;
}
}
return false;
}
bool Mesh::isSane(void)
{
for(std::set<MeshVertex*>::iterator vertexIter = m_vertices.begin(); vertexIter != m_vertices.end(); vertexIter++)
{
//This would be eaiser if we just propergated exceptions?
if((*vertexIter)->isSane() == false)
{
std::cout << "SANITY CHECK FAIL: Problem found in vertex set" << std::endl;
return false;
}
}
for(std::set<MeshFace*>::iterator faceIter = m_faces.begin(); faceIter != m_faces.end(); faceIter++)
{
//This would be eaiser if we just propergated exceptions?
if((*faceIter)->isSane() == false)
{
std::cout << "SANITY CHECK FAIL: Problem found in face set" << std::endl;
return false;
}
}
for(std::set<MeshEdge*>::iterator edgeIter = m_edges.begin(); edgeIter != m_edges.end(); edgeIter++)
{
//This would be eaiser if we just propergated exceptions?
if((*edgeIter)->isSane() == false)
{
std::cout << "SANITY CHECK FAIL: Problem found in edge set" << std::endl;
return false;
}
}
std::cout << "SANITY CHECK SUCCESS" << std::endl;
return true;
}
}