Initial version of mesh smoothing code.

This commit is contained in:
David Williams 2008-06-24 21:28:29 +00:00
parent b12bd1ebe2
commit e6a7174b53
10 changed files with 167 additions and 377 deletions

View File

@ -139,13 +139,13 @@ namespace PolyVox
assert(uYPos < getSideLength());
assert(uZPos < getSideLength());
const uint16_t blockX = uXPos >> m_uBlockSideLengthPower;
const uint16_t blockY = uYPos >> m_uBlockSideLengthPower;
const uint16_t blockZ = uZPos >> m_uBlockSideLengthPower;
const boost::uint16_t blockX = uXPos >> m_uBlockSideLengthPower;
const boost::uint16_t blockY = uYPos >> m_uBlockSideLengthPower;
const boost::uint16_t blockZ = uZPos >> m_uBlockSideLengthPower;
const uint16_t xOffset = uXPos - (blockX << m_uBlockSideLengthPower);
const uint16_t yOffset = uYPos - (blockY << m_uBlockSideLengthPower);
const uint16_t zOffset = uZPos - (blockZ << m_uBlockSideLengthPower);
const boost::uint16_t xOffset = uXPos - (blockX << m_uBlockSideLengthPower);
const boost::uint16_t yOffset = uYPos - (blockY << m_uBlockSideLengthPower);
const boost::uint16_t zOffset = uZPos - (blockZ << m_uBlockSideLengthPower);
const Block<VoxelType>* block = m_pBlocks
[

View File

@ -43,11 +43,11 @@ namespace PolyVox
bool operator<=(const BlockVolumeIterator& rhs);
bool operator>=(const BlockVolumeIterator& rhs);
float getAveragedVoxel(boost::uint16_t size) const;
VoxelType getMaxedVoxel(boost::uint8_t uLevel) const;
boost::uint16_t getPosX(void) const;
boost::uint16_t getPosY(void) const;
boost::uint16_t getPosZ(void) const;
const BlockVolume<VoxelType>& getVolume(void) const;
VoxelType getVoxel(void) const;
void setPosition(const Vector3DInt16& v3dNewPos);

View File

@ -104,38 +104,6 @@ namespace PolyVox
#pragma endregion
#pragma region Getters
template <typename VoxelType>
float BlockVolumeIterator<VoxelType>::getAveragedVoxel(boost::uint16_t size) const
{
assert(mXPosInVolume >= size);
assert(mYPosInVolume >= size);
assert(mZPosInVolume >= size);
assert(mXPosInVolume < mVolume.getSideLength() - (size + 1));
assert(mYPosInVolume < mVolume.getSideLength() - (size + 1));
assert(mZPosInVolume < mVolume.getSideLength() - (size + 1));
float sum = 0.0;
for(uint16_t z = mZPosInVolume-size; z <= mZPosInVolume+size; ++z)
{
for(uint16_t y = mYPosInVolume-size; y <= mYPosInVolume+size; ++y)
{
for(uint16_t x = mXPosInVolume-size; x <= mXPosInVolume+size; ++x)
{
if(mVolume.getVoxelAt(x,y,z) != 0)
{
sum += 1.0;
}
}
}
}
uint16_t kernelSideLength = size * 2 + 1;
uint16_t kernelVolume = kernelSideLength * kernelSideLength * kernelSideLength;
sum /= static_cast<float>(kernelVolume);
return sum;
}
template <typename VoxelType>
VoxelType BlockVolumeIterator<VoxelType>::getMaxedVoxel(boost::uint8_t uLevel) const
{
@ -192,6 +160,12 @@ namespace PolyVox
return mZPosInVolume;
}
template <typename VoxelType>
const BlockVolume<VoxelType>& BlockVolumeIterator<VoxelType>::getVolume(void) const
{
return mVolume;
}
template <typename VoxelType>
VoxelType BlockVolumeIterator<VoxelType>::getVoxel(void) const
{

View File

@ -19,6 +19,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
******************************************************************************/
#pragma endregion
#include "SurfaceAdjusters.h"
namespace PolyVox
{
template <typename VoxelType>
@ -76,25 +78,25 @@ namespace PolyVox
//FIXME - bitwise way of doing this?
volIter.setPosition(initialX-1, initialY, initialZ);
float voxel1nx = volIter.getAveragedVoxel(1);
float voxel1nx = computeSmoothedVoxel(volIter);
volIter.setPosition(initialX+1, initialY, initialZ);
float voxel1px = volIter.getAveragedVoxel(1);
float voxel1px = computeSmoothedVoxel(volIter);
volIter.setPosition(initialX, initialY-1, initialZ);
float voxel1ny = volIter.getAveragedVoxel(1);
float voxel1ny = computeSmoothedVoxel(volIter);
volIter.setPosition(initialX, initialY+1, initialZ);
float voxel1py = volIter.getAveragedVoxel(1);
float voxel1py = computeSmoothedVoxel(volIter);
volIter.setPosition(initialX, initialY, initialZ-1);
float voxel1nz = volIter.getAveragedVoxel(1);
float voxel1nz = computeSmoothedVoxel(volIter);
volIter.setPosition(initialX, initialY, initialZ+1);
float voxel1pz = volIter.getAveragedVoxel(1);
float voxel1pz = computeSmoothedVoxel(volIter);
return Vector3DFloat
(
voxel1px - voxel1nx,
voxel1py - voxel1ny,
voxel1pz - voxel1nz
voxel1nx - voxel1px,
voxel1ny - voxel1py,
voxel1nz - voxel1pz
);
}

View File

@ -33,6 +33,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
namespace PolyVox
{
POLYVOX_API void smoothRegionGeometry(BlockVolume<boost::uint8_t>* volumeData, RegionGeometry& regGeom);
float computeSmoothedVoxel(BlockVolumeIterator<boost::uint8_t>& volIter);
}
#endif

View File

@ -45,9 +45,6 @@ namespace PolyVox
POLYVOX_API void generateRoughVerticesForSlice(BlockVolumeIterator<boost::uint8_t>& volIter, Region& regSlice, const Vector3DFloat& offset, boost::uint8_t* bitmask, IndexedSurfacePatch* singleMaterialPatch,boost::int32_t vertexIndicesX[],boost::int32_t vertexIndicesY[],boost::int32_t vertexIndicesZ[]);
POLYVOX_API void generateReferenceMeshDataForRegion(BlockVolume<boost::uint8_t>* volumeData, Region region, IndexedSurfacePatch* singleMaterialPatch);
POLYVOX_API void generateSmoothMeshDataForRegion(BlockVolume<boost::uint8_t>* volumeData, Region region, IndexedSurfacePatch* singleMaterialPatch);
POLYVOX_API Vector3DFloat computeSmoothNormal(BlockVolume<boost::uint8_t>* volumeData, const Vector3DFloat& position, NormalGenerationMethod normalGenerationMethod);
}
#endif

View File

@ -30,6 +30,31 @@ namespace PolyVox
{
POLYVOX_API boost::uint8_t logBase2(boost::uint32_t uInput);
POLYVOX_API bool isPowerOf2(boost::uint32_t uInput);
template <typename Type>
Type trilinearlyInterpolate(
const Type& v000,const Type& v100,const Type& v010,const Type& v110,
const Type& v001,const Type& v101,const Type& v011,const Type& v111,
const float x, const float y, const float z)
{
assert((x >= 0.0f) && (y >= 0.0f) && (z >= 0.0f) &&
(x <= 1.0f) && (y <= 1.0f) && (z <= 1.0f));
//Interpolate along X
Type v000_v100 = (v100 - v000) * x + v000;
Type v001_v101 = (v101 - v001) * x + v001;
Type v010_v110 = (v110 - v010) * x + v010;
Type v011_v111 = (v111 - v011) * x + v011;
//Interpolate along Y
Type v000_v100__v010_v110 = (v010_v110 - v000_v100) * y + v000_v100;
Type v001_v101__v011_v111 = (v011_v111 - v001_v101) * y + v001_v101;
//Interpolate along Z
Type v000_v100__v010_v110____v001_v101__v011_v111 = (v001_v101__v011_v111 - v000_v100__v010_v110) * z + v000_v100__v010_v110;
return v000_v100__v010_v110____v001_v101__v011_v111;
}
}
#endif

View File

@ -1,7 +1,10 @@
#include "SurfaceAdjusters.h"
#include "BlockVolumeIterator.h"
#include "GradientEstimators.h"
#include "IndexedSurfacePatch.h"
#include "RegionGeometry.h"
#include "Utility.h"
#include <vector>
@ -9,13 +12,110 @@ namespace PolyVox
{
void smoothRegionGeometry(BlockVolume<boost::uint8_t>* volumeData, RegionGeometry& regGeom)
{
const boost::uint8_t uSmoothingFactor = 2;
const float fThreshold = 0.5f;
BlockVolumeIterator<boost::uint8_t> volIter(*volumeData);
std::vector<SurfaceVertex>& vecVertices = regGeom.m_patchSingleMaterial->m_vecVertices;
std::vector<SurfaceVertex>::iterator iterSurfaceVertex = vecVertices.begin();
while(iterSurfaceVertex != vecVertices.end())
{
iterSurfaceVertex->setPosition(iterSurfaceVertex->getPosition() + iterSurfaceVertex->getNormal());
//iterSurfaceVertex->setPosition(iterSurfaceVertex->getPosition() + Vector3DFloat(10.0f,0.0f,0.0f));
for(int ct = 0; ct < uSmoothingFactor; ++ct)
{
const Vector3DFloat& v3dPos = iterSurfaceVertex->getPosition() + static_cast<Vector3DFloat>(regGeom.m_v3dRegionPosition);
const Vector3DInt32 v3dFloor = static_cast<Vector3DInt32>(v3dPos);
const Vector3DFloat& v3dRem = v3dPos - static_cast<Vector3DFloat>(v3dFloor);
//Check all corners are within the volume, allowing a boundary for gradient estimation
bool lowerCornerInside = volumeData->containsPoint(v3dFloor,2);
bool upperCornerInside = volumeData->containsPoint(v3dFloor+Vector3DInt32(1,1,1),2);
if(lowerCornerInside && upperCornerInside) //If this test fails the vertex will be left as it was
{
volIter.setPosition(static_cast<Vector3DInt16>(v3dFloor + Vector3DInt32(0,0,0)));
const float v000 = computeSmoothedVoxel(volIter);
Vector3DFloat grad000 = computeSmoothCentralDifferenceGradient(volIter);
volIter.setPosition(static_cast<Vector3DInt16>(v3dFloor + Vector3DInt32(1,0,0)));
const float v100 = computeSmoothedVoxel(volIter);
Vector3DFloat grad100 = computeSmoothCentralDifferenceGradient(volIter);
volIter.setPosition(static_cast<Vector3DInt16>(v3dFloor + Vector3DInt32(0,1,0)));
const float v010 = computeSmoothedVoxel(volIter);
Vector3DFloat grad010 = computeSmoothCentralDifferenceGradient(volIter);
volIter.setPosition(static_cast<Vector3DInt16>(v3dFloor + Vector3DInt32(1,1,0)));
const float v110 = computeSmoothedVoxel(volIter);
Vector3DFloat grad110 = computeSmoothCentralDifferenceGradient(volIter);
volIter.setPosition(static_cast<Vector3DInt16>(v3dFloor + Vector3DInt32(0,0,1)));
const float v001 = computeSmoothedVoxel(volIter);
Vector3DFloat grad001 = computeSmoothCentralDifferenceGradient(volIter);
volIter.setPosition(static_cast<Vector3DInt16>(v3dFloor + Vector3DInt32(1,0,1)));
const float v101 = computeSmoothedVoxel(volIter);
Vector3DFloat grad101 = computeSmoothCentralDifferenceGradient(volIter);
volIter.setPosition(static_cast<Vector3DInt16>(v3dFloor + Vector3DInt32(0,1,1)));
const float v011 = computeSmoothedVoxel(volIter);
Vector3DFloat grad011 = computeSmoothCentralDifferenceGradient(volIter);
volIter.setPosition(static_cast<Vector3DInt16>(v3dFloor + Vector3DInt32(1,1,1)));
const float v111 = computeSmoothedVoxel(volIter);
Vector3DFloat grad111 = computeSmoothCentralDifferenceGradient(volIter);
float fInterVal = trilinearlyInterpolate(v000,v100,v010,v110,v001,v101,v011,v111,v3dRem.getX(),v3dRem.getY(),v3dRem.getZ());
Vector3DFloat fInterGrad = trilinearlyInterpolate(grad000,grad100,grad010,grad110,grad001,grad101,grad011,grad111,v3dRem.getX(),v3dRem.getY(),v3dRem.getZ());
fInterGrad.normalise();
float fDiff = fInterVal - fThreshold;
iterSurfaceVertex->setPosition(iterSurfaceVertex->getPosition() + (fInterGrad * fDiff));
iterSurfaceVertex->setNormal(fInterGrad); //This is actually the gradient for the previous position, but it won't have moved much.
} //if(lowerCornerInside && upperCornerInside)
} //for(int ct = 0; ct < uSmoothingFactor; ++ct)
++iterSurfaceVertex;
}
} //while(iterSurfaceVertex != vecVertices.end())
}
float computeSmoothedVoxel(BlockVolumeIterator<boost::uint8_t>& volIter)
{
assert(volIter.getPosX() >= 1);
assert(volIter.getPosY() >= 1);
assert(volIter.getPosZ() >= 1);
assert(volIter.getPosX() < volIter.getVolume().getSideLength() - 2);
assert(volIter.getPosY() < volIter.getVolume().getSideLength() - 2);
assert(volIter.getPosZ() < volIter.getVolume().getSideLength() - 2);
float sum = 0.0;
if(volIter.peekVoxel1nx1ny1nz() != 0) sum += 1.0f;
if(volIter.peekVoxel1nx1ny0pz() != 0) sum += 1.0f;
if(volIter.peekVoxel1nx1ny1pz() != 0) sum += 1.0f;
if(volIter.peekVoxel1nx0py1nz() != 0) sum += 1.0f;
if(volIter.peekVoxel1nx0py0pz() != 0) sum += 1.0f;
if(volIter.peekVoxel1nx0py1pz() != 0) sum += 1.0f;
if(volIter.peekVoxel1nx1py1nz() != 0) sum += 1.0f;
if(volIter.peekVoxel1nx1py0pz() != 0) sum += 1.0f;
if(volIter.peekVoxel1nx1py1pz() != 0) sum += 1.0f;
if(volIter.peekVoxel0px1ny1nz() != 0) sum += 1.0f;
if(volIter.peekVoxel0px1ny0pz() != 0) sum += 1.0f;
if(volIter.peekVoxel0px1ny1pz() != 0) sum += 1.0f;
if(volIter.peekVoxel0px0py1nz() != 0) sum += 1.0f;
if(volIter.getVoxel() != 0) sum += 1.0f;
if(volIter.peekVoxel0px0py1pz() != 0) sum += 1.0f;
if(volIter.peekVoxel0px1py1nz() != 0) sum += 1.0f;
if(volIter.peekVoxel0px1py0pz() != 0) sum += 1.0f;
if(volIter.peekVoxel0px1py1pz() != 0) sum += 1.0f;
if(volIter.peekVoxel1px1ny1nz() != 0) sum += 1.0f;
if(volIter.peekVoxel1px1ny0pz() != 0) sum += 1.0f;
if(volIter.peekVoxel1px1ny1pz() != 0) sum += 1.0f;
if(volIter.peekVoxel1px0py1nz() != 0) sum += 1.0f;
if(volIter.peekVoxel1px0py0pz() != 0) sum += 1.0f;
if(volIter.peekVoxel1px0py1pz() != 0) sum += 1.0f;
if(volIter.peekVoxel1px1py1nz() != 0) sum += 1.0f;
if(volIter.peekVoxel1px1py0pz() != 0) sum += 1.0f;
if(volIter.peekVoxel1px1py1pz() != 0) sum += 1.0f;
sum /= 27.0f;
return sum;
}
}

