Improved support for borders in Volumes and VolumeSamplers.

More fixes for edge case handling in marching cubes.
This commit is contained in:
David Williams 2010-08-26 20:48:51 +00:00
parent a39cb23dc3
commit cc22b682fa
4 changed files with 61 additions and 57 deletions

View File

@ -91,7 +91,7 @@ namespace PolyVox
m_regSliceCurrent.shift(Vector3DInt16(0,0,1));
//Process the other slices (previous slice is available)
for(int16_t uSlice = 1; uSlice < m_regSizeInVoxels.depth(); uSlice++)
for(int16_t uSlice = 1; uSlice <= m_regSizeInVoxels.depth(); uSlice++)
{
computeBitmaskForSlice<true>(pPreviousBitmask, pCurrentBitmask);
uNoOfNonEmptyCellsForSlice1 = m_uNoOfOccupiedCells;
@ -119,15 +119,6 @@ namespace PolyVox
m_regSliceCurrent.shift(Vector3DInt16(0,0,1));
}
//A final slice just to close of the volume
if((uNoOfNonEmptyCellsForSlice0 != 0) || (uNoOfNonEmptyCellsForSlice1 != 0))
{
memset(m_pCurrentVertexIndicesX.getRawData(), 0xff, m_pCurrentVertexIndicesX.getNoOfElements() * 4);
memset(m_pCurrentVertexIndicesY.getRawData(), 0xff, m_pCurrentVertexIndicesY.getNoOfElements() * 4);
memset(m_pCurrentVertexIndicesZ.getRawData(), 0xff, m_pCurrentVertexIndicesZ.getNoOfElements() * 4);
generateIndicesForSlice(pPreviousBitmask, m_pPreviousVertexIndicesX, m_pPreviousVertexIndicesY, m_pPreviousVertexIndicesZ, m_pCurrentVertexIndicesX, m_pCurrentVertexIndicesY, m_pCurrentVertexIndicesZ);
}
m_meshCurrent->m_Region = m_regSizeInVoxels;
m_meshCurrent->m_vecLodRecords.clear();
@ -416,14 +407,14 @@ namespace PolyVox
bool isPosZEdge = (uZVolSpace == m_regSizeInVoxels.getUpperCorner().getZ());
//Iterate over each cell in the region
for(uint16_t uYVolSpace = m_regSliceCurrent.getLowerCorner().getY(); uYVolSpace <= m_regSliceCurrent.getUpperCorner().getY()-1; uYVolSpace++)
for(uint16_t uYVolSpace = m_regSliceCurrent.getLowerCorner().getY(); uYVolSpace <= m_regSliceCurrent.getUpperCorner().getY(); uYVolSpace++)
{
const uint16_t uYRegSpace = uYVolSpace - m_regSizeInVoxels.getLowerCorner().getY();
//bool isYEdge = ((uYVolSpace == m_regSizeInVoxelsCropped.getLowerCorner().getY()) || (uYVolSpace == m_regSizeInVoxelsCropped.getUpperCorner().getY()));
bool isNegYEdge = (uYVolSpace == m_regSizeInVoxels.getLowerCorner().getY());
bool isPosYEdge = (uYVolSpace == m_regSizeInVoxels.getUpperCorner().getY());
for(uint16_t uXVolSpace = m_regSliceCurrent.getLowerCorner().getX(); uXVolSpace <= m_regSliceCurrent.getUpperCorner().getX()-1; uXVolSpace++)
for(uint16_t uXVolSpace = m_regSliceCurrent.getLowerCorner().getX(); uXVolSpace <= m_regSliceCurrent.getUpperCorner().getX(); uXVolSpace++)
{
//Current position
const uint16_t uXRegSpace = uXVolSpace - m_regSizeInVoxels.getLowerCorner().getX();
@ -655,9 +646,9 @@ namespace PolyVox
indlist[i] = -1;
}
for(uint16_t uYVolSpace = m_regSlicePrevious.getLowerCorner().getY(); uYVolSpace < m_regSizeInVoxels.getUpperCorner().getY(); uYVolSpace++)
for(uint16_t uYVolSpace = m_regSlicePrevious.getLowerCorner().getY(); uYVolSpace <= m_regSizeInCells.getUpperCorner().getY(); uYVolSpace++)
{
for(uint16_t uXVolSpace = m_regSlicePrevious.getLowerCorner().getX(); uXVolSpace < m_regSizeInVoxels.getUpperCorner().getX(); uXVolSpace++)
for(uint16_t uXVolSpace = m_regSlicePrevious.getLowerCorner().getX(); uXVolSpace <= m_regSizeInCells.getUpperCorner().getX(); uXVolSpace++)
{
uint16_t uZVolSpace = m_regSlicePrevious.getLowerCorner().getZ();
m_sampVolume.setPosition(uXVolSpace,uYVolSpace,uZVolSpace);

View File

@ -32,8 +32,8 @@ freely, subject to the following restrictions:
#include <limits>
#include <map>
#include <vector>
#include <memory>
#include <vector>
#pragma endregion
@ -128,6 +128,8 @@ namespace PolyVox
///Destructor
~Volume();
///Gets the value used for voxels which are outside the volume
VoxelType getBorderValue(void) const;
///Gets a Region representing the extents of the Volume.
Region getEnclosingRegion(void) const;
///Gets the width of the volume in voxels.
@ -143,10 +145,12 @@ namespace PolyVox
///Gets the length of the diagonal in voxels
float getDiagonalLength(void) const;
///Gets a voxel by <tt>x,y,z</tt> position
VoxelType getVoxelAt(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos, VoxelType tDefault = VoxelType()) const;
VoxelType getVoxelAt(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos) const;
///Gets a voxel by 3D vector position
VoxelType getVoxelAt(const Vector3DUint16& v3dPos, VoxelType tDefault = VoxelType()) const;
///Sets the value used for voxels which are outside the volume
void setBorderValue(const VoxelType& tBorder);
///Sets the voxel at an <tt>x,y,z</tt> position
bool setVoxelAt(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos, VoxelType tValue);
///Sets the voxel at a 3D vector position
@ -157,6 +161,7 @@ namespace PolyVox
private:
std::shared_ptr< Block<VoxelType> > getHomogenousBlock(VoxelType tHomogenousValue);
std::shared_ptr< Block<VoxelType> > m_pBorderBlock;
std::vector< std::shared_ptr< Block<VoxelType> > > m_pBlocks;
std::vector<bool> m_vecBlockIsPotentiallyHomogenous;
@ -174,20 +179,14 @@ namespace PolyVox
uint16_t m_uDepthInBlocks;
uint16_t m_uWidth;
uint8_t m_uWidthPower;
uint16_t m_uHeight;
uint8_t m_uHeightPower;
uint16_t m_uHeight;
uint16_t m_uDepth;
uint8_t m_uDepthPower;
uint8_t m_uBlockSideLengthPower;
uint16_t m_uBlockSideLength;
uint16_t m_uLongestSideLength;
uint16_t m_uShortestSideLength;
float m_fDiagonalLength;
uint32_t m_uCurrentBlockForTidying;

View File

@ -66,19 +66,12 @@ namespace PolyVox
}
//Debug mode validation
assert(isPowerOf2(uWidth));
assert(isPowerOf2(uHeight));
assert(isPowerOf2(uDepth));
assert(isPowerOf2(uBlockSideLength));
assert(uBlockSideLength <= uWidth);
assert(uBlockSideLength <= uHeight);
assert(uBlockSideLength <= uDepth);
//Release mode validation
if(!(isPowerOf2(uWidth) && isPowerOf2(uHeight) && isPowerOf2(uDepth)))
{
throw std::invalid_argument("Volume width, height, and depth must all be a power of two.");
}
if(!isPowerOf2(uBlockSideLength))
{
throw std::invalid_argument("Block side length must be a power of two.");
@ -98,20 +91,19 @@ namespace PolyVox
//Compute the volume side lengths
m_uWidth = uWidth;
m_uWidthPower = logBase2(m_uWidth);
//m_uWidthPower = logBase2(m_uWidth);
m_uHeight = uHeight;
m_uHeightPower = logBase2(m_uHeight);
//m_uHeightPower = logBase2(m_uHeight);
m_uDepth = uDepth;
m_uDepthPower = logBase2(m_uDepth);
//m_uDepthPower = logBase2(m_uDepth);
//Compute the block side length
m_uBlockSideLength = uBlockSideLength;
m_uBlockSideLengthPower = logBase2(m_uBlockSideLength);
//Compute the side length in blocks
//m_uSideLengthInBlocks = m_uSideLength / m_uBlockSideLength;
//Compute the side lengths in blocks
m_uWidthInBlocks = m_uWidth / m_uBlockSideLength;
m_uHeightInBlocks = m_uHeight / m_uBlockSideLength;
m_uDepthInBlocks = m_uDepth / m_uBlockSideLength;
@ -128,6 +120,11 @@ namespace PolyVox
m_vecBlockIsPotentiallyHomogenous[i] = false;
}
//Create the border block
std::shared_ptr< Block<VoxelType> > pTempBlock(new Block<VoxelType>(m_uBlockSideLength));
pTempBlock->fill(VoxelType());
m_pBorderBlock = pTempBlock;
//Other properties we might find useful later
m_uLongestSideLength = (std::max)((std::max)(m_uWidth,m_uHeight),m_uDepth);
m_uShortestSideLength = (std::min)((std::min)(m_uWidth,m_uHeight),m_uDepth);
@ -147,6 +144,18 @@ namespace PolyVox
#pragma endregion
#pragma region Getters
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
////////////////////////////////////////////////////////////////////////////////
VoxelType Volume<VoxelType>::getBorderValue(void) const
{
return m_pBorderBlock->getVoxelAt(0,0,0);
}
////////////////////////////////////////////////////////////////////////////////
/// The result will always have a lower corner at (0,0,0) and an upper corner at one
/// less than the side length. For example, if a volume has dimensions 256x512x1024
@ -231,7 +240,7 @@ namespace PolyVox
/// \return the voxel value
////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType>
VoxelType Volume<VoxelType>::getVoxelAt(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos, VoxelType tDefault) const
VoxelType Volume<VoxelType>::getVoxelAt(uint16_t uXPos, uint16_t uYPos, uint16_t uZPos) const
{
//We don't use getEnclosingRegion here because we care
//about speed and don't need to check the lower bound.
@ -256,7 +265,7 @@ namespace PolyVox
}
else
{
return tDefault;
return getBorderValue();
}
}
@ -273,6 +282,15 @@ namespace PolyVox
#pragma endregion
#pragma region Setters
////////////////////////////////////////////////////////////////////////////////
/// \param tBorder The value to use for voxels outside the volume.
////////////////////////////////////////////////////////////////////////////////
template <typename VoxelType>
void Volume<VoxelType>::setBorderValue(const VoxelType& tBorder)
{
return m_pBorderBlock->fill(tBorder);
}
////////////////////////////////////////////////////////////////////////////////
/// \param uXPos the \c x position of the voxel
/// \param uYPos the \c y position of the voxel

View File

@ -156,15 +156,23 @@ namespace PolyVox
const uint16_t uYPosInBlock = mYPosInVolume - (uYBlock << mVolume->m_uBlockSideLengthPower);
const uint16_t uZPosInBlock = mZPosInVolume - (uZBlock << mVolume->m_uBlockSideLengthPower);
const uint32_t uBlockIndexInVolume = uXBlock +
uYBlock * mVolume->m_uWidthInBlocks +
uZBlock * mVolume->m_uWidthInBlocks * mVolume->m_uHeightInBlocks;
const std::shared_ptr< Block<VoxelType> >& currentBlock = mVolume->m_pBlocks[uBlockIndexInVolume];
const uint32_t uVoxelIndexInBlock = uXPosInBlock +
uYPosInBlock * mVolume->m_uBlockSideLength +
uZPosInBlock * mVolume->m_uBlockSideLength * mVolume->m_uBlockSideLength;
mCurrentVoxel = currentBlock->m_tData + uVoxelIndexInBlock;
uYPosInBlock * mVolume->m_uBlockSideLength +
uZPosInBlock * mVolume->m_uBlockSideLength * mVolume->m_uBlockSideLength;
if((uXBlock < mVolume->m_uWidthInBlocks) && (uYBlock < mVolume->m_uHeightInBlocks) && (uZBlock < mVolume->m_uDepthInBlocks))
{
const uint32_t uBlockIndexInVolume = uXBlock +
uYBlock * mVolume->m_uWidthInBlocks +
uZBlock * mVolume->m_uWidthInBlocks * mVolume->m_uHeightInBlocks;
const std::shared_ptr< Block<VoxelType> >& currentBlock = mVolume->m_pBlocks[uBlockIndexInVolume];
mCurrentVoxel = currentBlock->m_tData + uVoxelIndexInBlock;
}
else
{
mCurrentVoxel = mVolume->m_pBorderBlock->m_tData + uVoxelIndexInBlock;
}
}
#pragma endregion
@ -172,8 +180,6 @@ namespace PolyVox
template <typename VoxelType>
void VolumeSampler<VoxelType>::movePositiveX(void)
{
assert(mXPosInVolume < mVolume->m_uWidth - 1);
//Note the *pre* increament here
if((++mXPosInVolume) % mVolume->m_uBlockSideLength != 0)
{
@ -190,8 +196,6 @@ namespace PolyVox
template <typename VoxelType>
void VolumeSampler<VoxelType>::movePositiveY(void)
{
assert(mYPosInVolume < mVolume->m_uHeight - 1);
//Note the *pre* increament here
if((++mYPosInVolume) % mVolume->m_uBlockSideLength != 0)
{
@ -208,8 +212,6 @@ namespace PolyVox
template <typename VoxelType>
void VolumeSampler<VoxelType>::movePositiveZ(void)
{
assert(mZPosInVolume < mVolume->m_uDepth - 1);
//Note the *pre* increament here
if((++mZPosInVolume) % mVolume->m_uBlockSideLength != 0)
{
@ -226,8 +228,6 @@ namespace PolyVox
template <typename VoxelType>
void VolumeSampler<VoxelType>::moveNegativeX(void)
{
assert(mXPosInVolume > 0);
//Note the *post* increament here
if((mXPosInVolume--) % mVolume->m_uBlockSideLength != 0)
{
@ -244,8 +244,6 @@ namespace PolyVox
template <typename VoxelType>
void VolumeSampler<VoxelType>::moveNegativeY(void)
{
assert(mYPosInVolume > 0);
//Note the *post* increament here
if((mYPosInVolume--) % mVolume->m_uBlockSideLength != 0)
{
@ -262,8 +260,6 @@ namespace PolyVox
template <typename VoxelType>
void VolumeSampler<VoxelType>::moveNegativeZ(void)
{
assert(mZPosInVolume > 0);
//Note the *post* increament here
if((mZPosInVolume--) % mVolume->m_uBlockSideLength != 0)
{