Templatised SurfaceMesh class on vertex type.

Replaced 'SurfaceVertex' with PositionMaterial and PositionMaterialNormal classes.
Different surface extractors can now work with different vertex types.
This commit is contained in:
David Williams
2010-10-17 21:13:46 +00:00
parent 56ec37f5e2
commit 9e1de4ba72
28 changed files with 460 additions and 176 deletions

View File

@ -35,7 +35,7 @@ namespace PolyVox
class CubicSurfaceExtractor
{
public:
CubicSurfaceExtractor(Volume<VoxelType>* volData, Region region, SurfaceMesh* result);
CubicSurfaceExtractor(Volume<VoxelType>* volData, Region region, SurfaceMesh<PositionMaterial>* result);
void execute();
@ -45,7 +45,7 @@ namespace PolyVox
VolumeSampler<VoxelType> m_sampVolume;
//The surface patch we are currently filling.
SurfaceMesh* m_meshCurrent;
SurfaceMesh<PositionMaterial>* m_meshCurrent;
//Information about the region we are currently processing
Region m_regSizeInVoxels;

View File

@ -30,7 +30,7 @@ freely, subject to the following restrictions:
namespace PolyVox
{
template <typename VoxelType>
CubicSurfaceExtractor<VoxelType>::CubicSurfaceExtractor(Volume<VoxelType>* volData, Region region, SurfaceMesh* result)
CubicSurfaceExtractor<VoxelType>::CubicSurfaceExtractor(Volume<VoxelType>* volData, Region region, SurfaceMesh<PositionMaterial>* result)
:m_volData(volData)
,m_sampVolume(volData)
,m_regSizeInVoxels(region)
@ -63,25 +63,25 @@ namespace PolyVox
{
int material = m_volData->getVoxelAt(x,y,z).getMaterial();
uint32_t v0 = m_meshCurrent->addVertex(SurfaceVertex(Vector3DFloat(regX + 0.5f, regY - 0.5f, regZ - 0.5f), Vector3DFloat(1.0f, 0.0f, 0.0f), material));
uint32_t v1 = m_meshCurrent->addVertex(SurfaceVertex(Vector3DFloat(regX + 0.5f, regY - 0.5f, regZ + 0.5f), Vector3DFloat(1.0f, 0.0f, 0.0f), material));
uint32_t v2 = m_meshCurrent->addVertex(SurfaceVertex(Vector3DFloat(regX + 0.5f, regY + 0.5f, regZ - 0.5f), Vector3DFloat(1.0f, 0.0f, 0.0f), material));
uint32_t v3 = m_meshCurrent->addVertex(SurfaceVertex(Vector3DFloat(regX + 0.5f, regY + 0.5f, regZ + 0.5f), Vector3DFloat(1.0f, 0.0f, 0.0f), material));
uint32_t v0 = m_meshCurrent->addVertex(PositionMaterial(Vector3DFloat(regX + 0.5f, regY - 0.5f, regZ - 0.5f), material));
uint32_t v1 = m_meshCurrent->addVertex(PositionMaterial(Vector3DFloat(regX + 0.5f, regY - 0.5f, regZ + 0.5f), material));
uint32_t v2 = m_meshCurrent->addVertex(PositionMaterial(Vector3DFloat(regX + 0.5f, regY + 0.5f, regZ - 0.5f), material));
uint32_t v3 = m_meshCurrent->addVertex(PositionMaterial(Vector3DFloat(regX + 0.5f, regY + 0.5f, regZ + 0.5f), material));
m_meshCurrent->addTriangle(v0,v2,v1);
m_meshCurrent->addTriangle(v1,v2,v3);
m_meshCurrent->addTriangleCubic(v0,v2,v1);
m_meshCurrent->addTriangleCubic(v1,v2,v3);
}
if(currentVoxel < plusXVoxel)
{
int material = m_volData->getVoxelAt(x+1,y,z).getMaterial();
uint32_t v0 = m_meshCurrent->addVertex(SurfaceVertex(Vector3DFloat(regX + 0.5f, regY - 0.5f, regZ - 0.5f), Vector3DFloat(-1.0f, 0.0f, 0.0f), material));
uint32_t v1 = m_meshCurrent->addVertex(SurfaceVertex(Vector3DFloat(regX + 0.5f, regY - 0.5f, regZ + 0.5f), Vector3DFloat(-1.0f, 0.0f, 0.0f), material));
uint32_t v2 = m_meshCurrent->addVertex(SurfaceVertex(Vector3DFloat(regX + 0.5f, regY + 0.5f, regZ - 0.5f), Vector3DFloat(-1.0f, 0.0f, 0.0f), material));
uint32_t v3 = m_meshCurrent->addVertex(SurfaceVertex(Vector3DFloat(regX + 0.5f, regY + 0.5f, regZ + 0.5f), Vector3DFloat(-1.0f, 0.0f, 0.0f), material));
uint32_t v0 = m_meshCurrent->addVertex(PositionMaterial(Vector3DFloat(regX + 0.5f, regY - 0.5f, regZ - 0.5f), material));
uint32_t v1 = m_meshCurrent->addVertex(PositionMaterial(Vector3DFloat(regX + 0.5f, regY - 0.5f, regZ + 0.5f), material));
uint32_t v2 = m_meshCurrent->addVertex(PositionMaterial(Vector3DFloat(regX + 0.5f, regY + 0.5f, regZ - 0.5f), material));
uint32_t v3 = m_meshCurrent->addVertex(PositionMaterial(Vector3DFloat(regX + 0.5f, regY + 0.5f, regZ + 0.5f), material));
m_meshCurrent->addTriangle(v0,v1,v2);
m_meshCurrent->addTriangle(v1,v3,v2);
m_meshCurrent->addTriangleCubic(v0,v1,v2);
m_meshCurrent->addTriangleCubic(v1,v3,v2);
}
int plusYVoxel = m_volData->getVoxelAt(x,y+1,z).getDensity() >= VoxelType::getThreshold();
@ -89,25 +89,25 @@ namespace PolyVox
{
int material = m_volData->getVoxelAt(x,y,z).getMaterial();
uint32_t v0 = m_meshCurrent->addVertex(SurfaceVertex(Vector3DFloat(regX - 0.5f, regY + 0.5f, regZ - 0.5f), Vector3DFloat(0.0f, 1.0f, 0.0f), material));
uint32_t v1 = m_meshCurrent->addVertex(SurfaceVertex(Vector3DFloat(regX - 0.5f, regY + 0.5f, regZ + 0.5f), Vector3DFloat(0.0f, 1.0f, 0.0f), material));
uint32_t v2 = m_meshCurrent->addVertex(SurfaceVertex(Vector3DFloat(regX + 0.5f, regY + 0.5f, regZ - 0.5f), Vector3DFloat(0.0f, 1.0f, 0.0f), material));
uint32_t v3 = m_meshCurrent->addVertex(SurfaceVertex(Vector3DFloat(regX + 0.5f, regY + 0.5f, regZ + 0.5f), Vector3DFloat(0.0f, 1.0f, 0.0f), material));
uint32_t v0 = m_meshCurrent->addVertex(PositionMaterial(Vector3DFloat(regX - 0.5f, regY + 0.5f, regZ - 0.5f), material));
uint32_t v1 = m_meshCurrent->addVertex(PositionMaterial(Vector3DFloat(regX - 0.5f, regY + 0.5f, regZ + 0.5f), material));
uint32_t v2 = m_meshCurrent->addVertex(PositionMaterial(Vector3DFloat(regX + 0.5f, regY + 0.5f, regZ - 0.5f), material));
uint32_t v3 = m_meshCurrent->addVertex(PositionMaterial(Vector3DFloat(regX + 0.5f, regY + 0.5f, regZ + 0.5f), material));
m_meshCurrent->addTriangle(v0,v1,v2);
m_meshCurrent->addTriangle(v1,v3,v2);
m_meshCurrent->addTriangleCubic(v0,v1,v2);
m_meshCurrent->addTriangleCubic(v1,v3,v2);
}
if(currentVoxel < plusYVoxel)
{
int material = m_volData->getVoxelAt(x,y+1,z).getMaterial();
uint32_t v0 = m_meshCurrent->addVertex(SurfaceVertex(Vector3DFloat(regX - 0.5f, regY + 0.5f, regZ - 0.5f), Vector3DFloat(0.0f, -1.0f, 0.0f), material));
uint32_t v1 = m_meshCurrent->addVertex(SurfaceVertex(Vector3DFloat(regX - 0.5f, regY + 0.5f, regZ + 0.5f), Vector3DFloat(0.0f, -1.0f, 0.0f), material));
uint32_t v2 = m_meshCurrent->addVertex(SurfaceVertex(Vector3DFloat(regX + 0.5f, regY + 0.5f, regZ - 0.5f), Vector3DFloat(0.0f, -1.0f, 0.0f), material));
uint32_t v3 = m_meshCurrent->addVertex(SurfaceVertex(Vector3DFloat(regX + 0.5f, regY + 0.5f, regZ + 0.5f), Vector3DFloat(0.0f, -1.0f, 0.0f), material));
uint32_t v0 = m_meshCurrent->addVertex(PositionMaterial(Vector3DFloat(regX - 0.5f, regY + 0.5f, regZ - 0.5f), material));
uint32_t v1 = m_meshCurrent->addVertex(PositionMaterial(Vector3DFloat(regX - 0.5f, regY + 0.5f, regZ + 0.5f), material));
uint32_t v2 = m_meshCurrent->addVertex(PositionMaterial(Vector3DFloat(regX + 0.5f, regY + 0.5f, regZ - 0.5f), material));
uint32_t v3 = m_meshCurrent->addVertex(PositionMaterial(Vector3DFloat(regX + 0.5f, regY + 0.5f, regZ + 0.5f), material));
m_meshCurrent->addTriangle(v0,v2,v1);
m_meshCurrent->addTriangle(v1,v2,v3);
m_meshCurrent->addTriangleCubic(v0,v2,v1);
m_meshCurrent->addTriangleCubic(v1,v2,v3);
}
int plusZVoxel = m_volData->getVoxelAt(x,y,z+1).getDensity() >= VoxelType::getThreshold();
@ -115,25 +115,25 @@ namespace PolyVox
{
int material = m_volData->getVoxelAt(x,y,z).getMaterial();
uint32_t v0 = m_meshCurrent->addVertex(SurfaceVertex(Vector3DFloat(regX - 0.5f, regY - 0.5f, regZ + 0.5f), Vector3DFloat(0.0f, 0.0f, 1.0f), material));
uint32_t v1 = m_meshCurrent->addVertex(SurfaceVertex(Vector3DFloat(regX - 0.5f, regY + 0.5f, regZ + 0.5f), Vector3DFloat(0.0f, 0.0f, 1.0f), material));
uint32_t v2 = m_meshCurrent->addVertex(SurfaceVertex(Vector3DFloat(regX + 0.5f, regY - 0.5f, regZ + 0.5f), Vector3DFloat(0.0f, 0.0f, 1.0f), material));
uint32_t v3 = m_meshCurrent->addVertex(SurfaceVertex(Vector3DFloat(regX + 0.5f, regY + 0.5f, regZ + 0.5f), Vector3DFloat(0.0f, 0.0f, 1.0f), material));
uint32_t v0 = m_meshCurrent->addVertex(PositionMaterial(Vector3DFloat(regX - 0.5f, regY - 0.5f, regZ + 0.5f), material));
uint32_t v1 = m_meshCurrent->addVertex(PositionMaterial(Vector3DFloat(regX - 0.5f, regY + 0.5f, regZ + 0.5f), material));
uint32_t v2 = m_meshCurrent->addVertex(PositionMaterial(Vector3DFloat(regX + 0.5f, regY - 0.5f, regZ + 0.5f), material));
uint32_t v3 = m_meshCurrent->addVertex(PositionMaterial(Vector3DFloat(regX + 0.5f, regY + 0.5f, regZ + 0.5f), material));
m_meshCurrent->addTriangle(v0,v2,v1);
m_meshCurrent->addTriangle(v1,v2,v3);
m_meshCurrent->addTriangleCubic(v0,v2,v1);
m_meshCurrent->addTriangleCubic(v1,v2,v3);
}
if(currentVoxel < plusZVoxel)
{
int material = m_volData->getVoxelAt(x,y,z+1).getMaterial();
uint32_t v0 = m_meshCurrent->addVertex(SurfaceVertex(Vector3DFloat(regX - 0.5f, regY - 0.5f, regZ + 0.5f), Vector3DFloat(0.0f, 0.0f, -1.0f), material));
uint32_t v1 = m_meshCurrent->addVertex(SurfaceVertex(Vector3DFloat(regX - 0.5f, regY + 0.5f, regZ + 0.5f), Vector3DFloat(0.0f, 0.0f, -1.0f), material));
uint32_t v2 = m_meshCurrent->addVertex(SurfaceVertex(Vector3DFloat(regX + 0.5f, regY - 0.5f, regZ + 0.5f), Vector3DFloat(0.0f, 0.0f, -1.0f), material));
uint32_t v3 = m_meshCurrent->addVertex(SurfaceVertex(Vector3DFloat(regX + 0.5f, regY + 0.5f, regZ + 0.5f), Vector3DFloat(0.0f, 0.0f, -1.0f), material));
uint32_t v0 = m_meshCurrent->addVertex(PositionMaterial(Vector3DFloat(regX - 0.5f, regY - 0.5f, regZ + 0.5f), material));
uint32_t v1 = m_meshCurrent->addVertex(PositionMaterial(Vector3DFloat(regX - 0.5f, regY + 0.5f, regZ + 0.5f), material));
uint32_t v2 = m_meshCurrent->addVertex(PositionMaterial(Vector3DFloat(regX + 0.5f, regY - 0.5f, regZ + 0.5f), material));
uint32_t v3 = m_meshCurrent->addVertex(PositionMaterial(Vector3DFloat(regX + 0.5f, regY + 0.5f, regZ + 0.5f), material));
m_meshCurrent->addTriangle(v0,v1,v2);
m_meshCurrent->addTriangle(v1,v3,v2);
m_meshCurrent->addTriangleCubic(v0,v1,v2);
m_meshCurrent->addTriangleCubic(v1,v3,v2);
}
}
}