View File

@ -32,9 +32,17 @@ namespace PolyVox
generateDecimatedMeshDataForRegion(volume.getVolumeData(), 0, *iterChangedRegions, regionGeometry.m_patchSingleMaterial);
computeNormalsForVertices(volume.getVolumeData(), regionGeometry, CENTRAL_DIFFERENCE);
//generateReferenceMeshDataForRegion(volume.getVolumeData(), *iterChangedRegions, regionGeometry.m_patchSingleMaterial);
//for(int ct = 0; ct < 2; ct++)
Vector3DInt32 temp = regionGeometry.m_v3dRegionPosition;
//temp /= 16;
if(temp.getX() % 32 == 0)
{
smoothRegionGeometry(volume.getVolumeData(), regionGeometry);
}
//smoothRegionGeometry(volume.getVolumeData(), regionGeometry);
//computeNormalsForVertices(volume.getVolumeData(), regionGeometry, CENTRAL_DIFFERENCE);
//genMultiFromSingle(regionGeometry.m_patchSingleMaterial, regionGeometry.m_patchMultiMaterial);
@ -746,324 +754,4 @@ namespace PolyVox
}
}*/
}
void generateSmoothMeshDataForRegion(BlockVolume<uint8_t>* volumeData, Region region, IndexedSurfacePatch* singleMaterialPatch)
{
//When generating the mesh for a region we actually look one voxel outside it in the
// back, bottom, right direction. Protect against access violations by cropping region here
Region regVolume = volumeData->getEnclosingRegion();
regVolume.setUpperCorner(regVolume.getUpperCorner() - Vector3DInt32(1,1,1));
region.cropTo(regVolume);
//Offset from lower block corner
const Vector3DFloat offset = static_cast<Vector3DFloat>(region.getLowerCorner());
Vector3DFloat vertlist[12];
uint8_t vertMaterials[12];
BlockVolumeIterator<boost::uint8_t> volIter(*volumeData);
volIter.setValidRegion(region);
const float threshold = 0.5f;
//////////////////////////////////////////////////////////////////////////
//Get mesh data
//////////////////////////////////////////////////////////////////////////
//Iterate over each cell in the region
for(volIter.setPosition(region.getLowerCorner().getX(),region.getLowerCorner().getY(), region.getLowerCorner().getZ());volIter.isValidForRegion();volIter.moveForwardInRegionXYZ())
{
//Current position
const uint16_t x = volIter.getPosX();
const uint16_t y = volIter.getPosY();
const uint16_t z = volIter.getPosZ();
//Voxels values
BlockVolumeIterator<boost::uint8_t> tempVolIter(*volumeData);
tempVolIter.setPosition(x,y,z);
const float v000 = tempVolIter.getAveragedVoxel(1);
tempVolIter.setPosition(x+1,y,z);
const float v100 = tempVolIter.getAveragedVoxel(1);
tempVolIter.setPosition(x,y+1,z);
const float v010 = tempVolIter.getAveragedVoxel(1);
tempVolIter.setPosition(x+1,y+1,z);
const float v110 = tempVolIter.getAveragedVoxel(1);
tempVolIter.setPosition(x,y,z+1);
const float v001 = tempVolIter.getAveragedVoxel(1);
tempVolIter.setPosition(x+1,y,z+1);
const float v101 = tempVolIter.getAveragedVoxel(1);
tempVolIter.setPosition(x,y+1,z+1);
const float v011 = tempVolIter.getAveragedVoxel(1);
tempVolIter.setPosition(x+1,y+1,z+1);
const float v111 = tempVolIter.getAveragedVoxel(1);
//Determine the index into the edge table which tells us which vertices are inside of the surface
uint8_t iCubeIndex = 0;
if (v000 < threshold) iCubeIndex |= 1;
if (v100 < threshold) iCubeIndex |= 2;
if (v110 < threshold) iCubeIndex |= 4;
if (v010 < threshold) iCubeIndex |= 8;
if (v001 < threshold) iCubeIndex |= 16;
if (v101 < threshold) iCubeIndex |= 32;
if (v111 < threshold) iCubeIndex |= 64;
if (v011 < threshold) iCubeIndex |= 128;
/* Cube is entirely in/out of the surface */
if (edgeTable[iCubeIndex] == 0)
{
continue;
}
/* Find the vertices where the surface intersects the cube */
if (edgeTable[iCubeIndex] & 1)
{
float a = v000;
float b = v100;
float val = (threshold-a)/(b-a);
vertlist[0].setX(x + val);
vertlist[0].setY(y);
vertlist[0].setZ(z);
vertMaterials[0] = 1;//v000 | v100; //Because one of these is 0, the or operation takes the max.
}
if (edgeTable[iCubeIndex] & 2)
{
float a = v100;
float b = v110;
float val = (threshold-a)/(b-a);
vertlist[1].setX(x + 1.0f);
vertlist[1].setY(y + val);
vertlist[1].setZ(z);
vertMaterials[1] = 1;//v100 | v110;
}
if (edgeTable[iCubeIndex] & 4)
{
float a = v010;
float b = v110;
float val = (threshold-a)/(b-a);
vertlist[2].setX(x + val);
vertlist[2].setY(y + 1.0f);
vertlist[2].setZ(z);
vertMaterials[2] = 1;//v010 | v110;
}
if (edgeTable[iCubeIndex] & 8)
{
float a = v000;
float b = v010;
float val = (threshold-a)/(b-a);
vertlist[3].setX(x);
vertlist[3].setY(y + val);
vertlist[3].setZ(z);
vertMaterials[3] = 1;//v000 | v010;
}
if (edgeTable[iCubeIndex] & 16)
{
float a = v001;
float b = v101;
float val = (threshold-a)/(b-a);
vertlist[4].setX(x + val);
vertlist[4].setY(y);
vertlist[4].setZ(z + 1.0f);
vertMaterials[4] = 1;//v001 | v101;
}
if (edgeTable[iCubeIndex] & 32)
{
float a = v101;
float b = v111;
float val = (threshold-a)/(b-a);
vertlist[5].setX(x + 1.0f);
vertlist[5].setY(y + val);
vertlist[5].setZ(z + 1.0f);
vertMaterials[5] = 1;//v101 | v111;
}
if (edgeTable[iCubeIndex] & 64)
{
float a = v011;
float b = v111;
float val = (threshold-a)/(b-a);
vertlist[6].setX(x + val);
vertlist[6].setY(y + 1.0f);
vertlist[6].setZ(z + 1.0f);
vertMaterials[6] = 1;//v011 | v111;
}
if (edgeTable[iCubeIndex] & 128)
{
float a = v001;
float b = v011;
float val = (threshold-a)/(b-a);
vertlist[7].setX(x);
vertlist[7].setY(y + val);
vertlist[7].setZ(z + 1.0f);
vertMaterials[7] = 1;//v001 | v011;
}
if (edgeTable[iCubeIndex] & 256)
{
float a = v000;
float b = v001;
float val = (threshold-a)/(b-a);
vertlist[8].setX(x);
vertlist[8].setY(y);
vertlist[8].setZ(z + val);
vertMaterials[8] = 1;//v000 | v001;
}
if (edgeTable[iCubeIndex] & 512)
{
float a = v100;
float b = v101;
float val = (threshold-a)/(b-a);
vertlist[9].setX(x + 1.0f);
vertlist[9].setY(y);
vertlist[9].setZ(z + val);
vertMaterials[9] = 1;//v100 | v101;
}
if (edgeTable[iCubeIndex] & 1024)
{
float a = v110;
float b = v111;
float val = (threshold-a)/(b-a);
vertlist[10].setX(x + 1.0f);
vertlist[10].setY(y + 1.0f);
vertlist[10].setZ(z + val);
vertMaterials[10] = 1;//v110 | v111;
}
if (edgeTable[iCubeIndex] & 2048)
{
float a = v010;
float b = v011;
float val = (threshold-a)/(b-a);
vertlist[11].setX(x);
vertlist[11].setY(y + 1.0f);
vertlist[11].setZ(z + val);
vertMaterials[11] = 1;//v010 | v011;
}
for (int i=0;triTable[iCubeIndex][i]!=-1;i+=3)
{
//The three vertices forming a triangle
const Vector3DFloat vertex0 = vertlist[triTable[iCubeIndex][i ]] - offset;
const Vector3DFloat vertex1 = vertlist[triTable[iCubeIndex][i+1]] - offset;
const Vector3DFloat vertex2 = vertlist[triTable[iCubeIndex][i+2]] - offset;
const uint8_t material0 = vertMaterials[triTable[iCubeIndex][i ]];
const uint8_t material1 = vertMaterials[triTable[iCubeIndex][i+1]];
const uint8_t material2 = vertMaterials[triTable[iCubeIndex][i+2]];
SurfaceVertex surfaceVertex0Alpha1(vertex0,material0 + 0.1f,1.0f);
SurfaceVertex surfaceVertex1Alpha1(vertex1,material1 + 0.1f,1.0f);
SurfaceVertex surfaceVertex2Alpha1(vertex2,material2 + 0.1f,1.0f);
singleMaterialPatch->addTriangle(surfaceVertex0Alpha1, surfaceVertex1Alpha1, surfaceVertex2Alpha1);
}//For each triangle
}//For each cell
//FIXME - can it happen that we have no vertices or triangles? Should exit early?
//for(std::map<uint8_t, IndexedSurfacePatch*>::iterator iterPatch = surfacePatchMapResult.begin(); iterPatch != surfacePatchMapResult.end(); ++iterPatch)
{
std::vector<SurfaceVertex>::iterator iterSurfaceVertex = singleMaterialPatch->getVertices().begin();
while(iterSurfaceVertex != singleMaterialPatch->getVertices().end())
{
Vector3DFloat tempNormal = computeSmoothNormal(volumeData, static_cast<Vector3DFloat>(iterSurfaceVertex->getPosition() + offset), CENTRAL_DIFFERENCE);
const_cast<SurfaceVertex&>(*iterSurfaceVertex).setNormal(tempNormal);
++iterSurfaceVertex;
}
}
}
Vector3DFloat computeSmoothNormal(BlockVolume<uint8_t>* volumeData, const Vector3DFloat& position, NormalGenerationMethod normalGenerationMethod)
{
const float posX = position.getX();
const float posY = position.getY();
const float posZ = position.getZ();
const uint16_t floorX = static_cast<uint16_t>(posX);
const uint16_t floorY = static_cast<uint16_t>(posY);
const uint16_t floorZ = static_cast<uint16_t>(posZ);
//Check all corners are within the volume, allowing a boundary for gradient estimation
bool lowerCornerInside = volumeData->containsPoint(Vector3DInt32(floorX, floorY, floorZ),1);
bool upperCornerInside = volumeData->containsPoint(Vector3DInt32(floorX+1, floorY+1, floorZ+1),1);
if((!lowerCornerInside) || (!upperCornerInside))
{
normalGenerationMethod = SIMPLE;
}
Vector3DFloat result;
BlockVolumeIterator<boost::uint8_t> volIter(*volumeData); //FIXME - save this somewhere - could be expensive to create?
if(normalGenerationMethod == SOBEL)
{
volIter.setPosition(static_cast<uint16_t>(posX),static_cast<uint16_t>(posY),static_cast<uint16_t>(posZ));
const Vector3DFloat gradFloor = computeSobelGradient(volIter);
if((posX - floorX) > 0.25) //The result should be 0.0 or 0.5
{
volIter.setPosition(static_cast<uint16_t>(posX+1.0),static_cast<uint16_t>(posY),static_cast<uint16_t>(posZ));
}
if((posY - floorY) > 0.25) //The result should be 0.0 or 0.5
{
volIter.setPosition(static_cast<uint16_t>(posX),static_cast<uint16_t>(posY+1.0),static_cast<uint16_t>(posZ));
}
if((posZ - floorZ) > 0.25) //The result should be 0.0 or 0.5
{
volIter.setPosition(static_cast<uint16_t>(posX),static_cast<uint16_t>(posY),static_cast<uint16_t>(posZ+1.0));
}
const Vector3DFloat gradCeil = computeSobelGradient(volIter);
result = ((gradFloor + gradCeil) * -1.0f);
if(result.lengthSquared() < 0.0001)
{
//Operation failed - fall back on simple gradient estimation
normalGenerationMethod = SIMPLE;
}
}
if(normalGenerationMethod == CENTRAL_DIFFERENCE)
{
volIter.setPosition(static_cast<uint16_t>(posX),static_cast<uint16_t>(posY),static_cast<uint16_t>(posZ));
const Vector3DFloat gradFloor = computeSmoothCentralDifferenceGradient(volIter);
if((posX - floorX) > 0.25) //The result should be 0.0 or 0.5
{
volIter.setPosition(static_cast<uint16_t>(posX+1.0),static_cast<uint16_t>(posY),static_cast<uint16_t>(posZ));
}
if((posY - floorY) > 0.25) //The result should be 0.0 or 0.5
{
volIter.setPosition(static_cast<uint16_t>(posX),static_cast<uint16_t>(posY+1.0),static_cast<uint16_t>(posZ));
}
if((posZ - floorZ) > 0.25) //The result should be 0.0 or 0.5
{
volIter.setPosition(static_cast<uint16_t>(posX),static_cast<uint16_t>(posY),static_cast<uint16_t>(posZ+1.0));
}
const Vector3DFloat gradCeil = computeSmoothCentralDifferenceGradient(volIter);
result = ((gradFloor + gradCeil) * -1.0f);
if(result.lengthSquared() < 0.0001)
{
//Operation failed - fall back on simple gradient estimation
normalGenerationMethod = SIMPLE;
}
}
if(normalGenerationMethod == SIMPLE)
{
volIter.setPosition(static_cast<uint16_t>(posX),static_cast<uint16_t>(posY),static_cast<uint16_t>(posZ));
const uint8_t uFloor = volIter.getVoxel() > 0 ? 1 : 0;
if((posX - floorX) > 0.25) //The result should be 0.0 or 0.5
{
uint8_t uCeil = volIter.peekVoxel1px0py0pz() > 0 ? 1 : 0;
result = Vector3DFloat(static_cast<float>(uFloor - uCeil),0.0,0.0);
}
else if((posY - floorY) > 0.25) //The result should be 0.0 or 0.5
{
uint8_t uCeil = volIter.peekVoxel0px1py0pz() > 0 ? 1 : 0;
result = Vector3DFloat(0.0,static_cast<float>(uFloor - uCeil),0.0);
}
else if((posZ - floorZ) > 0.25) //The result should be 0.0 or 0.5
{
uint8_t uCeil = volIter.peekVoxel0px0py1pz() > 0 ? 1 : 0;
result = Vector3DFloat(0.0, 0.0,static_cast<float>(uFloor - uCeil));
}
}
return result;
}
}

View File

@ -24,4 +24,7 @@ For Version 0.2
===============
Detect detatched regions.
Handle mesh generation for detatched regions.
Generate ambient lighting from volume?
Generate ambient lighting from volume?
Utility function for closing outside surfaces?
Consider how seperate surface should be generated for a single region.
Consider transparent materials like glass.