Added some documentation and small performance improvements.

This commit is contained in:
David Williams 2011-01-05 22:43:46 +00:00
parent a7828995d9
commit e6307a9a77
2 changed files with 55 additions and 9 deletions

View File

@ -28,6 +28,37 @@ freely, subject to the following restrictions:
namespace PolyVox
{
/// The MeshDecimator reduces the number of triangles in a mesh.
////////////////////////////////////////////////////////////////////////////////
/// Meshes generated by the PolyVox surface extractors typically have a very high
/// number of triangles in them. This can pose difficulties both for the rendering
/// storage of such meshes. The MeshDecimator provides a way of reducing the triangle
/// count with minimal visual effect.
///
/// The MeshDecimator is based on the principle of edge collapse, and currently works
/// with meshes generated by the SurfaceExtractor or CubicSurfaceExtractor. It does
/// not work with meshes generated by the CubicSurfaceExtractorWithNormals, although
/// this may be addressed in the future. The algorithm iterates over each pair of
/// connected vertices in the mesh and attemps to determine if they can be collapsed
/// into a single vertex.
///
/// The main criteria used in deciding whether two vertices can collapse is whether
/// they have the same normal. In the case of the cubic surfaces the normals must be
/// exactly the same, whereas in the case of the Marching Cubes surfaces a threshold
/// is used to determine whether two normals are 'close enough'. Additional constraints
/// apply to vertices which lie on the edges of regions or on the boundary between two
/// regions - these vertices are much less likely to be collapsed.
///
/// Given a mesh called 'mesh', you can create a decimated version as follows:
/// \code
/// SurfaceMesh<PositionMaterial> decimatedMesh;
/// MeshDecimator<PositionMaterial> decimator(&mesh, &decimatedMesh);
/// decimator.execute();
/// \endcode
///
/// The above applies for a cubic mesh, for a Marching Cubes mesh you need to parametise
/// the MeshDecimator and resulting SurfaceMesh on the 'PositionMaterialNormal' type
/// instead of the 'PositionMaterial' type.
template <typename VertexType>
class MeshDecimator
{
@ -62,8 +93,10 @@ namespace PolyVox
Vector3DFloat normal;
};
public:
///Constructor
MeshDecimator(const SurfaceMesh<VertexType>* pInputMesh, SurfaceMesh<VertexType>* pOutputMesh, float fEdgeCollapseThreshold = 0.95f);
///Performs the decimation.
void execute();
private:

View File

@ -23,6 +23,16 @@ freely, subject to the following restrictions:
namespace PolyVox
{
////////////////////////////////////////////////////////////////////////////////
/// Builds a MeshDecimator.
/// \param pInputMesh A pointer to the mesh to be decimated.
/// \param pOutputMesh A pointer to where the result should be stored. Any existing
/// contents will be deleted.
/// \param fEdgeCollapseThreshold This is only use in the case of a Marching Cubes
/// surface and controls how close two normals must be to collapse. The dot product
/// between the normals is computed and compared to this threshold. A threshold of
/// 1.0 means nothing will collapse, a threshold of 0.0 means everything will collapse.
////////////////////////////////////////////////////////////////////////////////
template <typename VertexType>
MeshDecimator<VertexType>::MeshDecimator(const SurfaceMesh<VertexType>* pInputMesh, SurfaceMesh<VertexType>* pOutputMesh, float fEdgeCollapseThreshold)
:m_pInputMesh(pInputMesh)
@ -324,6 +334,11 @@ namespace PolyVox
template<>
bool MeshDecimator<PositionMaterialNormal>::canCollapseNormalEdge(uint32_t uSrc, uint32_t uDst)
{
if(m_vecInitialVertexMetadata[uSrc].normal.dot(m_vecInitialVertexMetadata[uDst].normal) < m_fMinDotProductForCollapse)
{
return false;
}
//With the marching cubes surface we honour the user specified threshold
return !collapseChangesFaceNormals(uSrc, uDst, m_fMinDotProductForCollapse);
}
@ -331,6 +346,10 @@ namespace PolyVox
template<>
bool MeshDecimator<PositionMaterial>::canCollapseNormalEdge(uint32_t uSrc, uint32_t uDst)
{
//We don't actually use the normal here, because we want to allow face
//vertices to collapse onto edge vertices. Simply checking whether anything
//has flipped has proved to be the most robust approach, though rather slow...
//User specified threshold is not used for cubic surface, any
//movement is too much (but allow for floating point error).
return !collapseChangesFaceNormals(uSrc, uDst, 0.999f);
@ -365,11 +384,13 @@ namespace PolyVox
return false;
}
//This function should really use some work. For a start we already have the
//faces normals for the input mesh yet we are computing them on the fly here.
template <typename VertexType>
bool MeshDecimator<VertexType>::collapseChangesFaceNormals(uint32_t uSrc, uint32_t uDst, float fThreshold)
{
bool faceFlipped = false;
list<uint32_t> triangles = trianglesUsingVertex[uSrc];
list<uint32_t>& triangles = trianglesUsingVertex[uSrc];
for(list<uint32_t>::iterator triIter = triangles.begin(); triIter != triangles.end(); triIter++)
{
@ -410,14 +431,6 @@ namespace PolyVox
Vector3DFloat v1NewPos = m_pOutputMesh->m_vecVertices[vertexMapper[v1New]].getPosition();
Vector3DFloat v2NewPos = m_pOutputMesh->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);