View File

@ -0,0 +1,58 @@
/*******************************************************************************
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.
*******************************************************************************/
#ifndef __PolyVox_CubicSurfaceExtractorWithNormals_H__
#define __PolyVox_CubicSurfaceExtractorWithNormals_H__
#include "PolyVoxForwardDeclarations.h"
#include "VolumeSampler.h"
#include "PolyVoxImpl/TypeDef.h"
namespace PolyVox
{
template <typename VoxelType>
class CubicSurfaceExtractorWithNormals
{
public:
CubicSurfaceExtractorWithNormals(Volume<VoxelType>* volData, Region region, SurfaceMesh<PositionMaterialNormal>* result);
void execute();
private:
//The volume data and a sampler to access it.
Volume<VoxelType>* m_volData;
VolumeSampler<VoxelType> m_sampVolume;
//The surface patch we are currently filling.
SurfaceMesh<PositionMaterialNormal>* m_meshCurrent;
//Information about the region we are currently processing
Region m_regSizeInVoxels;
Region m_regSizeInCells;
};
}
#include "CubicSurfaceExtractorWithNormals.inl"
#endif

View File

@ -0,0 +1,150 @@
/*******************************************************************************
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.
*******************************************************************************/
#include "Array.h"
#include "MaterialDensityPair.h"
#include "SurfaceMesh.h"
#include "PolyVoxImpl/MarchingCubesTables.h"
#include "SurfaceVertex.h"
namespace PolyVox
{
template <typename VoxelType>
CubicSurfaceExtractorWithNormals<VoxelType>::CubicSurfaceExtractorWithNormals(Volume<VoxelType>* volData, Region region, SurfaceMesh<PositionMaterialNormal>* result)
:m_volData(volData)
,m_sampVolume(volData)
,m_regSizeInVoxels(region)
,m_meshCurrent(result)
{
m_regSizeInVoxels.cropTo(m_volData->getEnclosingRegion());
m_regSizeInCells = m_regSizeInVoxels;
m_regSizeInCells.setUpperCorner(m_regSizeInCells.getUpperCorner() - Vector3DInt16(1,1,1));
m_meshCurrent->clear();
}
template <typename VoxelType>
void CubicSurfaceExtractorWithNormals<VoxelType>::execute()
{
for(uint16_t z = m_regSizeInVoxels.getLowerCorner().getZ(); z < m_regSizeInVoxels.getUpperCorner().getZ(); z++)
{
for(uint16_t y = m_regSizeInVoxels.getLowerCorner().getY(); y < m_regSizeInVoxels.getUpperCorner().getY(); y++)
{
for(uint16_t x = m_regSizeInVoxels.getLowerCorner().getX(); x < m_regSizeInVoxels.getUpperCorner().getX(); x++)
{
uint16_t regX = x - m_regSizeInVoxels.getLowerCorner().getX();
uint16_t regY = y - m_regSizeInVoxels.getLowerCorner().getY();
uint16_t regZ = z - m_regSizeInVoxels.getLowerCorner().getZ();
int currentVoxel = m_volData->getVoxelAt(x,y,z).getDensity() >= VoxelType::getThreshold();
int plusXVoxel = m_volData->getVoxelAt(x+1,y,z).getDensity() >= VoxelType::getThreshold();
if(currentVoxel > plusXVoxel)
{
int material = m_volData->getVoxelAt(x,y,z).getMaterial();
uint32_t v0 = m_meshCurrent->addVertex(PositionMaterialNormal(Vector3DFloat(regX + 0.5f, regY - 0.5f, regZ - 0.5f), Vector3DFloat(1.0f, 0.0f, 0.0f), material));
uint32_t v1 = m_meshCurrent->addVertex(PositionMaterialNormal(Vector3DFloat(regX + 0.5f, regY - 0.5f, regZ + 0.5f), Vector3DFloat(1.0f, 0.0f, 0.0f), material));
uint32_t v2 = m_meshCurrent->addVertex(PositionMaterialNormal(Vector3DFloat(regX + 0.5f, regY + 0.5f, regZ - 0.5f), Vector3DFloat(1.0f, 0.0f, 0.0f), material));
uint32_t v3 = m_meshCurrent->addVertex(PositionMaterialNormal(Vector3DFloat(regX + 0.5f, regY + 0.5f, regZ + 0.5f), Vector3DFloat(1.0f, 0.0f, 0.0f), material));
m_meshCurrent->addTriangleCubic(v0,v2,v1);
m_meshCurrent->addTriangleCubic(v1,v2,v3);
}
if(currentVoxel < plusXVoxel)
{
int material = m_volData->getVoxelAt(x+1,y,z).getMaterial();
uint32_t v0 = m_meshCurrent->addVertex(PositionMaterialNormal(Vector3DFloat(regX + 0.5f, regY - 0.5f, regZ - 0.5f), Vector3DFloat(-1.0f, 0.0f, 0.0f), material));
uint32_t v1 = m_meshCurrent->addVertex(PositionMaterialNormal(Vector3DFloat(regX + 0.5f, regY - 0.5f, regZ + 0.5f), Vector3DFloat(-1.0f, 0.0f, 0.0f), material));
uint32_t v2 = m_meshCurrent->addVertex(PositionMaterialNormal(Vector3DFloat(regX + 0.5f, regY + 0.5f, regZ - 0.5f), Vector3DFloat(-1.0f, 0.0f, 0.0f), material));
uint32_t v3 = m_meshCurrent->addVertex(PositionMaterialNormal(Vector3DFloat(regX + 0.5f, regY + 0.5f, regZ + 0.5f), Vector3DFloat(-1.0f, 0.0f, 0.0f), material));
m_meshCurrent->addTriangleCubic(v0,v1,v2);
m_meshCurrent->addTriangleCubic(v1,v3,v2);
}
int plusYVoxel = m_volData->getVoxelAt(x,y+1,z).getDensity() >= VoxelType::getThreshold();
if(currentVoxel > plusYVoxel)
{
int material = m_volData->getVoxelAt(x,y,z).getMaterial();
uint32_t v0 = m_meshCurrent->addVertex(PositionMaterialNormal(Vector3DFloat(regX - 0.5f, regY + 0.5f, regZ - 0.5f), Vector3DFloat(0.0f, 1.0f, 0.0f), material));
uint32_t v1 = m_meshCurrent->addVertex(PositionMaterialNormal(Vector3DFloat(regX - 0.5f, regY + 0.5f, regZ + 0.5f), Vector3DFloat(0.0f, 1.0f, 0.0f), material));
uint32_t v2 = m_meshCurrent->addVertex(PositionMaterialNormal(Vector3DFloat(regX + 0.5f, regY + 0.5f, regZ - 0.5f), Vector3DFloat(0.0f, 1.0f, 0.0f), material));
uint32_t v3 = m_meshCurrent->addVertex(PositionMaterialNormal(Vector3DFloat(regX + 0.5f, regY + 0.5f, regZ + 0.5f), Vector3DFloat(0.0f, 1.0f, 0.0f), material));
m_meshCurrent->addTriangleCubic(v0,v1,v2);
m_meshCurrent->addTriangleCubic(v1,v3,v2);
}
if(currentVoxel < plusYVoxel)
{
int material = m_volData->getVoxelAt(x,y+1,z).getMaterial();
uint32_t v0 = m_meshCurrent->addVertex(PositionMaterialNormal(Vector3DFloat(regX - 0.5f, regY + 0.5f, regZ - 0.5f), Vector3DFloat(0.0f, -1.0f, 0.0f), material));
uint32_t v1 = m_meshCurrent->addVertex(PositionMaterialNormal(Vector3DFloat(regX - 0.5f, regY + 0.5f, regZ + 0.5f), Vector3DFloat(0.0f, -1.0f, 0.0f), material));
uint32_t v2 = m_meshCurrent->addVertex(PositionMaterialNormal(Vector3DFloat(regX + 0.5f, regY + 0.5f, regZ - 0.5f), Vector3DFloat(0.0f, -1.0f, 0.0f), material));
uint32_t v3 = m_meshCurrent->addVertex(PositionMaterialNormal(Vector3DFloat(regX + 0.5f, regY + 0.5f, regZ + 0.5f), Vector3DFloat(0.0f, -1.0f, 0.0f), material));
m_meshCurrent->addTriangleCubic(v0,v2,v1);
m_meshCurrent->addTriangleCubic(v1,v2,v3);
}
int plusZVoxel = m_volData->getVoxelAt(x,y,z+1).getDensity() >= VoxelType::getThreshold();
if(currentVoxel > plusZVoxel)
{
int material = m_volData->getVoxelAt(x,y,z).getMaterial();
uint32_t v0 = m_meshCurrent->addVertex(PositionMaterialNormal(Vector3DFloat(regX - 0.5f, regY - 0.5f, regZ + 0.5f), Vector3DFloat(0.0f, 0.0f, 1.0f), material));
uint32_t v1 = m_meshCurrent->addVertex(PositionMaterialNormal(Vector3DFloat(regX - 0.5f, regY + 0.5f, regZ + 0.5f), Vector3DFloat(0.0f, 0.0f, 1.0f), material));
uint32_t v2 = m_meshCurrent->addVertex(PositionMaterialNormal(Vector3DFloat(regX + 0.5f, regY - 0.5f, regZ + 0.5f), Vector3DFloat(0.0f, 0.0f, 1.0f), material));
uint32_t v3 = m_meshCurrent->addVertex(PositionMaterialNormal(Vector3DFloat(regX + 0.5f, regY + 0.5f, regZ + 0.5f), Vector3DFloat(0.0f, 0.0f, 1.0f), material));
m_meshCurrent->addTriangleCubic(v0,v2,v1);
m_meshCurrent->addTriangleCubic(v1,v2,v3);
}
if(currentVoxel < plusZVoxel)
{
int material = m_volData->getVoxelAt(x,y,z+1).getMaterial();
uint32_t v0 = m_meshCurrent->addVertex(PositionMaterialNormal(Vector3DFloat(regX - 0.5f, regY - 0.5f, regZ + 0.5f), Vector3DFloat(0.0f, 0.0f, -1.0f), material));
uint32_t v1 = m_meshCurrent->addVertex(PositionMaterialNormal(Vector3DFloat(regX - 0.5f, regY + 0.5f, regZ + 0.5f), Vector3DFloat(0.0f, 0.0f, -1.0f), material));
uint32_t v2 = m_meshCurrent->addVertex(PositionMaterialNormal(Vector3DFloat(regX + 0.5f, regY - 0.5f, regZ + 0.5f), Vector3DFloat(0.0f, 0.0f, -1.0f), material));
uint32_t v3 = m_meshCurrent->addVertex(PositionMaterialNormal(Vector3DFloat(regX + 0.5f, regY + 0.5f, regZ + 0.5f), Vector3DFloat(0.0f, 0.0f, -1.0f), material));
m_meshCurrent->addTriangleCubic(v0,v1,v2);
m_meshCurrent->addTriangleCubic(v1,v3,v2);
}
}
}
}
m_meshCurrent->m_Region = m_regSizeInVoxels;
m_meshCurrent->m_vecLodRecords.clear();
LodRecord lodRecord;
lodRecord.beginIndex = 0;
lodRecord.endIndex = m_meshCurrent->getNoOfIndices();
m_meshCurrent->m_vecLodRecords.push_back(lodRecord);
}
}

