Work on MeshDecimator.
This commit is contained in:
		| @@ -52,14 +52,19 @@ void OpenGLWidget::initializeGL() | ||||
| 	glEnable(GL_DEPTH_TEST);					 | ||||
| 	glDepthFunc(GL_LEQUAL);						 | ||||
|  | ||||
| 	//Anable smooth lighting | ||||
| 	glEnable(GL_LIGHTING); | ||||
| 	glEnable(GL_LIGHT0); | ||||
| 	//Enable smooth lighting | ||||
| 	//glEnable(GL_LIGHTING); | ||||
| 	//glEnable(GL_LIGHT0); | ||||
| 	glShadeModel(GL_SMOOTH); | ||||
|  | ||||
| 	//We'll be rendering with index/vertex arrays | ||||
| 	glEnableClientState(GL_VERTEX_ARRAY); | ||||
| 	glEnableClientState(GL_NORMAL_ARRAY); | ||||
|  | ||||
| 	glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); | ||||
|  | ||||
| 	glEnable(GL_CULL_FACE); | ||||
| 	glCullFace(GL_BACK); | ||||
| } | ||||
|  | ||||
| void OpenGLWidget::resizeGL(int w, int h) | ||||
| @@ -70,7 +75,7 @@ void OpenGLWidget::resizeGL(int w, int h) | ||||
| 	//Set up the projection matrix | ||||
| 	glMatrixMode(GL_PROJECTION); | ||||
| 	glLoadIdentity(); | ||||
| 	float frustumSize = 32.0f; //Half the volume size | ||||
| 	float frustumSize = 16.0f; //Half the volume size | ||||
| 	float aspect = static_cast<float>(width()) / static_cast<float>(height()); | ||||
| 	glOrtho(frustumSize*aspect, -frustumSize*aspect, frustumSize, -frustumSize, 1.0, 1000); | ||||
| } | ||||
| @@ -86,7 +91,7 @@ void OpenGLWidget::paintGL() | ||||
| 	glTranslatef(0.0f,0.0f,-100.0f); //Centre volume and move back | ||||
| 	glRotatef(m_xRotation, 1.0f, 0.0f, 0.0f); | ||||
| 	glRotatef(m_yRotation, 0.0f, 1.0f, 0.0f); | ||||
| 	glTranslatef(-32.0f,-32.0f,-32.0f); //Centre volume and move back | ||||
| 	glTranslatef(-16.0f,-16.0f,-16.0f); //Centre volume and move back | ||||
|  | ||||
| 	//Bind the index buffer | ||||
| 	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer); | ||||
|   | ||||
| @@ -24,10 +24,13 @@ freely, subject to the following restrictions: | ||||
| #include "OpenGLWidget.h" | ||||
|  | ||||
| #include "MaterialDensityPair.h" | ||||
| #include "CubicSurfaceExtractor.h" | ||||
| #include "CubicSurfaceExtractorWithNormals.h" | ||||
| #include "SurfaceMesh.h" | ||||
| #include "Volume.h" | ||||
|  | ||||
| #include "MeshDecimator.h" | ||||
|  | ||||
| #include <QApplication> | ||||
|  | ||||
| //Use the PolyVox namespace | ||||
| @@ -36,7 +39,9 @@ using namespace PolyVox; | ||||
| void createSphereInVolume(Volume<MaterialDensityPair44>& volData, float fRadius) | ||||
| { | ||||
| 	//This vector hold the position of the center of the volume | ||||
| 	Vector3DFloat v3dVolCenter(volData.getWidth() / 2, volData.getHeight() / 2, volData.getDepth() / 2); | ||||
| 	//Vector3DFloat v3dVolCenter(volData.getWidth() / 2, volData.getHeight() / 2, volData.getDepth() / 2); | ||||
|  | ||||
| 	Vector3DFloat v3dVolCenter(16, 16, 16); | ||||
|  | ||||
| 	//This three-level for loop iterates over every voxel in the volume | ||||
| 	for (int z = 0; z < volData.getWidth(); z++) | ||||
| @@ -55,14 +60,16 @@ void createSphereInVolume(Volume<MaterialDensityPair44>& volData, float fRadius) | ||||
| 				{ | ||||
| 					//Our new density value | ||||
| 					uint8_t uDensity = MaterialDensityPair44::getMaxDensity(); | ||||
| 					uint8_t uMaterial = 3; | ||||
|  | ||||
| 					//Get the old voxel | ||||
| 					MaterialDensityPair44 voxel = volData.getVoxelAt(x,y,z); | ||||
|  | ||||
| 					//Modify the density | ||||
| 					voxel.setDensity(uDensity); | ||||
| 					voxel.setMaterial(uMaterial); | ||||
|  | ||||
| 					//Wrte the voxel value into the volume	 | ||||
| 					//Write the voxel value into the volume	 | ||||
| 					volData.setVoxelAt(x, y, z, voxel); | ||||
| 				} | ||||
| 			} | ||||
| @@ -70,6 +77,28 @@ void createSphereInVolume(Volume<MaterialDensityPair44>& volData, float fRadius) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void addNormals(const PolyVox::SurfaceMesh<PolyVox::PositionMaterial>& inputMesh,  PolyVox::SurfaceMesh<PolyVox::PositionMaterialNormal>& outputMesh) | ||||
| { | ||||
| 	outputMesh.m_Region = inputMesh.m_Region; | ||||
|  | ||||
| 	outputMesh.m_vecTriangleIndices.clear(); | ||||
| 	for(int ct = 0; ct < inputMesh.m_vecTriangleIndices.size(); ++ct) | ||||
| 	{ | ||||
| 		outputMesh.m_vecTriangleIndices.push_back(inputMesh.m_vecTriangleIndices[ct]); | ||||
| 	} | ||||
|  | ||||
| 	outputMesh.m_vecVertices.clear(); | ||||
| 	for(int ct = 0; ct < inputMesh.m_vecVertices.size(); ++ct) | ||||
| 	{ | ||||
| 		PositionMaterialNormal vertex; | ||||
| 		vertex.position = inputMesh.m_vecVertices[ct].position; | ||||
| 		vertex.material = inputMesh.m_vecVertices[ct].material; | ||||
| 		outputMesh.m_vecVertices.push_back(vertex); | ||||
| 	} | ||||
|  | ||||
| 	outputMesh.generateAveragedFaceNormals(true, true); | ||||
| } | ||||
|  | ||||
| int main(int argc, char *argv[]) | ||||
| { | ||||
| 	//Create and show the Qt OpenGL window | ||||
| @@ -78,16 +107,77 @@ int main(int argc, char *argv[]) | ||||
| 	openGLWidget.show(); | ||||
|  | ||||
| 	//Create an empty volume and then place a sphere in it | ||||
| 	Volume<MaterialDensityPair44> volData(64, 64, 64); | ||||
| 	createSphereInVolume(volData, 30); | ||||
| 	Volume<MaterialDensityPair44> volData(32, 32, 32, 32); | ||||
| 	//createSphereInVolume(volData, 30); | ||||
|  | ||||
| 	//This three-level for loop iterates over every voxel in the volume | ||||
| 	/*for (int z = 8; z < 24; z++) | ||||
| 	{ | ||||
| 		for (int y = 8; y < 24; y++) | ||||
| 		{ | ||||
| 			for (int x = 8; x < 16; x++) | ||||
| 			{				 | ||||
| 				//Our new density value | ||||
| 				uint8_t uDensity = MaterialDensityPair44::getMaxDensity(); | ||||
|  | ||||
| 				//Get the old voxel | ||||
| 				MaterialDensityPair44 voxel = volData.getVoxelAt(x,y,z); | ||||
|  | ||||
| 				//Modify the density | ||||
| 				voxel.setDensity(uDensity); | ||||
| 				voxel.setMaterial(3); | ||||
|  | ||||
| 				//Write the voxel value into the volume	 | ||||
| 				volData.setVoxelAt(x, y, z, voxel); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	for (int z = 8; z < 24; z++) | ||||
| 	{ | ||||
| 		for (int y = 8; y < 24; y++) | ||||
| 		{ | ||||
| 			for (int x = 16; x < 24; x++) | ||||
| 			{				 | ||||
| 				//Our new density value | ||||
| 				uint8_t uDensity = MaterialDensityPair44::getMaxDensity(); | ||||
|  | ||||
| 				//Get the old voxel | ||||
| 				MaterialDensityPair44 voxel = volData.getVoxelAt(x,y,z); | ||||
|  | ||||
| 				//Modify the density | ||||
| 				voxel.setDensity(uDensity); | ||||
| 				voxel.setMaterial(5); | ||||
|  | ||||
| 				//Write the voxel value into the volume	 | ||||
| 				volData.setVoxelAt(x, y, z, voxel); | ||||
| 			} | ||||
| 		} | ||||
| 	}*/ | ||||
|  | ||||
| 	createSphereInVolume(volData, 10); | ||||
|  | ||||
| 	//Extract the surface | ||||
| 	SurfaceMesh<PositionMaterialNormal> mesh; | ||||
| 	CubicSurfaceExtractorWithNormals<MaterialDensityPair44> surfaceExtractor(&volData, volData.getEnclosingRegion(), &mesh); | ||||
| 	Region region(Vector3DInt16(0,0,0), Vector3DInt16(20,20,20)); | ||||
| 	SurfaceMesh<PositionMaterial> mesh; | ||||
| 	//CubicSurfaceExtractor<MaterialDensityPair44> surfaceExtractor(&volData, volData.getEnclosingRegion(), &mesh); | ||||
| 	CubicSurfaceExtractor<MaterialDensityPair44> surfaceExtractor(&volData, region, &mesh); | ||||
| 	surfaceExtractor.execute(); | ||||
|  | ||||
| 	/*SurfaceMesh<PositionMaterialNormal> meshWithNormals; | ||||
| 	addNormals(mesh, meshWithNormals); | ||||
|  | ||||
| 	meshWithNormals.decimate(0.99);*/ | ||||
|  | ||||
| 	MeshDecimator<PositionMaterial> decimator(&mesh); | ||||
| 	decimator.execute(); | ||||
|  | ||||
| 	SurfaceMesh<PositionMaterialNormal> meshWithNormals; | ||||
| 	addNormals(mesh, meshWithNormals); | ||||
|  | ||||
| 	//Pass the surface to the OpenGL window | ||||
| 	openGLWidget.setSurfaceMeshToRender(mesh); | ||||
| 	openGLWidget.setSurfaceMeshToRender(meshWithNormals); | ||||
| 	//openGLWidget.setSurfaceMeshToRender(mesh); | ||||
|  | ||||
| 	//Run the message pump. | ||||
| 	return app.exec(); | ||||
|   | ||||
| @@ -28,6 +28,7 @@ freely, subject to the following restrictions: | ||||
| #include "GradientEstimators.h" | ||||
| #include "MaterialDensityPair.h" | ||||
| #include "SurfaceExtractor.h" | ||||
| #include "MeshDecimator.h" | ||||
|  | ||||
| #include "Mesh.h" | ||||
|  | ||||
| @@ -125,6 +126,9 @@ void OpenGLWidget::setVolume(PolyVox::Volume<MaterialDensityPair44>* volData) | ||||
|  | ||||
| 						//mesh->decimate(0.999f); | ||||
|  | ||||
| 						MeshDecimator<PositionMaterialNormal> decimator(mesh.get()); | ||||
| 						decimator.execute(); | ||||
|  | ||||
| 						//mesh->generateAveragedFaceNormals(true); | ||||
| 						//////////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
| @@ -183,7 +187,7 @@ void OpenGLWidget::initializeGL() | ||||
| 	glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); | ||||
| 	glEnable(GL_LIGHT0); | ||||
|  | ||||
| 	//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); | ||||
| 	glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); | ||||
|  | ||||
| 	glShadeModel(GL_SMOOTH); | ||||
| } | ||||
|   | ||||
| @@ -30,15 +30,9 @@ namespace PolyVox | ||||
| { | ||||
| 	struct InitialVertexMetadata | ||||
| 	{ | ||||
| 		list<uint32_t> trianglesUsingVertex; | ||||
| 		Vector3DFloat normal; | ||||
| 		bool isOnRegionEdge; | ||||
| 		bool isOnMaterialEdge; | ||||
| 	}; | ||||
|  | ||||
| 	struct CurrentVertexMetadata | ||||
| 	{ | ||||
| 		list<uint32_t> trianglesUsingVertex; | ||||
| 		std::bitset<VF_NO_OF_FLAGS> vertexFlags; | ||||
| 	}; | ||||
|  | ||||
| 	struct Triangle | ||||
| @@ -60,16 +54,14 @@ namespace PolyVox | ||||
| 	private: | ||||
|  | ||||
| 		void fillInitialVertexMetadata(std::vector<InitialVertexMetadata>& vecInitialVertexMetadata); | ||||
| 		void fillCurrentVertexMetadata(std::vector<CurrentVertexMetadata>& vecCurrentVertexMetadata); | ||||
|  | ||||
| 		void buildTriangles(void); | ||||
| 		void buildConnectivityData(void); | ||||
|  | ||||
| 		bool attemptEdgeCollapse(uint32_t uSrc, uint32_t uDest); | ||||
|  | ||||
| 		SurfaceMesh<VertexType>* m_pInputMesh; | ||||
| 		//SurfaceMesh<PositionMaterial>* pMeshOutput; | ||||
|  | ||||
| 		void countNoOfNeighboursUsingMaterial(void); | ||||
| 		uint32_t performDecimationPass(float fMinDotProductForCollapse); | ||||
| 		bool isSubset(std::bitset<VF_NO_OF_FLAGS> a, std::bitset<VF_NO_OF_FLAGS> b); | ||||
|  | ||||
| @@ -80,19 +72,14 @@ namespace PolyVox | ||||
| 		bool collapseChangesFaceNormals(uint32_t uSrc, uint32_t uDst, float fThreshold); | ||||
|  | ||||
| 		//Data structures used during decimation | ||||
| 		std::vector<uint8_t> m_vecNoOfNeighboursUsingMaterial; | ||||
|  | ||||
| 		std::vector<bool> vertexLocked; | ||||
| 		std::vector<uint32_t> vertexMapper; | ||||
|  | ||||
| 		//vector< list<uint32_t> > trianglesUsingVertexCurrently; | ||||
|  | ||||
| 		std::vector<int> vecOfTriCts; | ||||
| 		std::vector<Vector3DFloat> vecOfTriNormals; | ||||
| 		std::vector<Triangle> m_vecTriangles; | ||||
| 		std::vector< list<uint32_t> > trianglesUsingVertex; | ||||
|  | ||||
| 		std::vector<InitialVertexMetadata> m_vecInitialVertexMetadata; | ||||
| 		std::vector<CurrentVertexMetadata> m_vecCurrentVertexMetadata; | ||||
|  | ||||
| 		float fMinDotProductForCollapse; | ||||
| 	}; | ||||
|   | ||||
| @@ -34,11 +34,7 @@ namespace PolyVox | ||||
| 	template <typename VertexType> | ||||
| 	void MeshDecimator<VertexType>::execute() | ||||
| 	{ | ||||
| 		// We will need the information from this function to | ||||
| 		// determine when material boundary edges can collapse. | ||||
| 		countNoOfNeighboursUsingMaterial(); | ||||
|  | ||||
| 		buildTriangles(); | ||||
| 		buildConnectivityData(); | ||||
| 		fillInitialVertexMetadata(m_vecInitialVertexMetadata); | ||||
|  | ||||
| 		uint32_t noOfEdgesCollapsed; | ||||
| @@ -46,6 +42,12 @@ namespace PolyVox | ||||
| 		{ | ||||
| 			noOfEdgesCollapsed = performDecimationPass(fMinDotProductForCollapse); | ||||
| 			m_pInputMesh->removeDegenerateTris();	 | ||||
| 			if(noOfEdgesCollapsed > 0) | ||||
| 			{ | ||||
| 				//Build the connectivity data for the next pass. If this is slow, then look | ||||
| 				//at adjusting it (based on vertex mapper?) rather than bulding from scratch. | ||||
| 				buildConnectivityData(); | ||||
| 			} | ||||
| 			//m_pInputMesh->removeUnusedVertices(); | ||||
| 		}while(noOfEdgesCollapsed > 0); | ||||
|  | ||||
| @@ -58,36 +60,8 @@ namespace PolyVox | ||||
| 	} | ||||
|  | ||||
| 	template <typename VertexType> | ||||
| 	void MeshDecimator<VertexType>::buildTriangles(void) | ||||
| 	void MeshDecimator<VertexType>::buildConnectivityData(void) | ||||
| 	{ | ||||
| 		// Each triangle exists in this vector once. | ||||
| 		vecOfTriCts.clear(); | ||||
| 		vecOfTriCts.resize(m_pInputMesh->m_vecTriangleIndices.size() / 3); | ||||
| 		for(int triCt = 0; triCt < vecOfTriCts.size(); triCt++) | ||||
| 		{ | ||||
| 			vecOfTriCts[triCt] = triCt; | ||||
| 		} | ||||
|  | ||||
| 		vecOfTriNormals.clear(); | ||||
| 		vecOfTriNormals.resize(vecOfTriCts.size()); | ||||
| 		for(int ct = 0; ct < vecOfTriCts.size(); ct++) | ||||
| 		{ | ||||
| 			int triCt = vecOfTriCts[ct]; | ||||
| 			int v0 = m_pInputMesh->m_vecTriangleIndices[triCt * 3 + 0]; | ||||
| 			int v1 = m_pInputMesh->m_vecTriangleIndices[triCt * 3 + 1]; | ||||
| 			int v2 = m_pInputMesh->m_vecTriangleIndices[triCt * 3 + 2]; | ||||
|  | ||||
| 			//Handle degenerates? | ||||
|  | ||||
| 			Vector3DFloat v0v1 = m_pInputMesh->m_vecVertices[v1].position - m_pInputMesh->m_vecVertices[v0].position; | ||||
| 			Vector3DFloat v0v2 = m_pInputMesh->m_vecVertices[v2].position - m_pInputMesh->m_vecVertices[v0].position; | ||||
| 			Vector3DFloat normal = v0v1.cross(v0v2); | ||||
|  | ||||
| 			normal.normalise(); | ||||
|  | ||||
| 			vecOfTriNormals[ct] = normal; | ||||
| 		} | ||||
|  | ||||
| 		m_vecTriangles.clear(); | ||||
| 		m_vecTriangles.resize(m_pInputMesh->m_vecTriangleIndices.size() / 3); | ||||
| 		for(int triCt = 0; triCt < m_vecTriangles.size(); triCt++) | ||||
| @@ -107,25 +81,27 @@ namespace PolyVox | ||||
|  | ||||
| 			m_vecTriangles[triCt].normal = normal; | ||||
| 		} | ||||
|  | ||||
| 		trianglesUsingVertex.clear(); | ||||
| 		trianglesUsingVertex.resize(m_pInputMesh->m_vecVertices.size()); | ||||
| 		for(int ct = 0; ct < m_vecTriangles.size(); ct++) | ||||
| 		{ | ||||
| 			trianglesUsingVertex[m_vecTriangles[ct].v0].push_back(ct); | ||||
| 			trianglesUsingVertex[m_vecTriangles[ct].v1].push_back(ct); | ||||
| 			trianglesUsingVertex[m_vecTriangles[ct].v2].push_back(ct); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	template <typename VertexType> | ||||
| 	void MeshDecimator<VertexType>::fillInitialVertexMetadata(std::vector<InitialVertexMetadata>& vecVertexMetadata) | ||||
| 	void MeshDecimator<PositionMaterial>::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); | ||||
| 			vecVertexMetadata[ct].vertexFlags.reset(); | ||||
| 		} | ||||
|  | ||||
| 		for(int outerCt = 0; outerCt < m_pInputMesh->m_vecVertices.size()-1; outerCt++) | ||||
| @@ -140,13 +116,10 @@ namespace PolyVox | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		//noOfDifferentNormals.clear(); | ||||
| 		//noOfDifferentNormals.resize(m_pInputMesh->m_vecVertices.size()); | ||||
| 		//std::fill(vecVertexMetadata.noOfDifferentNormals.begin(), vecVertexMetadata.noOfDifferentNormals.end(), 0); | ||||
| 		for(int ct = 0; ct < m_pInputMesh->m_vecVertices.size(); ct++) | ||||
| 		{ | ||||
| 			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 = trianglesUsingVertex[ct].cbegin(); iter != trianglesUsingVertex[ct].cend(); iter++) | ||||
| 			{ | ||||
| 				sumOfNormals += m_vecTriangles[*iter].normal; | ||||
| 			} | ||||
| @@ -155,51 +128,77 @@ namespace PolyVox | ||||
| 			vecVertexMetadata[ct].normal.normalise(); | ||||
| 		} | ||||
|  | ||||
| 		Vector3DFloat offset = static_cast<Vector3DFloat>(m_pInputMesh->m_Region.getLowerCorner()); | ||||
| 		for(int ct = 0; ct < m_pInputMesh->m_vecVertices.size(); ct++) | ||||
| 		for(int ct = 0; ct < vecVertexMetadata.size(); ct++) | ||||
| 		{ | ||||
| 			bool bInside = m_pInputMesh->m_Region.containsPoint(m_pInputMesh->m_vecVertices[ct].getPosition() + offset); | ||||
| 			vecVertexMetadata[ct].isOnRegionEdge = !bInside; | ||||
| 			Region regTransformed = m_pInputMesh->m_Region; | ||||
| 			regTransformed.shift(regTransformed.getLowerCorner() * static_cast<int16_t>(-1)); | ||||
|  | ||||
| 			//Plus and minus X | ||||
| 			vecVertexMetadata[ct].vertexFlags.set(VF_ON_GEOMETRY_EDGE_NEG_X, m_pInputMesh->m_vecVertices[ct].getPosition().getX() < regTransformed.getLowerCorner().getX() + 0.001f); | ||||
| 			vecVertexMetadata[ct].vertexFlags.set(VF_ON_GEOMETRY_EDGE_POS_X, m_pInputMesh->m_vecVertices[ct].getPosition().getX() > regTransformed.getUpperCorner().getX() - 0.001f); | ||||
| 			//Plus and minus Y | ||||
| 			vecVertexMetadata[ct].vertexFlags.set(VF_ON_GEOMETRY_EDGE_NEG_Y, m_pInputMesh->m_vecVertices[ct].getPosition().getY() < regTransformed.getLowerCorner().getY() + 0.001f); | ||||
| 			vecVertexMetadata[ct].vertexFlags.set(VF_ON_GEOMETRY_EDGE_POS_Y, m_pInputMesh->m_vecVertices[ct].getPosition().getY() > regTransformed.getUpperCorner().getY() - 0.001f); | ||||
| 			//Plus and minus Z | ||||
| 			vecVertexMetadata[ct].vertexFlags.set(VF_ON_GEOMETRY_EDGE_NEG_Z, m_pInputMesh->m_vecVertices[ct].getPosition().getZ() < regTransformed.getLowerCorner().getZ() + 0.001f); | ||||
| 			vecVertexMetadata[ct].vertexFlags.set(VF_ON_GEOMETRY_EDGE_POS_Z, m_pInputMesh->m_vecVertices[ct].getPosition().getZ() > regTransformed.getUpperCorner().getZ() - 0.001f); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	template <typename VertexType> | ||||
| 	void MeshDecimator<VertexType>::fillCurrentVertexMetadata(std::vector<CurrentVertexMetadata>& vecVertexMetadata) | ||||
| 	void MeshDecimator<PositionMaterialNormal>::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].vertexFlags.reset(); | ||||
| 			vecVertexMetadata[ct].isOnMaterialEdge = false; | ||||
| 			vecVertexMetadata[ct].normal = m_pInputMesh->m_vecVertices[ct].normal; | ||||
| 		} | ||||
|  | ||||
| 		//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++) | ||||
| 		for(int ct = 0; ct < vecVertexMetadata.size(); ct++) | ||||
| 		{ | ||||
| 			int triangle = ct / 3; | ||||
| 			Region regTransformed = m_pInputMesh->m_Region; | ||||
| 			regTransformed.shift(regTransformed.getLowerCorner() * static_cast<int16_t>(-1)); | ||||
|  | ||||
| 			vecVertexMetadata[m_pInputMesh->m_vecTriangleIndices[ct]].trianglesUsingVertex.push_back(triangle); | ||||
| 			//Plus and minus X | ||||
| 			vecVertexMetadata[ct].vertexFlags.set(VF_ON_GEOMETRY_EDGE_NEG_X, m_pInputMesh->m_vecVertices[ct].getPosition().getX() < regTransformed.getLowerCorner().getX() + 0.001f); | ||||
| 			vecVertexMetadata[ct].vertexFlags.set(VF_ON_GEOMETRY_EDGE_POS_X, m_pInputMesh->m_vecVertices[ct].getPosition().getX() > regTransformed.getUpperCorner().getX() - 0.001f); | ||||
| 			//Plus and minus Y | ||||
| 			vecVertexMetadata[ct].vertexFlags.set(VF_ON_GEOMETRY_EDGE_NEG_Y, m_pInputMesh->m_vecVertices[ct].getPosition().getY() < regTransformed.getLowerCorner().getY() + 0.001f); | ||||
| 			vecVertexMetadata[ct].vertexFlags.set(VF_ON_GEOMETRY_EDGE_POS_Y, m_pInputMesh->m_vecVertices[ct].getPosition().getY() > regTransformed.getUpperCorner().getY() - 0.001f); | ||||
| 			//Plus and minus Z | ||||
| 			vecVertexMetadata[ct].vertexFlags.set(VF_ON_GEOMETRY_EDGE_NEG_Z, m_pInputMesh->m_vecVertices[ct].getPosition().getZ() < regTransformed.getLowerCorner().getZ() + 0.001f); | ||||
| 			vecVertexMetadata[ct].vertexFlags.set(VF_ON_GEOMETRY_EDGE_POS_Z, m_pInputMesh->m_vecVertices[ct].getPosition().getZ() > regTransformed.getUpperCorner().getZ() - 0.001f); | ||||
| 		} | ||||
|  | ||||
| 		//If all three vertices have the same material then we are not on a material edge. If any vertex has a different | ||||
| 		//material then all three vertices are on a material edge. E.g. If one vertex has material 'a' and the other two  | ||||
| 		//have material 'b', then the two 'b's are still on an edge (with 'a') even though they are the same as eachother. | ||||
| 		for(int ct = 0; ct < m_vecTriangles.size(); ct++) | ||||
| 		{ | ||||
| 			uint32_t v0 = m_vecTriangles[ct].v0; | ||||
| 			uint32_t v1 = m_vecTriangles[ct].v1; | ||||
| 			uint32_t v2 = m_vecTriangles[ct].v2; | ||||
|  | ||||
| 			bool allMatch =  | ||||
| 				(m_pInputMesh->m_vecVertices[v0].material == m_pInputMesh->m_vecVertices[v1].material) &&  | ||||
| 				(m_pInputMesh->m_vecVertices[v1].material == m_pInputMesh->m_vecVertices[v2].material); | ||||
|  | ||||
| 			if(!allMatch) | ||||
| 			{ | ||||
| 				vecVertexMetadata[v0].isOnMaterialEdge = true; | ||||
| 				vecVertexMetadata[v1].isOnMaterialEdge = true; | ||||
| 				vecVertexMetadata[v2].isOnMaterialEdge = true; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	template <typename VertexType> | ||||
| 	uint32_t MeshDecimator<VertexType>::performDecimationPass(float fMinDotProductForCollapse) | ||||
| 	{ | ||||
| 		// I'm using a vector of lists here, rather than a vector of sets, | ||||
| 		// because I don't believe that duplicates should occur. But this | ||||
| 		// might be worth checking if we have problems in the future. | ||||
| 		/*trianglesUsingVertexCurrently.clear(); | ||||
| 		trianglesUsingVertexCurrently.resize(m_pInputMesh->m_vecVertices.size()); | ||||
| 		for(int ct = 0; ct < m_pInputMesh->m_vecTriangleIndices.size(); ct++) | ||||
| 		{ | ||||
| 			int triangle = ct / 3; | ||||
|  | ||||
| 			trianglesUsingVertexCurrently[m_pInputMesh->m_vecTriangleIndices[ct]].push_back(triangle); | ||||
| 		}*/ | ||||
|  | ||||
| 		// Count how many edges we have collapsed | ||||
| 		uint32_t noOfEdgesCollapsed = 0; | ||||
|  | ||||
| @@ -223,13 +222,9 @@ namespace PolyVox | ||||
| 			vertexLocked[ct] = false; | ||||
| 		} | ||||
|  | ||||
| 		buildTriangles(); | ||||
| 		fillCurrentVertexMetadata(m_vecCurrentVertexMetadata); | ||||
|  | ||||
| 		//For each triange... | ||||
| 		//For each triangle... | ||||
| 		for(int ctIter = 0; ctIter < m_vecTriangles.size(); ctIter++) | ||||
| 		{ | ||||
|  | ||||
| 			if(attemptEdgeCollapse(m_vecTriangles[ctIter].v0, m_vecTriangles[ctIter].v1)) | ||||
| 			{ | ||||
| 				++noOfEdgesCollapsed; | ||||
| @@ -266,6 +261,12 @@ namespace PolyVox | ||||
| 	template <typename VertexType> | ||||
| 	bool MeshDecimator<VertexType>::attemptEdgeCollapse(uint32_t uSrc, uint32_t uDst) | ||||
| 	{ | ||||
| 		//A vertex will be locked if it has already been involved in a collapse this pass. | ||||
| 		if(vertexLocked[uSrc] || vertexLocked[uDst]) | ||||
| 		{ | ||||
| 			return false; | ||||
| 		} | ||||
|  | ||||
| 		if(canCollapseEdge(uSrc, uDst)) | ||||
| 		{ | ||||
| 			//Move v0 onto v1 | ||||
| @@ -280,51 +281,13 @@ namespace PolyVox | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| 	//This function looks at every vertex in the mesh and determines | ||||
| 	//how many of it's neighbours have the same material. | ||||
| 	template <typename VertexType> | ||||
| 	void MeshDecimator<VertexType>::countNoOfNeighboursUsingMaterial(void) | ||||
| 	{ | ||||
| 		//Find all the neighbouring vertices for each vertex | ||||
| 		std::vector< std::set<int> > neighbouringVertices(m_pInputMesh->m_vecVertices.size()); | ||||
| 		for(int triCt = 0; triCt < m_pInputMesh->m_vecTriangleIndices.size() / 3; triCt++) | ||||
| 		{ | ||||
| 			int v0 = m_pInputMesh->m_vecTriangleIndices[(triCt * 3 + 0)]; | ||||
| 			int v1 = m_pInputMesh->m_vecTriangleIndices[(triCt * 3 + 1)]; | ||||
| 			int v2 = m_pInputMesh->m_vecTriangleIndices[(triCt * 3 + 2)]; | ||||
|  | ||||
| 			neighbouringVertices[v0].insert(v1); | ||||
| 			neighbouringVertices[v0].insert(v2); | ||||
|  | ||||
| 			neighbouringVertices[v1].insert(v0); | ||||
| 			neighbouringVertices[v1].insert(v2); | ||||
|  | ||||
| 			neighbouringVertices[v2].insert(v0); | ||||
| 			neighbouringVertices[v2].insert(v1); | ||||
| 		} | ||||
|  | ||||
| 		//For each vertex, check how many neighbours have the same material | ||||
| 		m_vecNoOfNeighboursUsingMaterial.resize(m_pInputMesh->m_vecVertices.size()); | ||||
| 		for(int vertCt = 0; vertCt < m_pInputMesh->m_vecVertices.size(); vertCt++) | ||||
| 		{ | ||||
| 			m_vecNoOfNeighboursUsingMaterial[vertCt] = 0; | ||||
| 			for(std::set<int>::iterator iter = neighbouringVertices[vertCt].begin(); iter != neighbouringVertices[vertCt].end(); iter++) | ||||
| 			{ | ||||
| 				if(m_pInputMesh->m_vecVertices[vertCt].getMaterial() == m_pInputMesh->m_vecVertices[*iter].getMaterial()) | ||||
| 				{ | ||||
| 					m_vecNoOfNeighboursUsingMaterial[vertCt]++; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// Returns true if every bit which is set in 'a' is also set in 'b'. The reverse does not need to be true. | ||||
| 	template <typename VertexType> | ||||
| 	bool MeshDecimator<VertexType>::isSubset(std::bitset<VF_NO_OF_FLAGS> a, std::bitset<VF_NO_OF_FLAGS> b) | ||||
| 	{ | ||||
| 		bool result = true; | ||||
|  | ||||
| 		for(int ct = 1; ct < 7; ct++) //Start at '1' to skip material flag | ||||
| 		for(int ct = 0; ct < VF_NO_OF_FLAGS; ct++) | ||||
| 		{ | ||||
| 			if(a.test(ct)) | ||||
| 			{ | ||||
| @@ -342,90 +305,15 @@ namespace PolyVox | ||||
| 	//template <typename VertexType> | ||||
| 	bool MeshDecimator<PositionMaterialNormal>::canCollapseEdge(uint32_t uSrc, uint32_t uDst) | ||||
| 	{ | ||||
| 		//A vertex will be locked if it has already been involved in a collapse this pass. | ||||
| 		if(vertexLocked[uSrc] || vertexLocked[uDst]) | ||||
| 		{ | ||||
| 			return false; | ||||
| 		} | ||||
|  | ||||
| 		if(m_pInputMesh->m_vecVertices[uSrc].getMaterial() != m_pInputMesh->m_vecVertices[uDst].getMaterial()) | ||||
| 		{ | ||||
| 			return false; | ||||
| 		} | ||||
|  | ||||
| 		//For now, don't collapse vertices on material edges... | ||||
| 		if(m_pInputMesh->m_vecVertices[uSrc].isOnMaterialEdge() || m_pInputMesh->m_vecVertices[uDst].isOnMaterialEdge()) | ||||
| 		if(m_vecInitialVertexMetadata[uSrc].isOnMaterialEdge || m_vecInitialVertexMetadata[uDst].isOnMaterialEdge) | ||||
| 		{			 | ||||
| 			if(true) | ||||
| 			{ | ||||
| 				bool pass = false;						 | ||||
|  | ||||
| 				bool allMatch = false; | ||||
|  | ||||
| 				// On the original undecimated mesh a material boundary vertex on a straight edge will | ||||
| 				// have four neighbours with the same material. If it's on a corner it will have a | ||||
| 				// different number. We only collapse straight edges to avoid changingthe shape of the | ||||
| 				// material boundary. | ||||
| 				if(m_vecNoOfNeighboursUsingMaterial[uSrc] == m_vecNoOfNeighboursUsingMaterial[uDst]) | ||||
| 				{ | ||||
| 					if(m_vecNoOfNeighboursUsingMaterial[uSrc] == 4) | ||||
| 					{ | ||||
| 						allMatch = true; | ||||
| 					} | ||||
| 				} | ||||
|  | ||||
| 				bool movementValid = false; | ||||
| 				Vector3DFloat movement = m_pInputMesh->m_vecVertices[uDst].getPosition() - m_pInputMesh->m_vecVertices[uSrc].getPosition(); | ||||
| 				movement.normalise(); | ||||
| 				if(movement.dot(Vector3DFloat(0,0,1)) > 0.999) | ||||
| 				{ | ||||
| 					movementValid = true; | ||||
| 				} | ||||
|  | ||||
| 				if(movement.dot(Vector3DFloat(0,1,0)) > 0.999) | ||||
| 				{ | ||||
| 					movementValid = true; | ||||
| 				} | ||||
|  | ||||
| 				if(movement.dot(Vector3DFloat(1,0,0)) > 0.999) | ||||
| 				{ | ||||
| 					movementValid = true; | ||||
| 				} | ||||
|  | ||||
| 				if(movement.dot(Vector3DFloat(0,0,-1)) > 0.999) | ||||
| 				{ | ||||
| 					movementValid = true; | ||||
| 				} | ||||
|  | ||||
| 				if(movement.dot(Vector3DFloat(0,-1,0)) > 0.999) | ||||
| 				{ | ||||
| 					movementValid = true; | ||||
| 				} | ||||
|  | ||||
| 				if(movement.dot(Vector3DFloat(-1,0,0)) > 0.999) | ||||
| 				{ | ||||
| 					movementValid = true; | ||||
| 				} | ||||
|  | ||||
| 				if(movementValid && allMatch) | ||||
| 				{ | ||||
| 					pass = true; | ||||
| 				} | ||||
|  | ||||
| 				if(!pass) | ||||
| 				{ | ||||
| 					return false; | ||||
| 				} | ||||
| 			} | ||||
| 			else //Material collapses not allowed | ||||
| 			{ | ||||
| 				return false; | ||||
| 			} | ||||
| 			return false; | ||||
| 		} | ||||
|  | ||||
| 		// Vertices on the geometrical edge of surface meshes need special handling.  | ||||
| 		// We check for this by whether any of the edge flags are set. | ||||
| 		if(m_pInputMesh->m_vecVertices[uSrc].m_bFlags.any() || m_pInputMesh->m_vecVertices[uDst].m_bFlags.any()) | ||||
| 		if(m_vecInitialVertexMetadata[uSrc].vertexFlags.any() || m_vecInitialVertexMetadata[uDst].vertexFlags.any()) | ||||
| 		{ | ||||
| 			// Assume we can't collapse until we prove otherwise... | ||||
| 			bool bCollapseGeometryEdgePair = false; | ||||
| @@ -433,7 +321,7 @@ namespace PolyVox | ||||
| 			// We can collapse normal vertices onto edge vertices, and edge vertices | ||||
| 			// onto corner vertices, but not vice-versa. Hence we check whether all | ||||
| 			// the edge flags in the source vertex are also set in the destination vertex. | ||||
| 			if(isSubset(m_pInputMesh->m_vecVertices[uSrc].m_bFlags, m_pInputMesh->m_vecVertices[uDst].m_bFlags)) | ||||
| 			if(isSubset(m_vecInitialVertexMetadata[uSrc].vertexFlags, m_vecInitialVertexMetadata[uDst].vertexFlags)) | ||||
| 			{ | ||||
| 				// In general adjacent regions surface meshes may collapse differently | ||||
| 				// and this can cause cracks. We solve this by only allowing the collapse | ||||
| @@ -468,38 +356,26 @@ namespace PolyVox | ||||
| 		return true; | ||||
| 	} | ||||
|  | ||||
| 	//template <typename VertexType> | ||||
| 	bool MeshDecimator<PositionMaterial>::canCollapseEdge(uint32_t uSrc, uint32_t uDst) | ||||
| 	{ | ||||
| 		//A vertex will be locked if it has already been involved in a collapse this pass. | ||||
| 		if(vertexLocked[uSrc] || vertexLocked[uDst]) | ||||
| 		{ | ||||
| 			return false; | ||||
| 		}		 | ||||
| 		bool bCanCollapse = true; | ||||
|  | ||||
| 		if(m_vecInitialVertexMetadata[uSrc].isOnMaterialEdge) | ||||
| 		{ | ||||
| 			if(m_vecInitialVertexMetadata[uSrc].isOnRegionEdge) | ||||
| 			{ | ||||
| 				assert(false); //Shouldn't be on both edge types. | ||||
| 				return false; | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				return canCollapseMaterialEdge(uSrc, uDst); | ||||
| 			} | ||||
| 			bCanCollapse &= canCollapseMaterialEdge(uSrc, uDst); | ||||
| 		} | ||||
| 		else | ||||
|  | ||||
| 		if(m_vecInitialVertexMetadata[uSrc].vertexFlags.any()) | ||||
| 		{ | ||||
| 			if(m_vecInitialVertexMetadata[uSrc].isOnRegionEdge) | ||||
| 			{ | ||||
| 				return canCollapseRegionEdge(uSrc, uDst); | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				return canCollapseNormalEdge(uSrc, uDst); | ||||
| 			} | ||||
| 			bCanCollapse &= canCollapseRegionEdge(uSrc, uDst); | ||||
| 		} | ||||
|  | ||||
| 		if(bCanCollapse) //Only bother with this is the earlier tests passed. | ||||
| 		{ | ||||
| 			bCanCollapse &= canCollapseNormalEdge(uSrc, uDst); | ||||
| 		} | ||||
|  | ||||
| 		return bCanCollapse; | ||||
| 	} | ||||
|  | ||||
| 	template <typename VertexType> | ||||
| @@ -511,42 +387,17 @@ namespace PolyVox | ||||
| 	template <typename VertexType> | ||||
| 	bool MeshDecimator<VertexType>::canCollapseRegionEdge(uint32_t uSrc, uint32_t uDst) | ||||
| 	{		 | ||||
| 		return false; | ||||
|  | ||||
| 		if(m_vecInitialVertexMetadata[uDst].isOnRegionEdge) | ||||
| 		if(isSubset(m_vecInitialVertexMetadata[uSrc].vertexFlags, m_vecInitialVertexMetadata[uDst].vertexFlags) == false) | ||||
| 		{ | ||||
|  | ||||
| 			int matchingCoordinates = 0; | ||||
| 			if(abs(m_pInputMesh->m_vecVertices[uSrc].getPosition().getX() - m_pInputMesh->m_vecVertices[uDst].getPosition().getX()) < 0.001) | ||||
| 			{ | ||||
| 				matchingCoordinates++; | ||||
| 			} | ||||
| 			if(abs(m_pInputMesh->m_vecVertices[uSrc].getPosition().getY() - m_pInputMesh->m_vecVertices[uDst].getPosition().getY()) < 0.001) | ||||
| 			{ | ||||
| 				matchingCoordinates++; | ||||
| 			} | ||||
| 			if(abs(m_pInputMesh->m_vecVertices[uSrc].getPosition().getZ() - m_pInputMesh->m_vecVertices[uDst].getPosition().getZ()) < 0.001) | ||||
| 			{ | ||||
| 				matchingCoordinates++; | ||||
| 			} | ||||
| 			if(matchingCoordinates != 2) | ||||
| 			{ | ||||
| 				return false; | ||||
| 			} | ||||
|  | ||||
| 			if(m_vecInitialVertexMetadata[uSrc].trianglesUsingVertex.size() != m_vecInitialVertexMetadata[uDst].trianglesUsingVertex.size()) //Corner | ||||
| 			{ | ||||
| 				return false; | ||||
| 			} | ||||
|  | ||||
| 			if(m_vecInitialVertexMetadata[uSrc].normal.dot(m_vecInitialVertexMetadata[uDst].normal) < 0.999f) | ||||
| 			{ | ||||
| 				return false; | ||||
| 			} | ||||
|  | ||||
| 			return !collapseChangesFaceNormals(uSrc, uDst, 0.999f); | ||||
| 			return false; | ||||
| 		} | ||||
| 		return false; | ||||
|  | ||||
| 		if(m_vecInitialVertexMetadata[uSrc].normal.dot(m_vecInitialVertexMetadata[uDst].normal) < 0.999f) | ||||
| 		{ | ||||
| 			return false; | ||||
| 		} | ||||
|  | ||||
| 		return true; | ||||
| 	} | ||||
|  | ||||
| 	template <typename VertexType> | ||||
| @@ -559,12 +410,7 @@ namespace PolyVox | ||||
| 	bool MeshDecimator<VertexType>::collapseChangesFaceNormals(uint32_t uSrc, uint32_t uDst, float fThreshold) | ||||
| 	{ | ||||
| 		bool faceFlipped = false; | ||||
| 		//list<uint32_t> triangles = trianglesUsingVertexCurrently[v0]; | ||||
| 		list<uint32_t> triangles = m_vecCurrentVertexMetadata[uSrc].trianglesUsingVertex; | ||||
| 		/*set<uint32_t> triangles; | ||||
| 		std::set_union(trianglesUsingVertex[v0].begin(), trianglesUsingVertex[v0].end(), | ||||
| 			trianglesUsingVertex[v1].begin(), trianglesUsingVertex[v1].end(), | ||||
| 			std::inserter(triangles, triangles.begin()));*/ | ||||
| 		list<uint32_t> triangles = trianglesUsingVertex[uSrc]; | ||||
|  | ||||
| 		for(list<uint32_t>::iterator triIter = triangles.begin(); triIter != triangles.end(); triIter++) | ||||
| 		{ | ||||
|   | ||||
| @@ -90,12 +90,6 @@ namespace PolyVox | ||||
| 		//which cover a whole triangle are counted. Materials which only | ||||
| 		//exist on a material boundary do not count. | ||||
| 		std::set<uint8_t> m_mapUsedMaterials; | ||||
|  | ||||
| 	private: | ||||
| 		void countNoOfNeighboursUsingMaterial(void); | ||||
|  | ||||
| 		//Data structures used during decimation | ||||
| 		std::vector<uint8_t> m_vecNoOfNeighboursUsingMaterial; | ||||
| 	};	 | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -332,44 +332,6 @@ namespace PolyVox | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	//This function looks at every vertex in the mesh and determines | ||||
| 	//how many of it's neighbours have the same material. | ||||
| 	template <typename VertexType> | ||||
| 	void SurfaceMesh<VertexType>::countNoOfNeighboursUsingMaterial(void) | ||||
| 	{ | ||||
| 		//Find all the neighbouring vertices for each vertex | ||||
| 		std::vector< std::set<int> > neighbouringVertices(m_vecVertices.size()); | ||||
| 		for(int triCt = 0; triCt < m_vecTriangleIndices.size() / 3; triCt++) | ||||
| 		{ | ||||
| 			int v0 = m_vecTriangleIndices[(triCt * 3 + 0)]; | ||||
| 			int v1 = m_vecTriangleIndices[(triCt * 3 + 1)]; | ||||
| 			int v2 = m_vecTriangleIndices[(triCt * 3 + 2)]; | ||||
|  | ||||
| 			neighbouringVertices[v0].insert(v1); | ||||
| 			neighbouringVertices[v0].insert(v2); | ||||
|  | ||||
| 			neighbouringVertices[v1].insert(v0); | ||||
| 			neighbouringVertices[v1].insert(v2); | ||||
|  | ||||
| 			neighbouringVertices[v2].insert(v0); | ||||
| 			neighbouringVertices[v2].insert(v1); | ||||
| 		} | ||||
|  | ||||
| 		//For each vertex, check how many neighbours have the same material | ||||
| 		m_vecNoOfNeighboursUsingMaterial.resize(m_vecVertices.size()); | ||||
| 		for(int vertCt = 0; vertCt < m_vecVertices.size(); vertCt++) | ||||
| 		{ | ||||
| 			m_vecNoOfNeighboursUsingMaterial[vertCt] = 0; | ||||
| 			for(std::set<int>::iterator iter = neighbouringVertices[vertCt].begin(); iter != neighbouringVertices[vertCt].end(); iter++) | ||||
| 			{ | ||||
| 				if(m_vecVertices[vertCt].getMaterial() == m_vecVertices[*iter].getMaterial()) | ||||
| 				{ | ||||
| 					m_vecNoOfNeighboursUsingMaterial[vertCt]++; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	template <typename VertexType> | ||||
| 	polyvox_shared_ptr< SurfaceMesh<VertexType> > SurfaceMesh<VertexType>::extractSubset(std::set<uint8_t> setMaterials) | ||||
| 	{ | ||||
|   | ||||
		Reference in New Issue
	
	Block a user