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.
This commit is contained in:
parent
5c8dd011e7
commit
89c48cdc27
@ -28,6 +28,9 @@ freely, subject to the following restrictions:
|
|||||||
#include "GradientEstimators.h"
|
#include "GradientEstimators.h"
|
||||||
#include "SurfaceExtractor.h"
|
#include "SurfaceExtractor.h"
|
||||||
|
|
||||||
|
#include "RenderDynamicMesh.h"
|
||||||
|
#include "Mesh.h"
|
||||||
|
|
||||||
//Some namespaces we need
|
//Some namespaces we need
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace PolyVox;
|
using namespace PolyVox;
|
||||||
@ -97,7 +100,40 @@ void OpenGLWidget::setVolume(PolyVox::Volume<PolyVox::uint8_t>* volData)
|
|||||||
|
|
||||||
if(isp->m_vecTriangleIndices.size() > 0)
|
if(isp->m_vecTriangleIndices.size() > 0)
|
||||||
{
|
{
|
||||||
isp->makeProgressiveMesh();
|
//isp->makeProgressiveMesh();
|
||||||
|
|
||||||
|
/*RenderDynamicMesh rdm;
|
||||||
|
rdm.buildFromIndexedSurfacePatch(*isp);*/
|
||||||
|
|
||||||
|
//computeNormalsForVertices(m_volData, *(isp.get()), SOBEL_SMOOTHED);
|
||||||
|
|
||||||
|
//isp->smoothPositions(0.3f);
|
||||||
|
//isp->generateAveragedFaceNormals(true);
|
||||||
|
|
||||||
|
/*for(int ct = 0; ct < 20; ct ++)
|
||||||
|
{
|
||||||
|
//cout << "Before: " << isp->noOfDegenerateTris() << endl;
|
||||||
|
isp->decimate();
|
||||||
|
//cout << "After: " << isp->noOfDegenerateTris() << endl;
|
||||||
|
isp->removeDegenerateTris();
|
||||||
|
//cout << "After Remove: " << isp->noOfDegenerateTris() << endl << endl;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//For decimation built into ISP
|
||||||
|
//isp->generateAveragedFaceNormals(true);
|
||||||
|
|
||||||
|
isp->decimate(0.999f);
|
||||||
|
|
||||||
|
//isp->generateAveragedFaceNormals(true);
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
/*isp->generateAveragedFaceNormals(true);
|
||||||
|
Mesh mesh;
|
||||||
|
mesh.buildFromISP(isp.get());
|
||||||
|
//mesh.removeEdge(*(mesh.m_edges.begin()));
|
||||||
|
mesh.decimateAll();
|
||||||
|
mesh.fillISP(isp.get());*/
|
||||||
|
|
||||||
|
|
||||||
Vector3DUint8 v3dRegPos(uRegionX,uRegionY,uRegionZ);
|
Vector3DUint8 v3dRegPos(uRegionX,uRegionY,uRegionZ);
|
||||||
|
@ -7,6 +7,10 @@ SET(CORE_SRC_FILES
|
|||||||
source/GradientEstimators.cpp
|
source/GradientEstimators.cpp
|
||||||
source/IndexedSurfacePatch.cpp
|
source/IndexedSurfacePatch.cpp
|
||||||
source/Log.cpp
|
source/Log.cpp
|
||||||
|
source/Mesh.cpp
|
||||||
|
source/MeshEdge.cpp
|
||||||
|
source/MeshFace.cpp
|
||||||
|
source/MeshVertex.cpp
|
||||||
source/progmesh.cpp
|
source/progmesh.cpp
|
||||||
source/Region.cpp
|
source/Region.cpp
|
||||||
source/SurfaceExtractor.cpp
|
source/SurfaceExtractor.cpp
|
||||||
@ -21,6 +25,10 @@ SET(CORE_INC_FILES
|
|||||||
include/IndexedSurfacePatch.h
|
include/IndexedSurfacePatch.h
|
||||||
include/list.h
|
include/list.h
|
||||||
include/Log.h
|
include/Log.h
|
||||||
|
include/Mesh.h
|
||||||
|
include/MeshEdge.h
|
||||||
|
include/MeshFace.h
|
||||||
|
include/MeshVertex.h
|
||||||
include/PolyVoxForwardDeclarations.h
|
include/PolyVoxForwardDeclarations.h
|
||||||
include/progmesh.h
|
include/progmesh.h
|
||||||
include/Region.h
|
include/Region.h
|
||||||
|
@ -64,7 +64,7 @@ namespace PolyVox
|
|||||||
void clear(void);
|
void clear(void);
|
||||||
const bool isEmpty(void) const;
|
const bool isEmpty(void) const;
|
||||||
|
|
||||||
void smoothPositions(float fAmount, bool bIncludeEdgeVertices = false);
|
void smoothPositions(float fAmount, bool bIncludeGeometryEdgeVertices = false);
|
||||||
void sumNearbyNormals(bool bNormaliseResult = true);
|
void sumNearbyNormals(bool bNormaliseResult = true);
|
||||||
|
|
||||||
POLYVOX_SHARED_PTR<IndexedSurfacePatch> extractSubset(std::set<uint8_t> setMaterials);
|
POLYVOX_SHARED_PTR<IndexedSurfacePatch> extractSubset(std::set<uint8_t> setMaterials);
|
||||||
@ -76,6 +76,14 @@ namespace PolyVox
|
|||||||
/*void growMaterialBoundary(void);
|
/*void growMaterialBoundary(void);
|
||||||
int countMaterialBoundary(void);*/
|
int countMaterialBoundary(void);*/
|
||||||
|
|
||||||
|
bool isSubset(std::bitset<4> a, std::bitset<4> b);
|
||||||
|
|
||||||
|
void decimate(float fMinDotProductForCollapse = 0.999f);
|
||||||
|
|
||||||
|
uint32_t performDecimationPass(float fMinDotProductForCollapse);
|
||||||
|
int noOfDegenerateTris(void);
|
||||||
|
void removeDegenerateTris(void);
|
||||||
|
|
||||||
void makeProgressiveMesh(void);
|
void makeProgressiveMesh(void);
|
||||||
|
|
||||||
Region m_Region;
|
Region m_Region;
|
||||||
|
61
library/PolyVoxCore/include/Mesh.h
Normal file
61
library/PolyVoxCore/include/Mesh.h
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
#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
|
||||||
|
|
||||||
|
#ifndef __PolyVox_Mesh_H__
|
||||||
|
#define __PolyVox_Mesh_H__
|
||||||
|
|
||||||
|
#include "MeshEdge.h"
|
||||||
|
#include "MeshFace.h"
|
||||||
|
#include "MeshVertex.h"
|
||||||
|
|
||||||
|
#include "PolyVoxImpl/TypeDef.h"
|
||||||
|
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
namespace PolyVox
|
||||||
|
{
|
||||||
|
class POLYVOXCORE_API Mesh
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
void buildFromISP(IndexedSurfacePatch* pIsp);
|
||||||
|
void fillISP(IndexedSurfacePatch* pIsp);
|
||||||
|
void matchEdgePairs(void);
|
||||||
|
void computeEdgeCosts(void);
|
||||||
|
|
||||||
|
void removeEdge(MeshEdge* pMeshEdge);
|
||||||
|
|
||||||
|
void decimateAll(void);
|
||||||
|
bool decimateOne(void);
|
||||||
|
|
||||||
|
bool isSane(void);
|
||||||
|
|
||||||
|
std::set<MeshEdge*> m_edges;
|
||||||
|
std::set<MeshFace*> m_faces;
|
||||||
|
std::set<MeshVertex*> m_vertices;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
61
library/PolyVoxCore/include/MeshEdge.h
Normal file
61
library/PolyVoxCore/include/MeshEdge.h
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
#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
|
||||||
|
|
||||||
|
#ifndef __PolyVox_MeshEdge_H__
|
||||||
|
#define __PolyVox_MeshEdge_H__
|
||||||
|
|
||||||
|
#include "PolyVoxForwardDeclarations.h"
|
||||||
|
|
||||||
|
#include "PolyVoxImpl/TypeDef.h"
|
||||||
|
|
||||||
|
namespace PolyVox
|
||||||
|
{
|
||||||
|
class POLYVOXCORE_API MeshEdge
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MeshEdge();
|
||||||
|
|
||||||
|
bool isSane(void);
|
||||||
|
|
||||||
|
void computeEdgeCost(Mesh* pParentMesh);
|
||||||
|
|
||||||
|
MeshEdge* m_pOtherEdge;
|
||||||
|
MeshEdge* m_pNextEdge;
|
||||||
|
MeshEdge* m_pPreviousEdge;
|
||||||
|
|
||||||
|
MeshVertex* m_pSrc;
|
||||||
|
MeshVertex* m_pDest;
|
||||||
|
|
||||||
|
MeshFace* m_pFace;
|
||||||
|
|
||||||
|
float m_fCost;
|
||||||
|
};
|
||||||
|
|
||||||
|
//FIXME - Rather than being global, these should just be used to sort within the set.
|
||||||
|
bool operator==(const MeshEdge& lhs, const MeshEdge& rhs);
|
||||||
|
bool operator<(const MeshEdge& lhs, const MeshEdge& rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
49
library/PolyVoxCore/include/MeshFace.h
Normal file
49
library/PolyVoxCore/include/MeshFace.h
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
#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
|
||||||
|
|
||||||
|
#ifndef __PolyVox_MeshFace_H__
|
||||||
|
#define __PolyVox_MeshFace_H__
|
||||||
|
|
||||||
|
#include "MeshEdge.h"
|
||||||
|
|
||||||
|
#include "PolyVoxImpl/TypeDef.h"
|
||||||
|
|
||||||
|
namespace PolyVox
|
||||||
|
{
|
||||||
|
class POLYVOXCORE_API MeshFace
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MeshFace();
|
||||||
|
bool isSane(void);
|
||||||
|
|
||||||
|
MeshEdge* m_pEdge;
|
||||||
|
|
||||||
|
Vector3DFloat getNormal(void);
|
||||||
|
bool collapseFlipsFace(MeshEdge* pEdgeToCollapse);
|
||||||
|
bool collapseFlipsFaceImpl(Vector3DFloat fixed0, Vector3DFloat fixed1, Vector3DFloat oldPos, Vector3DFloat newPos);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
52
library/PolyVoxCore/include/MeshVertex.h
Normal file
52
library/PolyVoxCore/include/MeshVertex.h
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
#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
|
||||||
|
|
||||||
|
#ifndef __PolyVox_MeshVertex_H__
|
||||||
|
#define __PolyVox_MeshVertex_H__
|
||||||
|
|
||||||
|
#include "PolyVoxForwardDeclarations.h"
|
||||||
|
#include "SurfaceVertex.h"
|
||||||
|
|
||||||
|
#include "PolyVoxImpl/TypeDef.h"
|
||||||
|
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
namespace PolyVox
|
||||||
|
{
|
||||||
|
class POLYVOXCORE_API MeshVertex
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MeshVertex();
|
||||||
|
SurfaceVertex m_vertexData;
|
||||||
|
//MeshEdge* m_pEdge;
|
||||||
|
//std::set<MeshFace*> m_faces;
|
||||||
|
//std::set<MeshEdge*> m_edges; //Edges which have this vertex as the src
|
||||||
|
long int m_index; //Bit wasteful to store this the whle time, as it's only used when converting to ISPs?
|
||||||
|
|
||||||
|
bool isSane(void);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -39,6 +39,13 @@ namespace PolyVox
|
|||||||
typedef Volume<uint16_t> UInt16Volume;
|
typedef Volume<uint16_t> UInt16Volume;
|
||||||
//---------------------------------
|
//---------------------------------
|
||||||
|
|
||||||
|
//---------- Mesh ----------
|
||||||
|
class Mesh;
|
||||||
|
class MeshEdge;
|
||||||
|
class MeshFace;
|
||||||
|
class MeshVertex;
|
||||||
|
//---------------------------------
|
||||||
|
|
||||||
class IndexedSurfacePatch;
|
class IndexedSurfacePatch;
|
||||||
class Region;
|
class Region;
|
||||||
class SurfaceVertex;
|
class SurfaceVertex;
|
||||||
|
@ -29,8 +29,18 @@ freely, subject to the following restrictions:
|
|||||||
#include "PolyVoxImpl/TypeDef.h"
|
#include "PolyVoxImpl/TypeDef.h"
|
||||||
#include "Vector.h"
|
#include "Vector.h"
|
||||||
|
|
||||||
|
#include <bitset>
|
||||||
|
|
||||||
namespace PolyVox
|
namespace PolyVox
|
||||||
{
|
{
|
||||||
|
enum POLYVOXCORE_API VertexFlags
|
||||||
|
{
|
||||||
|
VF_ON_MATERIAL_EDGE = 0x00,
|
||||||
|
VF_ON_GEOMETRY_EDGE_X = 0x01,
|
||||||
|
VF_ON_GEOMETRY_EDGE_Y = 0x02,
|
||||||
|
VF_ON_GEOMETRY_EDGE_Z = 0x03
|
||||||
|
};
|
||||||
|
|
||||||
class POLYVOXCORE_API SurfaceVertex
|
class POLYVOXCORE_API SurfaceVertex
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -42,20 +52,26 @@ namespace PolyVox
|
|||||||
const Vector3DFloat& getNormal(void) const;
|
const Vector3DFloat& getNormal(void) const;
|
||||||
const Vector3DFloat& getPosition(void) const;
|
const Vector3DFloat& getPosition(void) const;
|
||||||
|
|
||||||
bool isEdgeVertex(void) const;
|
bool isOnEdge(void) const;
|
||||||
|
bool isOnGeometryEdge(void) const;
|
||||||
void setEdgeVertex(bool isEdgeVertex);
|
bool isOnGeometryEdgeX(void) const;
|
||||||
|
bool isOnGeometryEdgeY(void) const;
|
||||||
|
bool isOnGeometryEdgeZ(void) const;
|
||||||
|
bool isOnMaterialEdge(void) const;
|
||||||
|
|
||||||
void setMaterial(float materialToSet);
|
void setMaterial(float materialToSet);
|
||||||
void setNormal(const Vector3DFloat& normalToSet);
|
void setNormal(const Vector3DFloat& normalToSet);
|
||||||
|
void setOnGeometryEdgeX(bool bOnRegionEdge);
|
||||||
|
void setOnGeometryEdgeY(bool bOnRegionEdge);
|
||||||
|
void setOnGeometryEdgeZ(bool bOnRegionEdge);
|
||||||
|
void setOnMaterialEdge(bool bOnMaterialEdge);
|
||||||
void setPosition(const Vector3DFloat& positionToSet);
|
void setPosition(const Vector3DFloat& positionToSet);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Vector3DFloat position;
|
Vector3DFloat position;
|
||||||
Vector3DFloat normal;
|
Vector3DFloat normal;
|
||||||
float material; //FIXME: This shouldn't be float on CPU?
|
float material; //FIXME: This shouldn't be float on CPU?
|
||||||
bool m_bIsEdgeVertex;
|
std::bitset<4> m_bFlags;
|
||||||
bool m_bIsMaterialEdgeVertex;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -27,6 +27,8 @@ freely, subject to the following restrictions:
|
|||||||
|
|
||||||
#include "progmesh.h"
|
#include "progmesh.h"
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
namespace PolyVox
|
namespace PolyVox
|
||||||
@ -108,9 +110,9 @@ namespace PolyVox
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_vecVertices[index0].m_bIsMaterialEdgeVertex = true;
|
m_vecVertices[index0].setOnMaterialEdge(true);
|
||||||
m_vecVertices[index1].m_bIsMaterialEdgeVertex = true;
|
m_vecVertices[index1].setOnMaterialEdge(true);
|
||||||
m_vecVertices[index2].m_bIsMaterialEdgeVertex = true;
|
m_vecVertices[index2].setOnMaterialEdge(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,6 +126,8 @@ namespace PolyVox
|
|||||||
{
|
{
|
||||||
m_vecVertices.clear();
|
m_vecVertices.clear();
|
||||||
m_vecTriangleIndices.clear();
|
m_vecTriangleIndices.clear();
|
||||||
|
m_vecLodRecords.clear();
|
||||||
|
m_mapUsedMaterials.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool IndexedSurfacePatch::isEmpty(void) const
|
const bool IndexedSurfacePatch::isEmpty(void) const
|
||||||
@ -138,11 +142,11 @@ namespace PolyVox
|
|||||||
/// normals must hve been set to something sensible before this functions is called.
|
/// normals must hve been set to something sensible before this functions is called.
|
||||||
/// \param fAmount A factor controlling how much the vertices move by. Find a good
|
/// \param fAmount A factor controlling how much the vertices move by. Find a good
|
||||||
/// value by experimentation, starting with something small such as 0.1f.
|
/// value by experimentation, starting with something small such as 0.1f.
|
||||||
/// \param bIncludeEdgeVertices Indicates whether vertices on the edge of an
|
/// \param bIncludeGeometryEdgeVertices Indicates whether vertices on the edge of an
|
||||||
/// IndexedSurfacePatch should be smoothed. This can cause dicontinuities between
|
/// IndexedSurfacePatch should be smoothed. This can cause dicontinuities between
|
||||||
/// neighbouring patches.
|
/// neighbouring patches.
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
void IndexedSurfacePatch::smoothPositions(float fAmount, bool bIncludeEdgeVertices)
|
void IndexedSurfacePatch::smoothPositions(float fAmount, bool bIncludeGeometryEdgeVertices)
|
||||||
{
|
{
|
||||||
if(m_vecVertices.size() == 0) //FIXME - I don't think we should need this test, but I have seen crashes otherwise...
|
if(m_vecVertices.size() == 0) //FIXME - I don't think we should need this test, but I have seen crashes otherwise...
|
||||||
{
|
{
|
||||||
@ -203,7 +207,7 @@ namespace PolyVox
|
|||||||
//Update with the new positions
|
//Update with the new positions
|
||||||
for(uint32_t uIndex = 0; uIndex < newPositions.size(); uIndex++)
|
for(uint32_t uIndex = 0; uIndex < newPositions.size(); uIndex++)
|
||||||
{
|
{
|
||||||
if((bIncludeEdgeVertices) || (m_vecVertices[uIndex].isEdgeVertex() == false))
|
if((bIncludeGeometryEdgeVertices) || (m_vecVertices[uIndex].isOnGeometryEdge() == false))
|
||||||
{
|
{
|
||||||
m_vecVertices[uIndex].setPosition(newPositions[uIndex]);
|
m_vecVertices[uIndex].setPosition(newPositions[uIndex]);
|
||||||
}
|
}
|
||||||
@ -413,6 +417,313 @@ namespace PolyVox
|
|||||||
m_vecVertices = vecNewVertices;
|
m_vecVertices = vecNewVertices;
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
|
void IndexedSurfacePatch::decimate(float fMinDotProductForCollapse)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Note for after holiday - This decimation is half working, but we get some undesirable collpses still. The face flip check
|
||||||
|
should stop these but doesn't quite seem to work. Also, note that before calling this function it is better if
|
||||||
|
'generateAveragedFaceNormals(true);' has been called first, as this seems to give better normals for our purposes.
|
||||||
|
*/
|
||||||
|
uint32_t noOfEdgesCollapsed = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
//generateAveragedFaceNormals(true);
|
||||||
|
noOfEdgesCollapsed = performDecimationPass(fMinDotProductForCollapse);
|
||||||
|
removeDegenerateTris();
|
||||||
|
}while(noOfEdgesCollapsed > 0);
|
||||||
|
|
||||||
|
//cout << "Collapsed " << performDecimationPass(fMinDotProductForCollapse) << " edges." << endl; removeDegenerateTris();
|
||||||
|
/*cout << "Collapsed " << performDecimationPass(fMinDotProductForCollapse) << " edges." << endl; removeDegenerateTris();
|
||||||
|
cout << "Collapsed " << performDecimationPass(fMinDotProductForCollapse) << " edges." << endl; removeDegenerateTris();
|
||||||
|
cout << "Collapsed " << performDecimationPass(fMinDotProductForCollapse) << " edges." << endl; removeDegenerateTris();
|
||||||
|
cout << "Collapsed " << performDecimationPass(fMinDotProductForCollapse) << " edges." << endl; removeDegenerateTris();*/
|
||||||
|
|
||||||
|
|
||||||
|
//Decimation will have invalidated LOD levels.
|
||||||
|
m_vecLodRecords.clear();
|
||||||
|
LodRecord lodRecord;
|
||||||
|
lodRecord.beginIndex = 0;
|
||||||
|
lodRecord.endIndex = getNoOfIndices();
|
||||||
|
m_vecLodRecords.push_back(lodRecord);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Returns true if every bit which is set in 'a' is also set in 'b'. The reverse does not need to be true.*/
|
||||||
|
bool IndexedSurfacePatch::isSubset(std::bitset<4> a, std::bitset<4> b)
|
||||||
|
{
|
||||||
|
bool result = true;
|
||||||
|
|
||||||
|
for(int ct = 0; ct < 4; ct++)
|
||||||
|
{
|
||||||
|
if(a.test(ct))
|
||||||
|
{
|
||||||
|
if(b.test(ct) == false)
|
||||||
|
{
|
||||||
|
result = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t IndexedSurfacePatch::performDecimationPass(float fMinDotProductForCollapse)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Note for after holiday - breaking this function down into sub functions will
|
||||||
|
likely help identify where the problem is...
|
||||||
|
*/
|
||||||
|
|
||||||
|
//Do we need a set? Do we actually get duplications?
|
||||||
|
vector< set<uint32_t> > trianglesUsingVertex(m_vecVertices.size());
|
||||||
|
for(int ct = 0; ct < m_vecTriangleIndices.size(); ct++)
|
||||||
|
{
|
||||||
|
int triangle = ct / 3;
|
||||||
|
|
||||||
|
trianglesUsingVertex[m_vecTriangleIndices[ct]].insert(triangle);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint32_t noOfEdgesCollapsed = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Note for after holiday - Check the use of this vertex mapper, and make
|
||||||
|
sure that when we access a vertex we go through the mapper if necessary.
|
||||||
|
*/
|
||||||
|
vector<uint32_t> vertexMapper(m_vecVertices.size());
|
||||||
|
vector<bool> vertexLocked(m_vecVertices.size());
|
||||||
|
|
||||||
|
//Initialise the mapper.
|
||||||
|
for(uint32_t ct = 0; ct < vertexMapper.size(); ct++)
|
||||||
|
{
|
||||||
|
vertexMapper[ct] = ct;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(uint32_t ct = 0; ct < vertexLocked.size(); ct++)
|
||||||
|
{
|
||||||
|
vertexLocked[ct] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//It *may* be beneficial to do this randomisation of the order in which we process the triangles
|
||||||
|
//in order to help the resulting vertices/triangles be more uniformly distributed. As a reminder,
|
||||||
|
//comment out the shuffle line to see what it does.
|
||||||
|
vector<int> vecOfTriCts;
|
||||||
|
for(int triCt = 0; triCt < m_vecTriangleIndices.size() / 3; triCt++)
|
||||||
|
{
|
||||||
|
vecOfTriCts.push_back(triCt);
|
||||||
|
}
|
||||||
|
random_shuffle(vecOfTriCts.begin(), vecOfTriCts.end());
|
||||||
|
|
||||||
|
//For each triange
|
||||||
|
//for(int triCt = 0; triCt < m_vecTriangleIndices.size() / 3; triCt++)
|
||||||
|
for(int ctIter = 0; ctIter < vecOfTriCts.size(); ctIter++)
|
||||||
|
{
|
||||||
|
int triCt = vecOfTriCts[ctIter];
|
||||||
|
|
||||||
|
//For each edge in each triangle
|
||||||
|
for(int edgeCt = 0; edgeCt < 3; edgeCt++)
|
||||||
|
{
|
||||||
|
int v0 = m_vecTriangleIndices[triCt * 3 + (edgeCt)];
|
||||||
|
int v1 = m_vecTriangleIndices[triCt * 3 + ((edgeCt +1) % 3)];
|
||||||
|
|
||||||
|
/*v0 = vertexMapper[v0];
|
||||||
|
v1 = vertexMapper[v1];*/
|
||||||
|
|
||||||
|
//A vertex will be locked if it has already been involved in a collapse this pass.
|
||||||
|
if(vertexLocked[v0] || vertexLocked[v1])
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
//For now, don't collapse vertices on mateial edges...
|
||||||
|
if(m_vecVertices[v0].isOnMaterialEdge() || m_vecVertices[v1].isOnMaterialEdge())
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
//...or those on geometry (region) edges.
|
||||||
|
if(m_vecVertices[v0].isOnGeometryEdge() || m_vecVertices[v1].isOnGeometryEdge())
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
//After holiday, consider using the following line so that 'internal' vertices can collapse onto
|
||||||
|
//edges (but not vice-versa) and edges can collapse onto corners (but not vice-versa).
|
||||||
|
//FIXME - Stop corners collapsing onto corners!
|
||||||
|
/*if(isSubset(m_vecVertices[v0].m_bFlags, m_vecVertices[v1].m_bFlags) == false)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
//Check the normals are within the threashold.
|
||||||
|
if(m_vecVertices[v0].getNormal().dot(m_vecVertices[v1].getNormal()) < fMinDotProductForCollapse)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//The last test is whether we will flip any of the faces
|
||||||
|
|
||||||
|
bool faceFlipped = false;
|
||||||
|
set<uint32_t> triangles = trianglesUsingVertex[v0];
|
||||||
|
/*set<uint32_t> triangles;
|
||||||
|
std::set_union(trianglesUsingVertex[v0].begin(), trianglesUsingVertex[v0].end(),
|
||||||
|
trianglesUsingVertex[v1].begin(), trianglesUsingVertex[v1].end(),
|
||||||
|
std::inserter(triangles, triangles.begin()));*/
|
||||||
|
|
||||||
|
for(set<uint32_t>::iterator triIter = triangles.begin(); triIter != triangles.end(); triIter++)
|
||||||
|
{
|
||||||
|
uint32_t tri = *triIter;
|
||||||
|
|
||||||
|
uint32_t v0Old = m_vecTriangleIndices[tri * 3];
|
||||||
|
uint32_t v1Old = m_vecTriangleIndices[tri * 3 + 1];
|
||||||
|
uint32_t v2Old = 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_vecVertices[vertexMapper[v0Old]].getPosition();
|
||||||
|
Vector3DFloat v1OldPos = m_vecVertices[vertexMapper[v1Old]].getPosition();
|
||||||
|
Vector3DFloat v2OldPos = m_vecVertices[vertexMapper[v2Old]].getPosition();
|
||||||
|
|
||||||
|
Vector3DFloat v0NewPos = m_vecVertices[vertexMapper[v0New]].getPosition();
|
||||||
|
Vector3DFloat v1NewPos = m_vecVertices[vertexMapper[v1New]].getPosition();
|
||||||
|
Vector3DFloat v2NewPos = 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)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//Move v0 onto v1
|
||||||
|
vertexMapper[v0] = v1; //vertexMapper[v1];
|
||||||
|
vertexLocked[v0] = true;
|
||||||
|
vertexLocked[v1] = true;
|
||||||
|
|
||||||
|
//Increment the counter
|
||||||
|
++noOfEdgesCollapsed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(noOfEdgesCollapsed > 0)
|
||||||
|
{
|
||||||
|
//Fix up the indices
|
||||||
|
for(int triCt = 0; triCt < m_vecTriangleIndices.size(); triCt++)
|
||||||
|
{
|
||||||
|
uint32_t before = m_vecTriangleIndices[triCt];
|
||||||
|
uint32_t after = vertexMapper[m_vecTriangleIndices[triCt]];
|
||||||
|
if(before != after)
|
||||||
|
{
|
||||||
|
m_vecTriangleIndices[triCt] = vertexMapper[m_vecTriangleIndices[triCt]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return noOfEdgesCollapsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
int IndexedSurfacePatch::noOfDegenerateTris(void)
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
for(int triCt = 0; triCt < m_vecTriangleIndices.size();)
|
||||||
|
{
|
||||||
|
int v0 = m_vecTriangleIndices[triCt];
|
||||||
|
triCt++;
|
||||||
|
int v1 = m_vecTriangleIndices[triCt];
|
||||||
|
triCt++;
|
||||||
|
int v2 = m_vecTriangleIndices[triCt];
|
||||||
|
triCt++;
|
||||||
|
|
||||||
|
if((v0 == v1) || (v1 == v2) || (v2 == v0))
|
||||||
|
{
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IndexedSurfacePatch::removeDegenerateTris(void)
|
||||||
|
{
|
||||||
|
int noOfNonDegenerate = 0;
|
||||||
|
int targetCt = 0;
|
||||||
|
for(int triCt = 0; triCt < m_vecTriangleIndices.size();)
|
||||||
|
{
|
||||||
|
int v0 = m_vecTriangleIndices[triCt];
|
||||||
|
triCt++;
|
||||||
|
int v1 = m_vecTriangleIndices[triCt];
|
||||||
|
triCt++;
|
||||||
|
int v2 = m_vecTriangleIndices[triCt];
|
||||||
|
triCt++;
|
||||||
|
|
||||||
|
if((v0 != v1) && (v1 != v2) & (v2 != v0))
|
||||||
|
{
|
||||||
|
m_vecTriangleIndices[targetCt] = v0;
|
||||||
|
targetCt++;
|
||||||
|
m_vecTriangleIndices[targetCt] = v1;
|
||||||
|
targetCt++;
|
||||||
|
m_vecTriangleIndices[targetCt] = v2;
|
||||||
|
targetCt++;
|
||||||
|
|
||||||
|
noOfNonDegenerate++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_vecTriangleIndices.resize(noOfNonDegenerate * 3);
|
||||||
|
}
|
||||||
|
|
||||||
void IndexedSurfacePatch::makeProgressiveMesh(void)
|
void IndexedSurfacePatch::makeProgressiveMesh(void)
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -425,7 +736,7 @@ namespace PolyVox
|
|||||||
vec.y = m_vecVertices[vertCt].getPosition().getY();
|
vec.y = m_vecVertices[vertCt].getPosition().getY();
|
||||||
vec.z = m_vecVertices[vertCt].getPosition().getZ();
|
vec.z = m_vecVertices[vertCt].getPosition().getZ();
|
||||||
|
|
||||||
if(m_vecVertices[vertCt].isEdgeVertex() || m_vecVertices[vertCt].m_bIsMaterialEdgeVertex)
|
if(m_vecVertices[vertCt].isOnEdge())
|
||||||
{
|
{
|
||||||
vec.fBoundaryCost = 1.0f;
|
vec.fBoundaryCost = 1.0f;
|
||||||
}
|
}
|
||||||
|
448
library/PolyVoxCore/source/Mesh.cpp
Normal file
448
library/PolyVoxCore/source/Mesh.cpp
Normal file
@ -0,0 +1,448 @@
|
|||||||
|
#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;
|
||||||
|
}
|
||||||
|
}
|
158
library/PolyVoxCore/source/MeshEdge.cpp
Normal file
158
library/PolyVoxCore/source/MeshEdge.cpp
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
#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 "MeshEdge.h"
|
||||||
|
|
||||||
|
#include "Mesh.h"
|
||||||
|
#include "MeshFace.h"
|
||||||
|
#include "MeshVertex.h"
|
||||||
|
#include "SurfaceVertex.h"
|
||||||
|
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
namespace PolyVox
|
||||||
|
{
|
||||||
|
|
||||||
|
bool operator==(const MeshEdge& lhs, const MeshEdge& rhs)
|
||||||
|
{
|
||||||
|
return lhs.m_pSrc == rhs.m_pSrc && lhs.m_pDest == rhs.m_pDest;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator<(const MeshEdge& lhs, const MeshEdge& rhs)
|
||||||
|
{
|
||||||
|
if(lhs == rhs)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (lhs.m_pSrc < rhs.m_pSrc)
|
||||||
|
return true;
|
||||||
|
if (rhs.m_pSrc < lhs.m_pSrc)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (lhs.m_pDest < rhs.m_pDest)
|
||||||
|
return true;
|
||||||
|
if (rhs.m_pDest < lhs.m_pDest)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
MeshEdge::MeshEdge()
|
||||||
|
{
|
||||||
|
m_pOtherEdge = 0;
|
||||||
|
m_pNextEdge = 0;
|
||||||
|
m_pPreviousEdge = 0;
|
||||||
|
|
||||||
|
m_pSrc = 0;
|
||||||
|
m_pDest = 0;
|
||||||
|
|
||||||
|
m_pFace = 0;
|
||||||
|
|
||||||
|
m_fCost = 1000000.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MeshEdge::computeEdgeCost(Mesh* pParentMesh)
|
||||||
|
{
|
||||||
|
SurfaceVertex v0Data = m_pSrc->m_vertexData;
|
||||||
|
SurfaceVertex v1Data = m_pDest->m_vertexData;
|
||||||
|
|
||||||
|
m_fCost = 1000000.0f;
|
||||||
|
|
||||||
|
//For now, don't collapse vertices on material edges...
|
||||||
|
if(v0Data.isOnMaterialEdge() || v1Data.isOnMaterialEdge())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//...or those on geometry (region) edges.
|
||||||
|
if(v0Data.isOnGeometryEdge() || v1Data.isOnGeometryEdge())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Check the normals are within the threshold.
|
||||||
|
if(v0Data.getNormal().dot(v1Data.getNormal()) < 0.999)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Test for face flips
|
||||||
|
for(std::set<MeshFace*>::iterator faceIter = pParentMesh->m_faces.begin(); faceIter != pParentMesh->m_faces.end(); faceIter++)
|
||||||
|
{
|
||||||
|
if((*faceIter)->collapseFlipsFace(this))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_fCost = 0.0f;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MeshEdge::isSane(void)
|
||||||
|
{
|
||||||
|
if(m_pSrc == 0)
|
||||||
|
{
|
||||||
|
std::cout << "SANITY CHECK FAIL: Edge has no source vertex" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(m_pDest == 0)
|
||||||
|
{
|
||||||
|
std::cout << "SANITY CHECK FAIL: Edge has no destination vertex" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(m_pFace == 0)
|
||||||
|
{
|
||||||
|
std::cout << "SANITY CHECK FAIL: Edge has no face attached" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Check loops
|
||||||
|
if(this != m_pNextEdge->m_pNextEdge->m_pNextEdge)
|
||||||
|
{
|
||||||
|
std::cout << "SANITY CHECK FAIL: Next edge loop is broken" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this != m_pPreviousEdge->m_pPreviousEdge->m_pPreviousEdge)
|
||||||
|
{
|
||||||
|
std::cout << "SANITY CHECK FAIL: Previous edge loop is broken" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Make sure the other edge points back here
|
||||||
|
if(m_pOtherEdge != 0)
|
||||||
|
{
|
||||||
|
if(this != m_pOtherEdge->m_pOtherEdge)
|
||||||
|
{
|
||||||
|
std::cout << "SANITY CHECK FAIL: Other edge exists but does not point back here." << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
114
library/PolyVoxCore/source/MeshFace.cpp
Normal file
114
library/PolyVoxCore/source/MeshFace.cpp
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
#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 "MeshFace.h"
|
||||||
|
|
||||||
|
#include "MeshEdge.h"
|
||||||
|
#include "MeshVertex.h"
|
||||||
|
|
||||||
|
#include "Vector.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace PolyVox
|
||||||
|
{
|
||||||
|
MeshFace::MeshFace()
|
||||||
|
{
|
||||||
|
m_pEdge = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MeshFace::isSane(void)
|
||||||
|
{
|
||||||
|
if(m_pEdge == 0)
|
||||||
|
{
|
||||||
|
std::cout << "SANITY CHECK FAIL: Face has no edge attached" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector3DFloat MeshFace::getNormal(void)
|
||||||
|
{
|
||||||
|
//Find the three vertices
|
||||||
|
Vector3DFloat pV0 = m_pEdge->m_pSrc->m_vertexData.getPosition();
|
||||||
|
Vector3DFloat pV1 = m_pEdge->m_pNextEdge->m_pSrc->m_vertexData.getPosition();
|
||||||
|
Vector3DFloat pV2 = m_pEdge->m_pNextEdge->m_pNextEdge->m_pSrc->m_vertexData.getPosition();
|
||||||
|
|
||||||
|
Vector3DFloat crossProduct = (pV1 - pV0).cross(pV2 - pV0);
|
||||||
|
|
||||||
|
assert(crossProduct.length() > 0.001);
|
||||||
|
|
||||||
|
crossProduct.normalise();
|
||||||
|
|
||||||
|
return crossProduct;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MeshFace::collapseFlipsFace(MeshEdge* pEdgeToCollapse)
|
||||||
|
{
|
||||||
|
MeshVertex* pSrc = pEdgeToCollapse->m_pSrc;
|
||||||
|
MeshVertex* pDest = pEdgeToCollapse->m_pDest;
|
||||||
|
|
||||||
|
MeshVertex* pV0 = m_pEdge->m_pSrc;
|
||||||
|
MeshVertex* pV1 = m_pEdge->m_pNextEdge->m_pSrc;
|
||||||
|
MeshVertex* pV2 = m_pEdge->m_pNextEdge->m_pNextEdge->m_pSrc;
|
||||||
|
|
||||||
|
if(pSrc == pV0)
|
||||||
|
{
|
||||||
|
return collapseFlipsFaceImpl(pV1->m_vertexData.getPosition(), pV2->m_vertexData.getPosition(), pSrc->m_vertexData.getPosition(), pDest->m_vertexData.getPosition());
|
||||||
|
}
|
||||||
|
if(pSrc == pV1)
|
||||||
|
{
|
||||||
|
return collapseFlipsFaceImpl(pV0->m_vertexData.getPosition(), pV2->m_vertexData.getPosition(), pSrc->m_vertexData.getPosition(), pDest->m_vertexData.getPosition());
|
||||||
|
}
|
||||||
|
if(pSrc == pV2)
|
||||||
|
{
|
||||||
|
return collapseFlipsFaceImpl(pV0->m_vertexData.getPosition(), pV1->m_vertexData.getPosition(), pSrc->m_vertexData.getPosition(), pDest->m_vertexData.getPosition());
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MeshFace::collapseFlipsFaceImpl(Vector3DFloat fixed0, Vector3DFloat fixed1, Vector3DFloat oldPos, Vector3DFloat newPos)
|
||||||
|
{
|
||||||
|
Vector3DFloat oldCrossProduct = (fixed0 - oldPos).cross(fixed1 - oldPos);
|
||||||
|
Vector3DFloat newCrossProduct = (fixed0 - newPos).cross(fixed1 - newPos);
|
||||||
|
|
||||||
|
if(oldCrossProduct.length() < 0.001f)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(newCrossProduct.length() < 0.001f)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
oldCrossProduct.normalise();
|
||||||
|
newCrossProduct.normalise();
|
||||||
|
|
||||||
|
return oldCrossProduct.dot(newCrossProduct) < 0.999f;
|
||||||
|
}
|
||||||
|
}
|
45
library/PolyVoxCore/source/MeshVertex.cpp
Normal file
45
library/PolyVoxCore/source/MeshVertex.cpp
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
#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 "MeshVertex.h"
|
||||||
|
|
||||||
|
namespace PolyVox
|
||||||
|
{
|
||||||
|
MeshVertex::MeshVertex()
|
||||||
|
{
|
||||||
|
m_index = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MeshVertex::isSane(void)
|
||||||
|
{
|
||||||
|
/*if(m_edges.empty())
|
||||||
|
{
|
||||||
|
std::cout << "SANITY CHECK FAIL: Vertex has no edges attached" << std::endl;
|
||||||
|
return false;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -623,7 +623,10 @@ namespace PolyVox
|
|||||||
const Vector3DFloat v3dNormal(v000 > v100 ? 1.0f : -1.0f,0.0,0.0);
|
const Vector3DFloat v3dNormal(v000 > v100 ? 1.0f : -1.0f,0.0,0.0);
|
||||||
const uint8_t uMaterial = v000 | v100; //Because one of these is 0, the or operation takes the max.
|
const uint8_t uMaterial = v000 | v100; //Because one of these is 0, the or operation takes the max.
|
||||||
SurfaceVertex surfaceVertex(v3dPosition, v3dNormal, uMaterial);
|
SurfaceVertex surfaceVertex(v3dPosition, v3dNormal, uMaterial);
|
||||||
surfaceVertex.setEdgeVertex(isXEdge || isYEdge || isZEdge);
|
//surfaceVertex.setOnGeometryEdge(isXEdge || isYEdge || isZEdge);
|
||||||
|
surfaceVertex.setOnGeometryEdgeX(isXEdge);
|
||||||
|
surfaceVertex.setOnGeometryEdgeY(isYEdge);
|
||||||
|
surfaceVertex.setOnGeometryEdgeZ(isZEdge);
|
||||||
uint32_t uLastVertexIndex = m_ispCurrent->addVertex(surfaceVertex);
|
uint32_t uLastVertexIndex = m_ispCurrent->addVertex(surfaceVertex);
|
||||||
m_pCurrentVertexIndicesX[getIndex(uXVolSpace - m_regInputCropped.getLowerCorner().getX(),uYVolSpace - m_regInputCropped.getLowerCorner().getY())] = uLastVertexIndex;
|
m_pCurrentVertexIndicesX[getIndex(uXVolSpace - m_regInputCropped.getLowerCorner().getX(),uYVolSpace - m_regInputCropped.getLowerCorner().getY())] = uLastVertexIndex;
|
||||||
}
|
}
|
||||||
@ -635,7 +638,10 @@ namespace PolyVox
|
|||||||
const Vector3DFloat v3dNormal(0.0,v000 > v010 ? 1.0f : -1.0f,0.0);
|
const Vector3DFloat v3dNormal(0.0,v000 > v010 ? 1.0f : -1.0f,0.0);
|
||||||
const uint8_t uMaterial = v000 | v010; //Because one of these is 0, the or operation takes the max.
|
const uint8_t uMaterial = v000 | v010; //Because one of these is 0, the or operation takes the max.
|
||||||
SurfaceVertex surfaceVertex(v3dPosition, v3dNormal, uMaterial);
|
SurfaceVertex surfaceVertex(v3dPosition, v3dNormal, uMaterial);
|
||||||
surfaceVertex.setEdgeVertex(isXEdge || isYEdge || isZEdge);
|
//surfaceVertex.setOnGeometryEdge(isXEdge || isYEdge || isZEdge);
|
||||||
|
surfaceVertex.setOnGeometryEdgeX(isXEdge);
|
||||||
|
surfaceVertex.setOnGeometryEdgeY(isYEdge);
|
||||||
|
surfaceVertex.setOnGeometryEdgeZ(isZEdge);
|
||||||
uint32_t uLastVertexIndex = m_ispCurrent->addVertex(surfaceVertex);
|
uint32_t uLastVertexIndex = m_ispCurrent->addVertex(surfaceVertex);
|
||||||
m_pCurrentVertexIndicesY[getIndex(uXVolSpace - m_regInputCropped.getLowerCorner().getX(),uYVolSpace - m_regInputCropped.getLowerCorner().getY())] = uLastVertexIndex;
|
m_pCurrentVertexIndicesY[getIndex(uXVolSpace - m_regInputCropped.getLowerCorner().getX(),uYVolSpace - m_regInputCropped.getLowerCorner().getY())] = uLastVertexIndex;
|
||||||
}
|
}
|
||||||
@ -647,7 +653,10 @@ namespace PolyVox
|
|||||||
const Vector3DFloat v3dNormal(0.0,0.0,v000 > v001 ? 1.0f : -1.0f);
|
const Vector3DFloat v3dNormal(0.0,0.0,v000 > v001 ? 1.0f : -1.0f);
|
||||||
const uint8_t uMaterial = v000 | v001; //Because one of these is 0, the or operation takes the max.
|
const uint8_t uMaterial = v000 | v001; //Because one of these is 0, the or operation takes the max.
|
||||||
SurfaceVertex surfaceVertex(v3dPosition, v3dNormal, uMaterial);
|
SurfaceVertex surfaceVertex(v3dPosition, v3dNormal, uMaterial);
|
||||||
surfaceVertex.setEdgeVertex(isXEdge || isYEdge || isZEdge);
|
//surfaceVertex.setOnGeometryEdge(isXEdge || isYEdge || isZEdge);
|
||||||
|
surfaceVertex.setOnGeometryEdgeX(isXEdge);
|
||||||
|
surfaceVertex.setOnGeometryEdgeY(isYEdge);
|
||||||
|
surfaceVertex.setOnGeometryEdgeZ(isZEdge);
|
||||||
uint32_t uLastVertexIndex = m_ispCurrent->addVertex(surfaceVertex);
|
uint32_t uLastVertexIndex = m_ispCurrent->addVertex(surfaceVertex);
|
||||||
m_pCurrentVertexIndicesZ[getIndex(uXVolSpace - m_regInputCropped.getLowerCorner().getX(),uYVolSpace - m_regInputCropped.getLowerCorner().getY())] = uLastVertexIndex;
|
m_pCurrentVertexIndicesZ[getIndex(uXVolSpace - m_regInputCropped.getLowerCorner().getX(),uYVolSpace - m_regInputCropped.getLowerCorner().getY())] = uLastVertexIndex;
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,6 @@ namespace PolyVox
|
|||||||
SurfaceVertex::SurfaceVertex(Vector3DFloat positionToSet, float materialToSet)
|
SurfaceVertex::SurfaceVertex(Vector3DFloat positionToSet, float materialToSet)
|
||||||
:position(positionToSet)
|
:position(positionToSet)
|
||||||
,material(materialToSet)
|
,material(materialToSet)
|
||||||
,m_bIsMaterialEdgeVertex(false)
|
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -45,7 +44,6 @@ namespace PolyVox
|
|||||||
:position(positionToSet)
|
:position(positionToSet)
|
||||||
,normal(normalToSet)
|
,normal(normalToSet)
|
||||||
,material(materialToSet)
|
,material(materialToSet)
|
||||||
,m_bIsMaterialEdgeVertex(false)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,14 +62,34 @@ namespace PolyVox
|
|||||||
return position;
|
return position;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SurfaceVertex::isEdgeVertex(void) const
|
bool SurfaceVertex::isOnEdge(void) const
|
||||||
{
|
{
|
||||||
return m_bIsEdgeVertex;
|
return (isOnMaterialEdge() || isOnGeometryEdge());
|
||||||
}
|
}
|
||||||
|
|
||||||
void SurfaceVertex::setEdgeVertex(bool isEdgeVertex)
|
bool SurfaceVertex::isOnMaterialEdge(void) const
|
||||||
{
|
{
|
||||||
m_bIsEdgeVertex = isEdgeVertex;
|
return m_bFlags[VF_ON_MATERIAL_EDGE];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SurfaceVertex::isOnGeometryEdge(void) const
|
||||||
|
{
|
||||||
|
return m_bFlags[VF_ON_GEOMETRY_EDGE_X] || m_bFlags[VF_ON_GEOMETRY_EDGE_Y] || m_bFlags[VF_ON_GEOMETRY_EDGE_Z];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SurfaceVertex::isOnGeometryEdgeX(void) const
|
||||||
|
{
|
||||||
|
return m_bFlags[VF_ON_GEOMETRY_EDGE_X];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SurfaceVertex::isOnGeometryEdgeY(void) const
|
||||||
|
{
|
||||||
|
return m_bFlags[VF_ON_GEOMETRY_EDGE_Y];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SurfaceVertex::isOnGeometryEdgeZ(void) const
|
||||||
|
{
|
||||||
|
return m_bFlags[VF_ON_GEOMETRY_EDGE_Z];
|
||||||
}
|
}
|
||||||
|
|
||||||
void SurfaceVertex::setMaterial(float materialToSet)
|
void SurfaceVertex::setMaterial(float materialToSet)
|
||||||
@ -84,6 +102,26 @@ namespace PolyVox
|
|||||||
normal = normalToSet;
|
normal = normalToSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SurfaceVertex::setOnMaterialEdge(bool bOnMaterialEdge)
|
||||||
|
{
|
||||||
|
m_bFlags[VF_ON_MATERIAL_EDGE] = bOnMaterialEdge;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SurfaceVertex::setOnGeometryEdgeX(bool bOnRegionEdge)
|
||||||
|
{
|
||||||
|
m_bFlags[VF_ON_GEOMETRY_EDGE_X] = bOnRegionEdge;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SurfaceVertex::setOnGeometryEdgeY(bool bOnRegionEdge)
|
||||||
|
{
|
||||||
|
m_bFlags[VF_ON_GEOMETRY_EDGE_Y] = bOnRegionEdge;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SurfaceVertex::setOnGeometryEdgeZ(bool bOnRegionEdge)
|
||||||
|
{
|
||||||
|
m_bFlags[VF_ON_GEOMETRY_EDGE_Z] = bOnRegionEdge;
|
||||||
|
}
|
||||||
|
|
||||||
void SurfaceVertex::setPosition(const Vector3DFloat& positionToSet)
|
void SurfaceVertex::setPosition(const Vector3DFloat& positionToSet)
|
||||||
{
|
{
|
||||||
position = positionToSet;
|
position = positionToSet;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user