View File

@ -55,7 +55,7 @@ namespace PolyVox
template <typename VoxelType>
Vector3DFloat computeSmoothSobelGradient(VolumeSampler<VoxelType>& volIter);
POLYVOXCORE_API void computeNormalsForVertices(Volume<uint8_t>* volumeData, SurfaceMesh& mesh, NormalGenerationMethod normalGenerationMethod);
POLYVOXCORE_API void computeNormalsForVertices(Volume<uint8_t>* volumeData, SurfaceMesh<PositionMaterialNormal>& mesh, NormalGenerationMethod normalGenerationMethod);
POLYVOXCORE_API Vector3DFloat computeNormal(Volume<uint8_t>* volumeData, const Vector3DFloat& v3dPos, NormalGenerationMethod normalGenerationMethod);
}

View File

@ -38,8 +38,8 @@ namespace PolyVox
{
public:
void buildFromMesh(SurfaceMesh* pMesh);
void fillMesh(SurfaceMesh* pMesh);
void buildFromMesh(SurfaceMesh<PositionMaterialNormal>* pMesh);
void fillMesh(SurfaceMesh<PositionMaterialNormal>* pMesh);
void matchEdgePairs(void);
void computeEdgeCosts(void);

View File

@ -37,7 +37,7 @@ namespace PolyVox
{
public:
MeshVertex();
SurfaceVertex m_vertexData;
PositionMaterialNormal m_vertexData;
//MeshEdge* m_pEdge;
//std::set<MeshFace*> m_faces;
//std::set<MeshEdge*> m_edges; //Edges which have this vertex as the src

View File

@ -77,9 +77,10 @@ namespace PolyVox
template <typename Type, uint8_t NoOfMaterialBits, uint8_t NoOfDensityBits> class MaterialDensityPair;
typedef MaterialDensityPair<uint8_t, 4, 4> MaterialDensityPair44;
class SurfaceMesh;
template <typename VertexType> class SurfaceMesh;
class Region;
class SurfaceVertex;
class PositionMaterial;
class PositionMaterialNormal;
template <typename VoxelType> class CubicSurfaceExtractor;
template <typename VoxelType> class SurfaceExtractor;

View File

@ -35,7 +35,7 @@ namespace PolyVox
class SurfaceExtractor
{
public:
SurfaceExtractor(Volume<VoxelType>* volData, Region region, SurfaceMesh* result);
SurfaceExtractor(Volume<VoxelType>* volData, Region region, SurfaceMesh<PositionMaterialNormal>* result);
void execute();
@ -84,7 +84,7 @@ namespace PolyVox
uint32_t m_uNoOfOccupiedCells;
//The surface patch we are currently filling.
SurfaceMesh* m_meshCurrent;
SurfaceMesh<PositionMaterialNormal>* m_meshCurrent;
//Information about the region we are currently processing
Region m_regSizeInVoxels;

View File

@ -30,7 +30,7 @@ freely, subject to the following restrictions:
namespace PolyVox
{
template <typename VoxelType>
SurfaceExtractor<VoxelType>::SurfaceExtractor(Volume<VoxelType>* volData, Region region, SurfaceMesh* result)
SurfaceExtractor<VoxelType>::SurfaceExtractor(Volume<VoxelType>* volData, Region region, SurfaceMesh<PositionMaterialNormal>* result)
:m_volData(volData)
,m_sampVolume(volData)
,m_regSizeInVoxels(region)
@ -457,7 +457,7 @@ namespace PolyVox
const uint8_t uMaterial = v000.getMaterial() | v100.getMaterial(); //Because one of these is 0, the or operation takes the max.
SurfaceVertex surfaceVertex(v3dPosition, v3dNormal, uMaterial);
PositionMaterialNormal surfaceVertex(v3dPosition, v3dNormal, uMaterial);
//surfaceVertex.setOnGeometryEdge(isXEdge || isYEdge || isZEdge);
surfaceVertex.setOnGeometryEdgeNegX(isNegXEdge);
surfaceVertex.setOnGeometryEdgePosX(isPosXEdge);
@ -487,7 +487,7 @@ namespace PolyVox
const uint8_t uMaterial = v000.getMaterial() | v010.getMaterial(); //Because one of these is 0, the or operation takes the max.
SurfaceVertex surfaceVertex(v3dPosition, v3dNormal, uMaterial);
PositionMaterialNormal surfaceVertex(v3dPosition, v3dNormal, uMaterial);
//surfaceVertex.setOnGeometryEdge(isXEdge || isYEdge || isZEdge);
surfaceVertex.setOnGeometryEdgeNegX(isNegXEdge);
surfaceVertex.setOnGeometryEdgePosX(isPosXEdge);
@ -517,7 +517,7 @@ namespace PolyVox
const uint8_t uMaterial = v000.getMaterial() | v001.getMaterial(); //Because one of these is 0, the or operation takes the max.
SurfaceVertex surfaceVertex(v3dPosition, v3dNormal, uMaterial);
PositionMaterialNormal surfaceVertex(v3dPosition, v3dNormal, uMaterial);
//surfaceVertex.setOnGeometryEdge(isXEdge || isYEdge || isZEdge);
surfaceVertex.setOnGeometryEdgeNegX(isNegXEdge);
surfaceVertex.setOnGeometryEdgePosX(isPosXEdge);

View File

@ -42,7 +42,8 @@ namespace PolyVox
int endIndex; //Let's put it just past the end STL style
};
class POLYVOXCORE_API SurfaceMesh
template <typename VertexType>
class SurfaceMesh
{
public:
SurfaceMesh();
@ -53,26 +54,21 @@ namespace PolyVox
uint32_t getNoOfNonUniformTrianges(void) const;
uint32_t getNoOfUniformTrianges(void) const;
uint32_t getNoOfVertices(void) const;
std::vector<SurfaceVertex>& getRawVertexData(void); //FIXME - this should be removed
const std::vector<SurfaceVertex>& getVertices(void) const;
std::vector<VertexType>& getRawVertexData(void); //FIXME - this should be removed
const std::vector<VertexType>& getVertices(void) const;
void addTriangle(uint32_t index0, uint32_t index1, uint32_t index2);
uint32_t addVertex(const SurfaceVertex& vertex);
void addTriangleCubic(uint32_t index0, uint32_t index1, uint32_t index2);
uint32_t addVertex(const VertexType& vertex);
void clear(void);
const bool isEmpty(void) const;
void smoothPositions(float fAmount, bool bIncludeGeometryEdgeVertices = false);
void sumNearbyNormals(bool bNormaliseResult = true);
polyvox_shared_ptr<SurfaceMesh> extractSubset(std::set<uint8_t> setMaterials);
polyvox_shared_ptr< SurfaceMesh<VertexType> > extractSubset(std::set<uint8_t> setMaterials);
void generateAveragedFaceNormals(bool bNormalise, bool bIncludeEdgeVertices = false);
//Vector3DInt32 m_v3dRegionPosition; //FIXME - remove this?
/*void growMaterialBoundary(void);
int countMaterialBoundary(void);*/
bool isSubset(std::bitset<VF_NO_OF_FLAGS> a, std::bitset<VF_NO_OF_FLAGS> b);
@ -90,7 +86,7 @@ namespace PolyVox
public:
std::vector<uint32_t> m_vecTriangleIndices;
std::vector<SurfaceVertex> m_vecVertices;
std::vector<VertexType> m_vecVertices;
std::vector<LodRecord> m_vecLodRecords;
@ -107,4 +103,6 @@ namespace PolyVox
};
}
#include "SurfaceMesh.inl"
#endif /* __SurfaceMesh_H__ */

View File

@ -0,0 +1,862 @@
/*******************************************************************************
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.
*******************************************************************************/
#include <cstdlib>
#include <list>
#include <algorithm>
using namespace std;
namespace PolyVox
{
template <typename VertexType>
SurfaceMesh<VertexType>::SurfaceMesh()
{
m_iTimeStamp = -1;
}
template <typename VertexType>
SurfaceMesh<VertexType>::~SurfaceMesh()
{
}
template <typename VertexType>
const std::vector<uint32_t>& SurfaceMesh<VertexType>::getIndices(void) const
{
return m_vecTriangleIndices;
}
template <typename VertexType>
uint32_t SurfaceMesh<VertexType>::getNoOfIndices(void) const
{
return m_vecTriangleIndices.size();
}
template <typename VertexType>
uint32_t SurfaceMesh<VertexType>::getNoOfNonUniformTrianges(void) const
{
uint32_t result = 0;
for(uint32_t i = 0; i < m_vecTriangleIndices.size() - 2; i += 3)
{
if((m_vecVertices[m_vecTriangleIndices[i]].getMaterial() == m_vecVertices[m_vecTriangleIndices[i+1]].getMaterial())
&& (m_vecVertices[m_vecTriangleIndices[i]].getMaterial() == m_vecVertices[m_vecTriangleIndices[i+2]].getMaterial()))
{
}
else
{
result++;
}
}
return result;
}
template <typename VertexType>
uint32_t SurfaceMesh<VertexType>::getNoOfUniformTrianges(void) const
{
uint32_t result = 0;
for(uint32_t i = 0; i < m_vecTriangleIndices.size() - 2; i += 3)
{
if((m_vecVertices[m_vecTriangleIndices[i]].getMaterial() == m_vecVertices[m_vecTriangleIndices[i+1]].getMaterial())
&& (m_vecVertices[m_vecTriangleIndices[i]].getMaterial() == m_vecVertices[m_vecTriangleIndices[i+2]].getMaterial()))
{
result++;
}
}
return result;
}
template <typename VertexType>
uint32_t SurfaceMesh<VertexType>::getNoOfVertices(void) const
{
return m_vecVertices.size();
}
template <typename VertexType>
std::vector<VertexType>& SurfaceMesh<VertexType>::getRawVertexData(void)
{
return m_vecVertices;
}
template <typename VertexType>
const std::vector<VertexType>& SurfaceMesh<VertexType>::getVertices(void) const
{
return m_vecVertices;
}
template <typename VertexType>
void SurfaceMesh<VertexType>::addTriangle(uint32_t index0, uint32_t index1, uint32_t index2)
{
m_vecTriangleIndices.push_back(index0);
m_vecTriangleIndices.push_back(index1);
m_vecTriangleIndices.push_back(index2);
if((m_vecVertices[index0].material == m_vecVertices[index1].material) && (m_vecVertices[index0].material == m_vecVertices[index2].material))
{
m_mapUsedMaterials.insert(m_vecVertices[index0].material);
}
else
{
m_vecVertices[index0].setOnMaterialEdge(true);
m_vecVertices[index1].setOnMaterialEdge(true);
m_vecVertices[index2].setOnMaterialEdge(true);
}
}
template <typename VertexType>
void SurfaceMesh<VertexType>::addTriangleCubic(uint32_t index0, uint32_t index1, uint32_t index2)
{
m_vecTriangleIndices.push_back(index0);
m_vecTriangleIndices.push_back(index1);
m_vecTriangleIndices.push_back(index2);
}
template <typename VertexType>
uint32_t SurfaceMesh<VertexType>::addVertex(const VertexType& vertex)
{
m_vecVertices.push_back(vertex);
return m_vecVertices.size() - 1;
}
template <typename VertexType>
void SurfaceMesh<VertexType>::clear(void)
{
m_vecVertices.clear();
m_vecTriangleIndices.clear();
m_vecLodRecords.clear();
m_mapUsedMaterials.clear();
}
template <typename VertexType>
const bool SurfaceMesh<VertexType>::isEmpty(void) const
{
return (getNoOfVertices() == 0) || (getNoOfIndices() == 0);
}
////////////////////////////////////////////////////////////////////////////////
/// The function works on a per triangle basis without any need for connectivity
/// information. It determines whether a triangle is lying on a flat or curved
/// section of the surface patch by examining the normals - therefore these
/// 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
/// value by experimentation, starting with something small such as 0.1f.
/// \param bIncludeGeometryEdgeVertices Indicates whether vertices on the edge of an
/// SurfaceMesh should be smoothed. This can cause dicontinuities between
/// neighbouring patches.
////////////////////////////////////////////////////////////////////////////////
template <typename VertexType>
void SurfaceMesh<VertexType>::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...
{
return;
}
//This will hold the new positions, and is initialised with the current positions.
std::vector<Vector3DFloat> newPositions(m_vecVertices.size());
for(uint32_t uIndex = 0; uIndex < newPositions.size(); uIndex++)
{
newPositions[uIndex] = m_vecVertices[uIndex].getPosition();
}
//Iterate over each triangle
for(vector<uint32_t>::iterator iterIndex = m_vecTriangleIndices.begin(); iterIndex != m_vecTriangleIndices.end();)
{
//Get the vertex data for the triangle
PositionMaterialNormal& v0 = m_vecVertices[*iterIndex];
Vector3DFloat& v0New = newPositions[*iterIndex];
iterIndex++;
PositionMaterialNormal& v1 = m_vecVertices[*iterIndex];
Vector3DFloat& v1New = newPositions[*iterIndex];
iterIndex++;
PositionMaterialNormal& v2 = m_vecVertices[*iterIndex];
Vector3DFloat& v2New = newPositions[*iterIndex];
iterIndex++;
//Find the midpoint
Vector3DFloat v3dMidpoint = (v0.position + v1.position + v2.position) / 3.0f;
//Vectors from vertex to midpoint
Vector3DFloat v0ToMidpoint = v3dMidpoint - v0.position;
Vector3DFloat v1ToMidpoint = v3dMidpoint - v1.position;
Vector3DFloat v2ToMidpoint = v3dMidpoint - v2.position;
//Get the vertex normals
Vector3DFloat n0 = v0.getNormal();
Vector3DFloat n1 = v1.getNormal();
Vector3DFloat n2 = v2.getNormal();
//I don't think these normalisation are necessary... and could be slow.
//Normals should be normalised anyway, and as long as all triangles are
//about the same size the distances to midpoint should be similar too.
//v0ToMidpoint.normalise();
//v1ToMidpoint.normalise();
//v2ToMidpoint.normalise();
//n0.normalise();
//n1.normalise();
//n2.normalise();
//If the dot product is zero the the normals are perpendicular
//to the triangle, hence the positions do not move.
v0New += (n0 * (n0.dot(v0ToMidpoint)) * fAmount);
v1New += (n1 * (n1.dot(v1ToMidpoint)) * fAmount);
v2New += (n2 * (n2.dot(v2ToMidpoint)) * fAmount);
}
//Update with the new positions
for(uint32_t uIndex = 0; uIndex < newPositions.size(); uIndex++)
{
if((bIncludeGeometryEdgeVertices) || (m_vecVertices[uIndex].isOnGeometryEdge() == false))
{
m_vecVertices[uIndex].setPosition(newPositions[uIndex]);
}
}
}
////////////////////////////////////////////////////////////////////////////////
/// This function can help improve the visual appearance of a surface patch by
/// smoothing normals with other nearby normals. It iterates over each triangle
/// in the surface patch and determines the sum of its corners normals. For any
/// given vertex, these sums are in turn summed for any triangles which use the
/// vertex. Usually, the resulting normals should be renormalised afterwards.
/// Note: This function can cause lighting discontinuities accross region boundaries.
////////////////////////////////////////////////////////////////////////////////
template <typename VertexType>
void SurfaceMesh<VertexType>::sumNearbyNormals(bool bNormaliseResult)
{
if(m_vecVertices.size() == 0) //FIXME - I don't think we should need this test, but I have seen crashes otherwise...
{
return;
}
std::vector<Vector3DFloat> summedNormals(m_vecVertices.size());
//Initialise all normals to zero. Should be ok as the vector should store all elements contiguously.
memset(&summedNormals[0], 0, summedNormals.size() * sizeof(Vector3DFloat));
for(vector<uint32_t>::iterator iterIndex = m_vecTriangleIndices.begin(); iterIndex != m_vecTriangleIndices.end();)
{
PositionMaterialNormal& v0 = m_vecVertices[*iterIndex];
Vector3DFloat& v0New = summedNormals[*iterIndex];
iterIndex++;
PositionMaterialNormal& v1 = m_vecVertices[*iterIndex];
Vector3DFloat& v1New = summedNormals[*iterIndex];
iterIndex++;
PositionMaterialNormal& v2 = m_vecVertices[*iterIndex];
Vector3DFloat& v2New = summedNormals[*iterIndex];
iterIndex++;
Vector3DFloat sumOfNormals = v0.getNormal() + v1.getNormal() + v2.getNormal();
v0New += sumOfNormals;
v1New += sumOfNormals;
v2New += sumOfNormals;
}
for(uint32_t uIndex = 0; uIndex < summedNormals.size(); uIndex++)
{
if(bNormaliseResult)
{
summedNormals[uIndex].normalise();
}
m_vecVertices[uIndex].setNormal(summedNormals[uIndex]);
}
}
template <typename VertexType>
void SurfaceMesh<VertexType>::generateAveragedFaceNormals(bool bNormalise, bool bIncludeEdgeVertices)
{
Vector3DFloat offset = static_cast<Vector3DFloat>(m_Region.getLowerCorner());
//Initially zero the normals
for(vector<PositionMaterialNormal>::iterator iterVertex = m_vecVertices.begin(); iterVertex != m_vecVertices.end(); iterVertex++)
{
if(m_Region.containsPoint(iterVertex->getPosition() + offset, 0.001))
{
iterVertex->setNormal(Vector3DFloat(0.0f,0.0f,0.0f));
}
}
for(vector<uint32_t>::iterator iterIndex = m_vecTriangleIndices.begin(); iterIndex != m_vecTriangleIndices.end();)
{
PositionMaterialNormal& v0 = m_vecVertices[*iterIndex];
iterIndex++;
PositionMaterialNormal& v1 = m_vecVertices[*iterIndex];
iterIndex++;
PositionMaterialNormal& v2 = m_vecVertices[*iterIndex];
iterIndex++;
Vector3DFloat triangleNormal = (v1.getPosition()-v0.getPosition()).cross(v2.getPosition()-v0.getPosition());
if(m_Region.containsPoint(v0.getPosition() + offset, 0.001))
{
v0.setNormal(v0.getNormal() + triangleNormal);
}
if(m_Region.containsPoint(v1.getPosition() + offset, 0.001))
{
v1.setNormal(v1.getNormal() + triangleNormal);
}
if(m_Region.containsPoint(v2.getPosition() + offset, 0.001))
{
v2.setNormal(v2.getNormal() + triangleNormal);
}
}
if(bNormalise)
{
for(vector<PositionMaterialNormal>::iterator iterVertex = m_vecVertices.begin(); iterVertex != m_vecVertices.end(); iterVertex++)
{
Vector3DFloat normal = iterVertex->getNormal();
normal.normalise();
iterVertex->setNormal(normal);
}
}
}
//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)
{
polyvox_shared_ptr< SurfaceMesh<VertexType> > result(new SurfaceMesh<VertexType>);
if(m_vecVertices.size() == 0) //FIXME - I don't think we should need this test, but I have seen crashes otherwise...
{
return result;
}
assert(m_vecLodRecords.size() == 1);
if(m_vecLodRecords.size() != 1)
{
//If we have done progressive LOD then it's too late to split into subsets.
return result;
}
std::vector<int32_t> indexMap(m_vecVertices.size());
std::fill(indexMap.begin(), indexMap.end(), -1);
for(uint32_t triCt = 0; triCt < m_vecTriangleIndices.size(); triCt += 3)
{
PositionMaterialNormal& v0 = m_vecVertices[m_vecTriangleIndices[triCt]];
PositionMaterialNormal& v1 = m_vecVertices[m_vecTriangleIndices[triCt + 1]];
PositionMaterialNormal& v2 = m_vecVertices[m_vecTriangleIndices[triCt + 2]];
if(
(setMaterials.find(v0.getMaterial()) != setMaterials.end()) ||
(setMaterials.find(v1.getMaterial()) != setMaterials.end()) ||
(setMaterials.find(v2.getMaterial()) != setMaterials.end()))
{
uint32_t i0;
if(indexMap[m_vecTriangleIndices[triCt]] == -1)
{
indexMap[m_vecTriangleIndices[triCt]] = result->addVertex(v0);
}
i0 = indexMap[m_vecTriangleIndices[triCt]];
uint32_t i1;
if(indexMap[m_vecTriangleIndices[triCt+1]] == -1)
{
indexMap[m_vecTriangleIndices[triCt+1]] = result->addVertex(v1);
}
i1 = indexMap[m_vecTriangleIndices[triCt+1]];
uint32_t i2;
if(indexMap[m_vecTriangleIndices[triCt+2]] == -1)
{
indexMap[m_vecTriangleIndices[triCt+2]] = result->addVertex(v2);
}
i2 = indexMap[m_vecTriangleIndices[triCt+2]];
result->addTriangle(i0,i1,i2);
}
}
result->m_vecLodRecords.clear();
LodRecord lodRecord;
lodRecord.beginIndex = 0;
lodRecord.endIndex = result->getNoOfIndices();
result->m_vecLodRecords.push_back(lodRecord);
return result;
}
/*int SurfaceMesh::countMaterialBoundary(void)
{
int count = 0;
for(int ct = 0; ct < m_vecVertices.size(); ct++)
{
if(m_vecVertices[ct].m_bIsMaterialEdgeVertex)
{
count++;
}
}
return count;
}
void SurfaceMesh::growMaterialBoundary(void)
{
std::vector<PositionMaterialNormal> vecNewVertices = m_vecVertices;
for(vector<uint32_t>::iterator iterIndex = m_vecTriangleIndices.begin(); iterIndex != m_vecTriangleIndices.end();)
{
PositionMaterialNormal& v0 = m_vecVertices[*iterIndex];
PositionMaterialNormal& v0New = vecNewVertices[*iterIndex];
iterIndex++;
PositionMaterialNormal& v1 = m_vecVertices[*iterIndex];
PositionMaterialNormal& v1New = vecNewVertices[*iterIndex];
iterIndex++;
PositionMaterialNormal& v2 = m_vecVertices[*iterIndex];
PositionMaterialNormal& v2New = vecNewVertices[*iterIndex];
iterIndex++;
if(v0.m_bIsMaterialEdgeVertex || v1.m_bIsMaterialEdgeVertex || v2.m_bIsMaterialEdgeVertex)
{
v0New.m_bIsMaterialEdgeVertex = true;
v1New.m_bIsMaterialEdgeVertex = true;
v2New.m_bIsMaterialEdgeVertex = true;
}
}
m_vecVertices = vecNewVertices;
}*/
template <typename VertexType>
void SurfaceMesh<VertexType>::decimate(float fMinDotProductForCollapse)
{
// We will need the information from this function to
// determine when material boundary edges can collapse.
countNoOfNeighboursUsingMaterial();
uint32_t noOfEdgesCollapsed;
do
{
noOfEdgesCollapsed = performDecimationPass(fMinDotProductForCollapse);
removeDegenerateTris();
}while(noOfEdgesCollapsed > 0);
//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.
template <typename VertexType>
bool SurfaceMesh<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
{
if(a.test(ct))
{
if(b.test(ct) == false)
{
result = false;
break;
}
}
}
return result;
}
template <typename VertexType>
uint32_t SurfaceMesh<VertexType>::performDecimationPass(float fMinDotProductForCollapse)
{
// I'm using a vector of lists here, rather than a vector of sets,
// because I don't believe that duplicaes should occur. But this
// might be worth checking if we have problems in the future.
vector< list<uint32_t> > trianglesUsingVertex(m_vecVertices.size());
for(int ct = 0; ct < m_vecTriangleIndices.size(); ct++)
{
int triangle = ct / 3;
trianglesUsingVertex[m_vecTriangleIndices[ct]].push_back(triangle);
}
// Count how many edges we have collapsed
uint32_t noOfEdgesCollapsed = 0;
// The vertex mapper track whick vertices collapse onto which.
vector<uint32_t> vertexMapper(m_vecVertices.size());
// Once a vertex is involved in a collapse (either because it
// moves onto a different vertex, or because a different vertex
// moves onto it) it is forbidden to take part in another collapse
// this pass. We enforce this by setting the vertex locked flag.
vector<bool> vertexLocked(m_vecVertices.size());
// Initialise the vectors
for(uint32_t ct = 0; ct < m_vecVertices.size(); ct++)
{
// Initiall all vertices points to themselves
vertexMapper[ct] = ct;
// All vertices are initially unlocked
vertexLocked[ct] = false;
}
// Each triangle exists in this vector once.
vector<int> vecOfTriCts(m_vecTriangleIndices.size() / 3);
for(int triCt = 0; triCt < vecOfTriCts.size(); triCt++)
{
vecOfTriCts[triCt] = triCt;
}
// It *may* be beneficial to randomise the order in which triangles
// are processed to get a more uniform distribution off collapses and
// more equally sized triangles at the end. This need more testing really.
random_shuffle(vecOfTriCts.begin(), vecOfTriCts.end());
//For each triange...
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)];
//A vertex will be locked if it has already been involved in a collapse this pass.
if(vertexLocked[v0] || vertexLocked[v1])
{
continue;
}
if(m_vecVertices[v0].getMaterial() != m_vecVertices[v1].getMaterial())
{
continue;
}
//For now, don't collapse vertices on material edges...
if(m_vecVertices[v0].isOnMaterialEdge() || m_vecVertices[v1].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[v0] == m_vecNoOfNeighboursUsingMaterial[v1])
{
if(m_vecNoOfNeighboursUsingMaterial[v0] == 4)
{
allMatch = true;
}
}
bool movementValid = false;
Vector3DFloat movement = m_vecVertices[v1].getPosition() - m_vecVertices[v0].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)
{
continue;
}
}
else //Material collapses not allowed
{
continue;
}
}
// 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_vecVertices[v0].m_bFlags.any() || m_vecVertices[v1].m_bFlags.any())
{
// Assume we can't collapse until we prove otherwise...
bool bCollapseGeometryEdgePair = false;
// 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_vecVertices[v0].m_bFlags, m_vecVertices[v1].m_bFlags))
{
// In general adjacent regions surface meshes may collapse differently
// and this can cause cracks. We solve this by only allowing the collapse
// is the normals are exactly the same. We do not use the user provided
// tolerence here (but do allow for floating point error).
if(m_vecVertices[v0].getNormal().dot(m_vecVertices[v1].getNormal()) > 0.999)
{
// Ok, this pair can collapse.
bCollapseGeometryEdgePair = true;
}
}
// Use the result.
if(!bCollapseGeometryEdgePair)
{
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;
list<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(list<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;
}
template <typename VertexType>
int SurfaceMesh<VertexType>::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;
}
template <typename VertexType>
void SurfaceMesh<VertexType>::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);
}
}

View File

@ -44,12 +44,28 @@ namespace PolyVox
VF_NO_OF_FLAGS
};
class POLYVOXCORE_API SurfaceVertex
class POLYVOXCORE_API PositionMaterial
{
public:
SurfaceVertex();
SurfaceVertex(Vector3DFloat positionToSet, float materialToSet);
SurfaceVertex(Vector3DFloat positionToSet, Vector3DFloat normalToSet, float materialToSet);
PositionMaterial();
PositionMaterial(Vector3DFloat positionToSet, float materialToSet);
float getMaterial(void) const;
const Vector3DFloat& getPosition(void) const;
void setMaterial(float materialToSet);
void setPosition(const Vector3DFloat& positionToSet);
public:
Vector3DFloat position;
float material;
};
class POLYVOXCORE_API PositionMaterialNormal
{
public:
PositionMaterialNormal();
PositionMaterialNormal(Vector3DFloat positionToSet, float materialToSet);
PositionMaterialNormal(Vector3DFloat positionToSet, Vector3DFloat normalToSet, float materialToSet);
float getMaterial(void) const;
const Vector3DFloat& getNormal(void) const;
@ -83,11 +99,6 @@ namespace PolyVox
float material; //FIXME: This shouldn't be float on CPU?
std::bitset<VF_NO_OF_FLAGS> m_bFlags;
};
//bool operator < (const SurfaceVertexIterator& lhs, const SurfaceVertexIterator& rhs);
}
#endif

View File

@ -66,12 +66,12 @@ namespace PolyVox
{
}
template <typename VoxelType>
////////////////////////////////////////////////////////////////////////////////
/// The border value is returned whenever an atempt is made to read a voxel which
/// is outside the extents of the volume.
/// \return The value used for voxels outside of the volume
////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType>
VoxelType Volume<VoxelType>::getBorderValue(void) const
{
return m_pBorderBlock->getVoxelAt(0,0,0);