From a1ac75022c01b104b1e8f86f1e8bac5e3f458221 Mon Sep 17 00:00:00 2001 From: David Williams Date: Sat, 15 Dec 2012 17:49:43 +0100 Subject: [PATCH 01/30] Initial changes required for Cubiquity. --- .../PolyVoxCore/CubicSurfaceExtractor.h | 9 +- .../PolyVoxCore/CubicSurfaceExtractor.inl | 66 +-- .../include/PolyVoxCore/DefaultIsQuadNeeded.h | 98 ++-- .../DefaultMarchingCubesController.h | 282 ++++++------ .../include/PolyVoxCore/Interpolation.h | 164 +++---- .../MarchingCubesSurfaceExtractor.h | 430 +++++++++--------- .../MarchingCubesSurfaceExtractor.inl | 101 ++-- .../PolyVoxCore/PolyVoxForwardDeclarations.h | 4 +- .../include/PolyVoxCore/SurfaceMesh.h | 4 +- .../include/PolyVoxCore/SurfaceMesh.inl | 6 +- .../include/PolyVoxCore/Vector.inl | 20 +- .../include/PolyVoxCore/VertexTypes.h | 92 +++- .../include/PolyVoxCore/VolumeResampler.inl | 2 +- library/PolyVoxCore/source/Impl/Utility.cpp | 130 +++--- library/PolyVoxCore/source/VertexTypes.cpp | 79 +--- 15 files changed, 734 insertions(+), 753 deletions(-) diff --git a/library/PolyVoxCore/include/PolyVoxCore/CubicSurfaceExtractor.h b/library/PolyVoxCore/include/PolyVoxCore/CubicSurfaceExtractor.h index 76f53f89..1c9f6cdd 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/CubicSurfaceExtractor.h +++ b/library/PolyVoxCore/include/PolyVoxCore/CubicSurfaceExtractor.h @@ -81,7 +81,7 @@ namespace PolyVox struct IndexAndMaterial { int32_t iIndex; - int32_t uMaterial; //Should actually use the material type here, but this is ok for now. + typename VolumeType::VoxelType uMaterial; }; enum FaceNames @@ -109,13 +109,12 @@ namespace PolyVox }; public: - CubicSurfaceExtractor(VolumeType* volData, Region region, SurfaceMesh* result, bool bMergeQuads = true, IsQuadNeeded isQuadNeeded = IsQuadNeeded()); - + CubicSurfaceExtractor(VolumeType* volData, Region region, SurfaceMesh >* result, bool bMergeQuads = true, IsQuadNeeded isQuadNeeded = IsQuadNeeded()); void execute(); private: - int32_t addVertex(float fX, float fY, float fZ, uint32_t uMaterial, Array<3, IndexAndMaterial>& existingVertices); + int32_t addVertex(float fX, float fY, float fZ, typename VolumeType::VoxelType uMaterial, Array<3, IndexAndMaterial>& existingVertices); bool performQuadMerging(std::list& quads); bool mergeQuads(Quad& q1, Quad& q2); @@ -128,7 +127,7 @@ namespace PolyVox Region m_regSizeInVoxels; //The surface patch we are currently filling. - SurfaceMesh* m_meshCurrent; + SurfaceMesh >* m_meshCurrent; //Used to avoid creating duplicate vertices. Array<3, IndexAndMaterial> m_previousSliceVertices; diff --git a/library/PolyVoxCore/include/PolyVoxCore/CubicSurfaceExtractor.inl b/library/PolyVoxCore/include/PolyVoxCore/CubicSurfaceExtractor.inl index 211498c9..8dbe3c4a 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/CubicSurfaceExtractor.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/CubicSurfaceExtractor.inl @@ -35,7 +35,7 @@ namespace PolyVox const uint32_t CubicSurfaceExtractor::MaxVerticesPerPosition = 6; template - CubicSurfaceExtractor::CubicSurfaceExtractor(VolumeType* volData, Region region, SurfaceMesh* result, bool bMergeQuads, IsQuadNeeded isQuadNeeded) + CubicSurfaceExtractor::CubicSurfaceExtractor(VolumeType* volData, Region region, SurfaceMesh >* result, bool bMergeQuads, IsQuadNeeded isQuadNeeded) :m_volData(volData) ,m_regSizeInVoxels(region) ,m_meshCurrent(result) @@ -58,6 +58,10 @@ namespace PolyVox memset(m_previousSliceVertices.getRawData(), 0xff, m_previousSliceVertices.getNoOfElements() * sizeof(IndexAndMaterial)); memset(m_currentSliceVertices.getRawData(), 0xff, m_currentSliceVertices.getNoOfElements() * sizeof(IndexAndMaterial)); + uint32_t uRegionWidth = m_regSizeInVoxels.getUpperCorner().getX() - m_regSizeInVoxels.getLowerCorner().getX() + 1; + uint32_t uRegionHeight = m_regSizeInVoxels.getUpperCorner().getY() - m_regSizeInVoxels.getLowerCorner().getY() + 1; + uint32_t uRegionDepth = m_regSizeInVoxels.getUpperCorner().getZ() - m_regSizeInVoxels.getLowerCorner().getZ() + 1; + m_vecQuads[NegativeX].resize(m_regSizeInVoxels.getUpperCorner().getX() - m_regSizeInVoxels.getLowerCorner().getX() + 2); m_vecQuads[PositiveX].resize(m_regSizeInVoxels.getUpperCorner().getX() - m_regSizeInVoxels.getLowerCorner().getX() + 2); @@ -83,7 +87,7 @@ namespace PolyVox volumeSampler.setPosition(x,y,z); - uint32_t material; //Filled in by callback + typename VolumeType::VoxelType material; //Filled in by callback typename VolumeType::VoxelType currentVoxel = volumeSampler.getVoxel(); typename VolumeType::VoxelType negXVoxel = volumeSampler.peekVoxel1nx0py0pz(); typename VolumeType::VoxelType negYVoxel = volumeSampler.peekVoxel0px1ny0pz(); @@ -92,20 +96,20 @@ namespace PolyVox // X if(m_funcIsQuadNeededCallback(currentVoxel, negXVoxel, material)) { - uint32_t v0 = addVertex(static_cast(regX) - 0.5f, static_cast(regY) - 0.5f, static_cast(regZ) - 0.5f, material, m_previousSliceVertices); - uint32_t v1 = addVertex(static_cast(regX) - 0.5f, static_cast(regY) - 0.5f, static_cast(regZ) + 0.5f, material, m_currentSliceVertices); - uint32_t v2 = addVertex(static_cast(regX) - 0.5f, static_cast(regY) + 0.5f, static_cast(regZ) + 0.5f, material, m_currentSliceVertices); - uint32_t v3 = addVertex(static_cast(regX) - 0.5f, static_cast(regY) + 0.5f, static_cast(regZ) - 0.5f, material, m_previousSliceVertices); + uint32_t v0 = addVertex(regX - 0.5f, regY - 0.5f, regZ - 0.5f, material, m_previousSliceVertices); + uint32_t v1 = addVertex(regX - 0.5f, regY - 0.5f, regZ + 0.5f, material, m_currentSliceVertices); + uint32_t v2 = addVertex(regX - 0.5f, regY + 0.5f, regZ + 0.5f, material, m_currentSliceVertices); + uint32_t v3 = addVertex(regX - 0.5f, regY + 0.5f, regZ - 0.5f, material, m_previousSliceVertices); m_vecQuads[NegativeX][regX].push_back(Quad(v0, v1, v2, v3)); } if(m_funcIsQuadNeededCallback(negXVoxel, currentVoxel, material)) { - uint32_t v0 = addVertex(static_cast(regX) - 0.5f, static_cast(regY) - 0.5f, static_cast(regZ) - 0.5f, material, m_previousSliceVertices); - uint32_t v1 = addVertex(static_cast(regX) - 0.5f, static_cast(regY) - 0.5f, static_cast(regZ) + 0.5f, material, m_currentSliceVertices); - uint32_t v2 = addVertex(static_cast(regX) - 0.5f, static_cast(regY) + 0.5f, static_cast(regZ) + 0.5f, material, m_currentSliceVertices); - uint32_t v3 = addVertex(static_cast(regX) - 0.5f, static_cast(regY) + 0.5f, static_cast(regZ) - 0.5f, material, m_previousSliceVertices); + uint32_t v0 = addVertex(regX - 0.5f, regY - 0.5f, regZ - 0.5f, material, m_previousSliceVertices); + uint32_t v1 = addVertex(regX - 0.5f, regY - 0.5f, regZ + 0.5f, material, m_currentSliceVertices); + uint32_t v2 = addVertex(regX - 0.5f, regY + 0.5f, regZ + 0.5f, material, m_currentSliceVertices); + uint32_t v3 = addVertex(regX - 0.5f, regY + 0.5f, regZ - 0.5f, material, m_previousSliceVertices); m_vecQuads[PositiveX][regX].push_back(Quad(v0, v3, v2, v1)); } @@ -113,20 +117,20 @@ namespace PolyVox // Y if(m_funcIsQuadNeededCallback(currentVoxel, negYVoxel, material)) { - uint32_t v0 = addVertex(static_cast(regX) - 0.5f, static_cast(regY) - 0.5f, static_cast(regZ) - 0.5f, material, m_previousSliceVertices); - uint32_t v1 = addVertex(static_cast(regX) + 0.5f, static_cast(regY) - 0.5f, static_cast(regZ) - 0.5f, material, m_previousSliceVertices); - uint32_t v2 = addVertex(static_cast(regX) + 0.5f, static_cast(regY) - 0.5f, static_cast(regZ) + 0.5f, material, m_currentSliceVertices); - uint32_t v3 = addVertex(static_cast(regX) - 0.5f, static_cast(regY) - 0.5f, static_cast(regZ) + 0.5f, material, m_currentSliceVertices); + uint32_t v0 = addVertex(regX - 0.5f, regY - 0.5f, regZ - 0.5f, material, m_previousSliceVertices); + uint32_t v1 = addVertex(regX + 0.5f, regY - 0.5f, regZ - 0.5f, material, m_previousSliceVertices); + uint32_t v2 = addVertex(regX + 0.5f, regY - 0.5f, regZ + 0.5f, material, m_currentSliceVertices); + uint32_t v3 = addVertex(regX - 0.5f, regY - 0.5f, regZ + 0.5f, material, m_currentSliceVertices); m_vecQuads[NegativeY][regY].push_back(Quad(v0, v1, v2, v3)); } if(m_funcIsQuadNeededCallback(negYVoxel, currentVoxel, material)) { - uint32_t v0 = addVertex(static_cast(regX) - 0.5f, static_cast(regY) - 0.5f, static_cast(regZ) - 0.5f, material, m_previousSliceVertices); - uint32_t v1 = addVertex(static_cast(regX) + 0.5f, static_cast(regY) - 0.5f, static_cast(regZ) - 0.5f, material, m_previousSliceVertices); - uint32_t v2 = addVertex(static_cast(regX) + 0.5f, static_cast(regY) - 0.5f, static_cast(regZ) + 0.5f, material, m_currentSliceVertices); - uint32_t v3 = addVertex(static_cast(regX) - 0.5f, static_cast(regY) - 0.5f, static_cast(regZ) + 0.5f, material, m_currentSliceVertices); + uint32_t v0 = addVertex(regX - 0.5f, regY - 0.5f, regZ - 0.5f, material, m_previousSliceVertices); + uint32_t v1 = addVertex(regX + 0.5f, regY - 0.5f, regZ - 0.5f, material, m_previousSliceVertices); + uint32_t v2 = addVertex(regX + 0.5f, regY - 0.5f, regZ + 0.5f, material, m_currentSliceVertices); + uint32_t v3 = addVertex(regX - 0.5f, regY - 0.5f, regZ + 0.5f, material, m_currentSliceVertices); m_vecQuads[PositiveY][regY].push_back(Quad(v0, v3, v2, v1)); } @@ -134,20 +138,20 @@ namespace PolyVox // Z if(m_funcIsQuadNeededCallback(currentVoxel, negZVoxel, material)) { - uint32_t v0 = addVertex(static_cast(regX) - 0.5f, static_cast(regY) - 0.5f, static_cast(regZ) - 0.5f, material, m_previousSliceVertices); - uint32_t v1 = addVertex(static_cast(regX) - 0.5f, static_cast(regY) + 0.5f, static_cast(regZ) - 0.5f, material, m_previousSliceVertices); - uint32_t v2 = addVertex(static_cast(regX) + 0.5f, static_cast(regY) + 0.5f, static_cast(regZ) - 0.5f, material, m_previousSliceVertices); - uint32_t v3 = addVertex(static_cast(regX) + 0.5f, static_cast(regY) - 0.5f, static_cast(regZ) - 0.5f, material, m_previousSliceVertices); + uint32_t v0 = addVertex(regX - 0.5f, regY - 0.5f, regZ - 0.5f, material, m_previousSliceVertices); + uint32_t v1 = addVertex(regX - 0.5f, regY + 0.5f, regZ - 0.5f, material, m_previousSliceVertices); + uint32_t v2 = addVertex(regX + 0.5f, regY + 0.5f, regZ - 0.5f, material, m_previousSliceVertices); + uint32_t v3 = addVertex(regX + 0.5f, regY - 0.5f, regZ - 0.5f, material, m_previousSliceVertices); m_vecQuads[NegativeZ][regZ].push_back(Quad(v0, v1, v2, v3)); } if(m_funcIsQuadNeededCallback(negZVoxel, currentVoxel, material)) { - uint32_t v0 = addVertex(static_cast(regX) - 0.5f, static_cast(regY) - 0.5f, static_cast(regZ) - 0.5f, material, m_previousSliceVertices); - uint32_t v1 = addVertex(static_cast(regX) - 0.5f, static_cast(regY) + 0.5f, static_cast(regZ) - 0.5f, material, m_previousSliceVertices); - uint32_t v2 = addVertex(static_cast(regX) + 0.5f, static_cast(regY) + 0.5f, static_cast(regZ) - 0.5f, material, m_previousSliceVertices); - uint32_t v3 = addVertex(static_cast(regX) + 0.5f, static_cast(regY) - 0.5f, static_cast(regZ) - 0.5f, material, m_previousSliceVertices); + uint32_t v0 = addVertex(regX - 0.5f, regY - 0.5f, regZ - 0.5f, material, m_previousSliceVertices); + uint32_t v1 = addVertex(regX - 0.5f, regY + 0.5f, regZ - 0.5f, material, m_previousSliceVertices); + uint32_t v2 = addVertex(regX + 0.5f, regY + 0.5f, regZ - 0.5f, material, m_previousSliceVertices); + uint32_t v3 = addVertex(regX + 0.5f, regY - 0.5f, regZ - 0.5f, material, m_previousSliceVertices); m_vecQuads[PositiveZ][regZ].push_back(Quad(v0, v3, v2, v1)); } @@ -184,7 +188,7 @@ namespace PolyVox } m_meshCurrent->m_Region = m_regSizeInVoxels; - m_meshCurrent->removeUnusedVertices(); + //m_meshCurrent->removeUnusedVertices(); m_meshCurrent->m_vecLodRecords.clear(); LodRecord lodRecord; @@ -194,7 +198,7 @@ namespace PolyVox } template - int32_t CubicSurfaceExtractor::addVertex(float fX, float fY, float fZ, uint32_t uMaterialIn, Array<3, IndexAndMaterial>& existingVertices) + int32_t CubicSurfaceExtractor::addVertex(float fX, float fY, float fZ, typename VolumeType::VoxelType uMaterialIn, Array<3, IndexAndMaterial>& existingVertices) { uint32_t uX = static_cast(fX + 0.75f); uint32_t uY = static_cast(fY + 0.75f); @@ -206,14 +210,14 @@ namespace PolyVox if(rEntry.iIndex == -1) { //No vertices matched and we've now hit an empty space. Fill it by creating a vertex. - rEntry.iIndex = m_meshCurrent->addVertex(PositionMaterial(Vector3DFloat(fX, fY, fZ), uMaterialIn)); + rEntry.iIndex = m_meshCurrent->addVertex(PositionMaterial (Vector3DFloat(fX, fY, fZ), uMaterialIn)); rEntry.uMaterial = uMaterialIn; return rEntry.iIndex; } //If we have an existing vertex and the material matches then we can return it. - if(rEntry.uMaterial == static_cast(uMaterialIn)) + if(rEntry.uMaterial == uMaterialIn) { return rEntry.iIndex; } @@ -260,7 +264,7 @@ namespace PolyVox { //All four vertices of a given quad have the same material, //so just check that the first pair of vertices match. - if(std::abs(m_meshCurrent->getVertices()[q1.vertices[0]].getMaterial() - m_meshCurrent->getVertices()[q2.vertices[0]].getMaterial()) < 0.001) + if(m_meshCurrent->getVertices()[q1.vertices[0]].getMaterial() == m_meshCurrent->getVertices()[q2.vertices[0]].getMaterial()) { //Now check whether quad 2 is adjacent to quad one by comparing vertices. //Adjacent quads must share two vertices, and the second quad could be to the diff --git a/library/PolyVoxCore/include/PolyVoxCore/DefaultIsQuadNeeded.h b/library/PolyVoxCore/include/PolyVoxCore/DefaultIsQuadNeeded.h index 81ddb9e5..ea6cf673 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/DefaultIsQuadNeeded.h +++ b/library/PolyVoxCore/include/PolyVoxCore/DefaultIsQuadNeeded.h @@ -1,50 +1,50 @@ -/******************************************************************************* -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_DefaultIsQuadNeeded_H__ -#define __PolyVox_DefaultIsQuadNeeded_H__ - -#include "PolyVoxCore/Impl/TypeDef.h" - -namespace PolyVox -{ - template - class DefaultIsQuadNeeded - { - public: - bool operator()(VoxelType back, VoxelType front, uint32_t& materialToUse) - { - if((back > 0) && (front == 0)) - { - materialToUse = static_cast(back); - return true; - } - else - { - return false; - } - } - }; -} - +/******************************************************************************* +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_DefaultIsQuadNeeded_H__ +#define __PolyVox_DefaultIsQuadNeeded_H__ + +#include "PolyVoxCore/Impl/TypeDef.h" + +namespace PolyVox +{ + template + class DefaultIsQuadNeeded + { + public: + bool operator()(VoxelType back, VoxelType front, float& materialToUse) + { + if((back > 0) && (front == 0)) + { + materialToUse = static_cast(back); + return true; + } + else + { + return false; + } + } + }; +} + #endif //__PolyVox_DefaultIsQuadNeeded_H__ \ No newline at end of file diff --git a/library/PolyVoxCore/include/PolyVoxCore/DefaultMarchingCubesController.h b/library/PolyVoxCore/include/PolyVoxCore/DefaultMarchingCubesController.h index 8d5359e9..43aa0956 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/DefaultMarchingCubesController.h +++ b/library/PolyVoxCore/include/PolyVoxCore/DefaultMarchingCubesController.h @@ -1,148 +1,134 @@ -/******************************************************************************* -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_MarchingCubesController_H__ -#define __PolyVox_MarchingCubesController_H__ - -#include "PolyVoxCore/BaseVolume.h" - -#include - -namespace PolyVox -{ - /** - * This class provides a default implementation of a controller for the MarchingCubesSurfaceExtractor. It controls the behaviour of the - * MarchingCubesSurfaceExtractor and provides the required properties from the underlying voxel type. - * - * PolyVox does not enforce any requirements regarding what data must be present in a voxel, and instead allows any primitive or user-defined - * type to be used. However, the Marching Cubes algorithm does have some requirents about the underlying data in that conceptually it operates - * on a density field. In addition, the PolyVox implementation of the Marching Cubes algorithm also understands the idea of each voxel - * having a material which is copied into the vertex data. - * - * Because we want the MarchingCubesSurfaceExtractor to work on any voxel type, we use a Marching Cubes controller (passed as - * a parameter of the MarchingCubesSurfaceExtractor) to expose the required properties. This parameter defaults to the DefaultMarchingCubesController. - * The main implementation of this class is designed to work with primitives data types, and the class is also specialised for the Material, - * Density and MaterialdensityPair classes. - * - * If you create a custom class for your voxel data then you probably want to include a specialisation of DefaultMarchingCubesController, - * though you don't have to if you don't want to use the Marching Cubes algorithm or if you prefer to define a seperate Marching Cubes controller - * and pass it as an explicit parameter (rather than relying on the default). - * - * For primitive types, the DefaultMarchingCubesController considers the value of the voxel to represent it's density and just returns a constant - * for the material. So you can, for example, run the MarchingCubesSurfaceExtractor on a volume of floats or ints. - * - * It is possible to customise the behaviour of the controller by providing a threshold value through the constructor. The extracted surface - * will pass through the density value specified by the threshold, and so you should make sure that the threshold value you choose is between - * the minimum and maximum values found in your volume data. By default it is in the middle of the representable range of the underlying type. - * - * \sa MarchingCubesSurfaceExtractor - * - */ - template - class DefaultMarchingCubesController - { - public: - /// Used to inform the MarchingCubesSurfaceExtractor about which type it should use for representing densities. - typedef VoxelType DensityType; - /// Used to inform the MarchingCubesSurfaceExtractor about which type it should use for representing materials. We're using a float here - /// because this implementation always returns a constant value off 1.0f. PolyVox also uses floats to store the materials in the mesh vertices - /// but this is not really desirable on modern hardware. We'll probably come back to material representation in the future. - typedef float MaterialType; - - /** - * Constructor - * - * This version of the constructor takes no parameters and sets the threshold to the middle of the representable range of the underlying type. - * For example, if the voxel type is 'uint8_t' then the representable range is 0-255, and the threshold will be set to 127. On the other hand, - * if the voxel type is 'float' then the representable range is -FLT_MAX to FLT_MAX and the threshold will be set to zero. - */ - DefaultMarchingCubesController(void) - :m_tThreshold(((std::numeric_limits::min)() + (std::numeric_limits::max)()) / 2) - ,m_eWrapMode(WrapModes::Border) - ,m_tBorder(VoxelType(0)) - { - } - - /** - * Converts the underlying voxel type into a density value. - * - * The default implementation of this function just returns the voxel type directly and is suitable for primitives types. Specialisations of - * this class can modify this behaviour. - */ - DensityType convertToDensity(VoxelType voxel) - { - return voxel; - } - - /** - * Converts the underlying voxel type into a material value. - * - * The default implementation of this function just returns the constant '1'. There's not much else it can do, as it needs to work with primitive - * types and the actual value of the type is already being considered to be the density. Specialisations of this class can modify this behaviour. - */ - MaterialType convertToMaterial(VoxelType /*voxel*/) - { - return 1; - } - - VoxelType getBorderValue(void) - { - return m_tBorder; - } - - /** - * Returns the density value which was passed to the constructor. - * - * As mentioned in the class description, the extracted surface will pass through the density value specified by the threshold, and so you - * should make sure that the threshold value you choose is between the minimum and maximum values found in your volume data. By default it - * is in the middle of the representable range of the underlying type. - */ - DensityType getThreshold(void) - { - return m_tThreshold; - } - - WrapMode getWrapMode(void) - { - return m_eWrapMode; - } - - void setThreshold(DensityType tThreshold) - { - m_tThreshold = tThreshold; - } - - void setWrapMode(WrapMode eWrapMode, VoxelType tBorder = VoxelType(0)) - { - m_eWrapMode = eWrapMode; - m_tBorder = tBorder; - } - - private: - DensityType m_tThreshold; - WrapMode m_eWrapMode; - VoxelType m_tBorder; - }; -} - -#endif +/******************************************************************************* +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_MarchingCubesController_H__ +#define __PolyVox_MarchingCubesController_H__ + +#include "PolyVoxCore/BaseVolume.h" + +#include + +namespace PolyVox +{ + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// This class provides a default implementation of a controller for the MarchingCubesSurfaceExtractor. It controls the behaviour of the + /// MarchingCubesSurfaceExtractor and provides the required properties from the underlying voxel type. + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// PolyVox does not enforce any requirements regarding what data must be present in a voxel, and instead allows any primitive or user-defined + /// type to be used. However, the Marching Cubes algorithm does have some requirents about the underlying data in that conceptually it operates + /// on a density field. In addition, the PolyVox implementation of the Marching Cubes algorithm also understands the idea of each voxel + /// having a material which is copied into the vertex data. + /// + /// Because we want the MarchingCubesSurfaceExtractor to work on any voxel type, we use a Marching Cubes controller (passed as + /// a parameter of the MarchingCubesSurfaceExtractor) to expose the required properties. This parameter defaults to the DefaultMarchingCubesController. + /// The main implementation of this class is designed to work with primitives data types, and the class is also specialised for the Material, + /// Density and MaterialdensityPair classes. + /// + /// If you create a custom class for your voxel data then you probably want to include a specialisation of DefaultMarchingCubesController, + /// though you don't have to if you don't want to use the Marching Cubes algorithm or if you prefer to define a seperate Marching Cubes controller + /// and pass it as an explicit parameter (rather than relying on the default). + /// + /// For primitive types, the DefaultMarchingCubesController considers the value of the voxel to represent it's density and just returns a constant + /// for the material. So you can, for example, run the MarchingCubesSurfaceExtractor on a volume of floats or ints. + /// + /// It is possible to customise the behaviour of the controller by providing a threshold value through the constructor. The extracted surface + /// will pass through the density value specified by the threshold, and so you should make sure that the threshold value you choose is between + /// the minimum and maximum values found in your volume data. By default it is in the middle of the representable range of the underlying type. + /// + /// \sa MarchingCubesSurfaceExtractor + /// + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + template + class DefaultMarchingCubesController + { + public: + /// Used to inform the MarchingCubesSurfaceExtractor about which type it should use for representing densities. + typedef VoxelType DensityType; + /// Used to inform the MarchingCubesSurfaceExtractor about which type it should use for representing materials. We're using a float here + /// because this implementation always returns a constant value off 1.0f. PolyVox also uses floats to store the materials in the mesh vertices + /// but this is not really desirable on modern hardware. We'll probably come back to material representation in the future. + typedef float MaterialType; + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// Constructor + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// This version of the constructor takes no parameters and sets the threshold to the middle of the representable range of the underlying type. + /// For example, if the voxel type is 'uint8_t' then the representable range is 0-255, and the threshold will be set to 127. On the other hand, + /// if the voxel type is 'float' then the representable range is -FLT_MAX to FLT_MAX and the threshold will be set to zero. + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + DefaultMarchingCubesController(void) + { + m_tThreshold = ((std::numeric_limits::min)() + (std::numeric_limits::max)()) / 2; + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// Constructor + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// This version of the constructor allows you to set a custom threshold. + /// \param tThreshold The threshold to use. + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + DefaultMarchingCubesController(DensityType tThreshold) + { + m_tThreshold = tThreshold; + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// Converts the underlying voxel type into a density value. + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// The default implementation of this function just returns the voxel type directly and is suitable for primitives types. Specialisations of + /// this class can modify this behaviour. + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + DensityType convertToDensity(VoxelType voxel) + { + return voxel; + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// Converts the underlying voxel type into a material value. + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// The default implementation of this function just returns the constant '1'. There's not much else it can do, as it needs to work with primitive + /// types and the actual value of the type is already being considered to be the density. Specialisations of this class can modify this behaviour. + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + MaterialType convertToMaterial(VoxelType voxel) + { + return 1; + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// Returns the density value which was passed to the constructor. + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// As mentioned in the class description, the extracted surface will pass through the density value specified by the threshold, and so you + /// should make sure that the threshold value you choose is between the minimum and maximum values found in your volume data. By default it + ///is in the middle of the representable range of the underlying type. + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + DensityType getThreshold(void) + { + return m_tThreshold; + } + + private: + DensityType m_tThreshold; + }; +} + +#endif diff --git a/library/PolyVoxCore/include/PolyVoxCore/Interpolation.h b/library/PolyVoxCore/include/PolyVoxCore/Interpolation.h index 5c76fe47..e52b321f 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/Interpolation.h +++ b/library/PolyVoxCore/include/PolyVoxCore/Interpolation.h @@ -1,82 +1,82 @@ -/******************************************************************************* -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_Interpolation_H__ -#define __PolyVox_Interpolation_H__ - -#include - -namespace PolyVox -{ - template - Type lerp( - const Type& v0,const Type& v1, - const float x) - { - assert((x >= 0.0f) && (x <= 1.0f)); - - //Interpolate along X - Type v0_1 = v0 + x * (v1 - v0); - - return v0_1; - } - - template - Type bilerp( - const Type& v00,const Type& v10,const Type& v01,const Type& v11, - const float x, const float y) - { - assert((x >= 0.0f) && (y >= 0.0f) && - (x <= 1.0f) && (y <= 1.0f)); - - // Linearly interpolate along x - Type v00_10 = lerp(v00, v10, x); - Type v01_11 = lerp(v01, v11, x); - - // And linearly interpolate the results along y - Type v00_10__v01_11 = lerp(v00_10, v01_11, y); - - return v00_10__v01_11; - } - - template - Type trilerp( - 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)); - - // Bilinearly interpolate along Y - Type v000_v100__v010_v110 = bilerp(v000, v100, v010, v110, x, y); - Type v001_v101__v011_v111 = bilerp(v001, v101, v011, v111, x, y); - - // And linearly interpolate the results along z - Type v000_v100__v010_v110____v001_v101__v011_v111 = lerp(v000_v100__v010_v110, v001_v101__v011_v111, z); - - return v000_v100__v010_v110____v001_v101__v011_v111; - } -} - -#endif //__PolyVox_Interpolation_H__ +/******************************************************************************* +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_Interpolation_H__ +#define __PolyVox_Interpolation_H__ + +#include + +namespace PolyVox +{ + template + Type lerp( + const Type& v0,const Type& v1, + const float x) + { + assert((x >= 0.0f) && (x <= 1.0f)); + + //Interpolate along X + Type v0_1 = (v1 - v0) * x + v0; + + return v0_1; + } + + template + Type bilerp( + const Type& v00,const Type& v10,const Type& v01,const Type& v11, + const float x, const float y) + { + assert((x >= 0.0f) && (y >= 0.0f) && + (x <= 1.0f) && (y <= 1.0f)); + + // Linearly interpolate along x + Type v00_10 = lerp(v00, v10, x); + Type v01_11 = lerp(v01, v11, x); + + // And linearly interpolate the results along y + Type v00_10__v01_11 = lerp(v00_10, v01_11, y); + + return v00_10__v01_11; + } + + template + Type trilerp( + 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)); + + // Bilinearly interpolate along Y + Type v000_v100__v010_v110 = bilerp(v000, v100, v010, v110, x, y); + Type v001_v101__v011_v111 = bilerp(v001, v101, v011, v111, x, y); + + // And linearly interpolate the results along z + Type v000_v100__v010_v110____v001_v101__v011_v111 = lerp(v000_v100__v010_v110, v001_v101__v011_v111, z); + + return v000_v100__v010_v110____v001_v101__v011_v111; + } +} + +#endif //__PolyVox_Interpolation_H__ diff --git a/library/PolyVoxCore/include/PolyVoxCore/MarchingCubesSurfaceExtractor.h b/library/PolyVoxCore/include/PolyVoxCore/MarchingCubesSurfaceExtractor.h index b0d7c694..6fa98986 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/MarchingCubesSurfaceExtractor.h +++ b/library/PolyVoxCore/include/PolyVoxCore/MarchingCubesSurfaceExtractor.h @@ -1,210 +1,220 @@ -/******************************************************************************* -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_SurfaceExtractor_H__ -#define __PolyVox_SurfaceExtractor_H__ - -#include "Impl/MarchingCubesTables.h" -#include "Impl/TypeDef.h" - -#include "PolyVoxCore/Array.h" -#include "PolyVoxCore/SurfaceMesh.h" -#include "PolyVoxCore/DefaultMarchingCubesController.h" - -namespace PolyVox -{ - template< typename VolumeType, typename Controller = DefaultMarchingCubesController > - class MarchingCubesSurfaceExtractor - { - public: - MarchingCubesSurfaceExtractor(VolumeType* volData, Region region, SurfaceMesh* result, Controller controller = Controller()); - - void execute(); - - private: - //Compute the cell bitmask for a particular slice in z. - template - uint32_t computeBitmaskForSlice(const Array2DUint8& pPreviousBitmask, Array2DUint8& pCurrentBitmask); - - //Compute the cell bitmask for a given cell. - template - void computeBitmaskForCell(const Array2DUint8& pPreviousBitmask, Array2DUint8& pCurrentBitmask, uint32_t uXRegSpace, uint32_t uYRegSpace); - - //Use the cell bitmasks to generate all the vertices needed for that slice - void generateVerticesForSlice(const Array2DUint8& pCurrentBitmask, - Array2DInt32& m_pCurrentVertexIndicesX, - Array2DInt32& m_pCurrentVertexIndicesY, - Array2DInt32& m_pCurrentVertexIndicesZ); - - //////////////////////////////////////////////////////////////////////////////// - // NOTE: These two functions are in the .h file rather than the .inl due to an apparent bug in VC2010. - //See http://stackoverflow.com/questions/1484885/strange-vc-compile-error-c2244 for details. - //////////////////////////////////////////////////////////////////////////////// - Vector3DFloat computeCentralDifferenceGradient(const typename VolumeType::Sampler& volIter) - { - //FIXME - Should actually use DensityType here, both in principle and because the maths may be - //faster (and to reduce casts). So it would be good to add a way to get DensityType from a voxel. - //But watch out for when the DensityType is unsigned and the difference could be negative. - float voxel1nx = static_cast(m_controller.convertToDensity(volIter.peekVoxel1nx0py0pz())); - float voxel1px = static_cast(m_controller.convertToDensity(volIter.peekVoxel1px0py0pz())); - - float voxel1ny = static_cast(m_controller.convertToDensity(volIter.peekVoxel0px1ny0pz())); - float voxel1py = static_cast(m_controller.convertToDensity(volIter.peekVoxel0px1py0pz())); - - float voxel1nz = static_cast(m_controller.convertToDensity(volIter.peekVoxel0px0py1nz())); - float voxel1pz = static_cast(m_controller.convertToDensity(volIter.peekVoxel0px0py1pz())); - - return Vector3DFloat - ( - voxel1nx - voxel1px, - voxel1ny - voxel1py, - voxel1nz - voxel1pz - ); - } - - Vector3DFloat computeSobelGradient(const typename VolumeType::Sampler& volIter) - { - static const int weights[3][3][3] = { { {2,3,2}, {3,6,3}, {2,3,2} }, { - {3,6,3}, {6,0,6}, {3,6,3} }, { {2,3,2}, {3,6,3}, {2,3,2} } }; - - //FIXME - Should actually use DensityType here, both in principle and because the maths may be - //faster (and to reduce casts). So it would be good to add a way to get DensityType from a voxel. - //But watch out for when the DensityType is unsigned and the difference could be negative. - const float pVoxel1nx1ny1nz = static_cast(m_controller.convertToDensity(volIter.peekVoxel1nx1ny1nz())); - const float pVoxel1nx1ny0pz = static_cast(m_controller.convertToDensity(volIter.peekVoxel1nx1ny0pz())); - const float pVoxel1nx1ny1pz = static_cast(m_controller.convertToDensity(volIter.peekVoxel1nx1ny1pz())); - const float pVoxel1nx0py1nz = static_cast(m_controller.convertToDensity(volIter.peekVoxel1nx0py1nz())); - const float pVoxel1nx0py0pz = static_cast(m_controller.convertToDensity(volIter.peekVoxel1nx0py0pz())); - const float pVoxel1nx0py1pz = static_cast(m_controller.convertToDensity(volIter.peekVoxel1nx0py1pz())); - const float pVoxel1nx1py1nz = static_cast(m_controller.convertToDensity(volIter.peekVoxel1nx1py1nz())); - const float pVoxel1nx1py0pz = static_cast(m_controller.convertToDensity(volIter.peekVoxel1nx1py0pz())); - const float pVoxel1nx1py1pz = static_cast(m_controller.convertToDensity(volIter.peekVoxel1nx1py1pz())); - - const float pVoxel0px1ny1nz = static_cast(m_controller.convertToDensity(volIter.peekVoxel0px1ny1nz())); - const float pVoxel0px1ny0pz = static_cast(m_controller.convertToDensity(volIter.peekVoxel0px1ny0pz())); - const float pVoxel0px1ny1pz = static_cast(m_controller.convertToDensity(volIter.peekVoxel0px1ny1pz())); - const float pVoxel0px0py1nz = static_cast(m_controller.convertToDensity(volIter.peekVoxel0px0py1nz())); - //const float pVoxel0px0py0pz = static_cast(m_controller.convertToDensity(volIter.peekVoxel0px0py0pz())); - const float pVoxel0px0py1pz = static_cast(m_controller.convertToDensity(volIter.peekVoxel0px0py1pz())); - const float pVoxel0px1py1nz = static_cast(m_controller.convertToDensity(volIter.peekVoxel0px1py1nz())); - const float pVoxel0px1py0pz = static_cast(m_controller.convertToDensity(volIter.peekVoxel0px1py0pz())); - const float pVoxel0px1py1pz = static_cast(m_controller.convertToDensity(volIter.peekVoxel0px1py1pz())); - - const float pVoxel1px1ny1nz = static_cast(m_controller.convertToDensity(volIter.peekVoxel1px1ny1nz())); - const float pVoxel1px1ny0pz = static_cast(m_controller.convertToDensity(volIter.peekVoxel1px1ny0pz())); - const float pVoxel1px1ny1pz = static_cast(m_controller.convertToDensity(volIter.peekVoxel1px1ny1pz())); - const float pVoxel1px0py1nz = static_cast(m_controller.convertToDensity(volIter.peekVoxel1px0py1nz())); - const float pVoxel1px0py0pz = static_cast(m_controller.convertToDensity(volIter.peekVoxel1px0py0pz())); - const float pVoxel1px0py1pz = static_cast(m_controller.convertToDensity(volIter.peekVoxel1px0py1pz())); - const float pVoxel1px1py1nz = static_cast(m_controller.convertToDensity(volIter.peekVoxel1px1py1nz())); - const float pVoxel1px1py0pz = static_cast(m_controller.convertToDensity(volIter.peekVoxel1px1py0pz())); - const float pVoxel1px1py1pz = static_cast(m_controller.convertToDensity(volIter.peekVoxel1px1py1pz())); - - const float xGrad(- weights[0][0][0] * pVoxel1nx1ny1nz - - weights[1][0][0] * pVoxel1nx1ny0pz - weights[2][0][0] * - pVoxel1nx1ny1pz - weights[0][1][0] * pVoxel1nx0py1nz - - weights[1][1][0] * pVoxel1nx0py0pz - weights[2][1][0] * - pVoxel1nx0py1pz - weights[0][2][0] * pVoxel1nx1py1nz - - weights[1][2][0] * pVoxel1nx1py0pz - weights[2][2][0] * - pVoxel1nx1py1pz + weights[0][0][2] * pVoxel1px1ny1nz + - weights[1][0][2] * pVoxel1px1ny0pz + weights[2][0][2] * - pVoxel1px1ny1pz + weights[0][1][2] * pVoxel1px0py1nz + - weights[1][1][2] * pVoxel1px0py0pz + weights[2][1][2] * - pVoxel1px0py1pz + weights[0][2][2] * pVoxel1px1py1nz + - weights[1][2][2] * pVoxel1px1py0pz + weights[2][2][2] * - pVoxel1px1py1pz); - - const float yGrad(- weights[0][0][0] * pVoxel1nx1ny1nz - - weights[1][0][0] * pVoxel1nx1ny0pz - weights[2][0][0] * - pVoxel1nx1ny1pz + weights[0][2][0] * pVoxel1nx1py1nz + - weights[1][2][0] * pVoxel1nx1py0pz + weights[2][2][0] * - pVoxel1nx1py1pz - weights[0][0][1] * pVoxel0px1ny1nz - - weights[1][0][1] * pVoxel0px1ny0pz - weights[2][0][1] * - pVoxel0px1ny1pz + weights[0][2][1] * pVoxel0px1py1nz + - weights[1][2][1] * pVoxel0px1py0pz + weights[2][2][1] * - pVoxel0px1py1pz - weights[0][0][2] * pVoxel1px1ny1nz - - weights[1][0][2] * pVoxel1px1ny0pz - weights[2][0][2] * - pVoxel1px1ny1pz + weights[0][2][2] * pVoxel1px1py1nz + - weights[1][2][2] * pVoxel1px1py0pz + weights[2][2][2] * - pVoxel1px1py1pz); - - const float zGrad(- weights[0][0][0] * pVoxel1nx1ny1nz + - weights[2][0][0] * pVoxel1nx1ny1pz - weights[0][1][0] * - pVoxel1nx0py1nz + weights[2][1][0] * pVoxel1nx0py1pz - - weights[0][2][0] * pVoxel1nx1py1nz + weights[2][2][0] * - pVoxel1nx1py1pz - weights[0][0][1] * pVoxel0px1ny1nz + - weights[2][0][1] * pVoxel0px1ny1pz - weights[0][1][1] * - pVoxel0px0py1nz + weights[2][1][1] * pVoxel0px0py1pz - - weights[0][2][1] * pVoxel0px1py1nz + weights[2][2][1] * - pVoxel0px1py1pz - weights[0][0][2] * pVoxel1px1ny1nz + - weights[2][0][2] * pVoxel1px1ny1pz - weights[0][1][2] * - pVoxel1px0py1nz + weights[2][1][2] * pVoxel1px0py1pz - - weights[0][2][2] * pVoxel1px1py1nz + weights[2][2][2] * - pVoxel1px1py1pz); - - //Note: The above actually give gradients going from low density to high density. - //For our normals we want the the other way around, so we switch the components as we return them. - return Vector3DFloat(-xGrad,-yGrad,-zGrad); - } - //////////////////////////////////////////////////////////////////////////////// - // End of compiler bug workaroumd. - //////////////////////////////////////////////////////////////////////////////// - - //Use the cell bitmasks to generate all the indices needed for that slice - void generateIndicesForSlice(const Array2DUint8& pPreviousBitmask, - const Array2DInt32& m_pPreviousVertexIndicesX, - const Array2DInt32& m_pPreviousVertexIndicesY, - const Array2DInt32& m_pPreviousVertexIndicesZ, - const Array2DInt32& m_pCurrentVertexIndicesX, - const Array2DInt32& m_pCurrentVertexIndicesY); - - //The volume data and a sampler to access it. - VolumeType* m_volData; - typename VolumeType::Sampler m_sampVolume; - - //Used to return the number of cells in a slice which contain triangles. - uint32_t m_uNoOfOccupiedCells; - - //The surface patch we are currently filling. - SurfaceMesh* m_meshCurrent; - - //Information about the region we are currently processing - Region m_regSizeInVoxels; - Region m_regSizeInCells; - /*Region m_regSizeInVoxelsCropped; - Region m_regSizeInVoxelsUncropped; - Region m_regVolumeCropped;*/ - Region m_regSlicePrevious; - Region m_regSliceCurrent; - - //Used to convert arbitrary voxel types in densities and materials. - Controller m_controller; - - //Our threshold value - typename Controller::DensityType m_tThreshold; - }; -} - -#include "PolyVoxCore/MarchingCubesSurfaceExtractor.inl" - -#endif +/******************************************************************************* +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_SurfaceExtractor_H__ +#define __PolyVox_SurfaceExtractor_H__ + +#include "Impl/MarchingCubesTables.h" +#include "Impl/TypeDef.h" + +#include "PolyVoxCore/Array.h" +#include "PolyVoxCore/SurfaceMesh.h" +#include "PolyVoxCore/DefaultMarchingCubesController.h" + +namespace PolyVox +{ + template< typename VolumeType, typename Controller = DefaultMarchingCubesController > + class MarchingCubesSurfaceExtractor + { + public: + MarchingCubesSurfaceExtractor(VolumeType* volData, Region region, SurfaceMesh >* result, Controller controller = Controller()); + + void execute(); + + private: + //Compute the cell bitmask for a particular slice in z. + template + uint32_t computeBitmaskForSlice(const Array2DUint8& pPreviousBitmask, Array2DUint8& pCurrentBitmask); + + //Compute the cell bitmask for a given cell. + template + void computeBitmaskForCell(const Array2DUint8& pPreviousBitmask, Array2DUint8& pCurrentBitmask); + + //Use the cell bitmasks to generate all the vertices needed for that slice + void generateVerticesForSlice(const Array2DUint8& pCurrentBitmask, + Array2DInt32& m_pCurrentVertexIndicesX, + Array2DInt32& m_pCurrentVertexIndicesY, + Array2DInt32& m_pCurrentVertexIndicesZ); + + //////////////////////////////////////////////////////////////////////////////// + // NOTE: These two functions are in the .h file rather than the .inl due to an apparent bug in VC2010. + //See http://stackoverflow.com/questions/1484885/strange-vc-compile-error-c2244 for details. + //////////////////////////////////////////////////////////////////////////////// + Vector3DFloat computeCentralDifferenceGradient(const typename VolumeType::Sampler& volIter) + { + //FIXME - Should actually use DensityType here, both in principle and because the maths may be + //faster (and to reduce casts). So it would be good to add a way to get DensityType from a voxel. + //But watch out for when the DensityType is unsigned and the difference could be negative. + float voxel1nx = static_cast(m_controller.convertToDensity(volIter.peekVoxel1nx0py0pz())); + float voxel1px = static_cast(m_controller.convertToDensity(volIter.peekVoxel1px0py0pz())); + + float voxel1ny = static_cast(m_controller.convertToDensity(volIter.peekVoxel0px1ny0pz())); + float voxel1py = static_cast(m_controller.convertToDensity(volIter.peekVoxel0px1py0pz())); + + float voxel1nz = static_cast(m_controller.convertToDensity(volIter.peekVoxel0px0py1nz())); + float voxel1pz = static_cast(m_controller.convertToDensity(volIter.peekVoxel0px0py1pz())); + + return Vector3DFloat + ( + voxel1nx - voxel1px, + voxel1ny - voxel1py, + voxel1nz - voxel1pz + ); + } + + Vector3DFloat computeSobelGradient(const typename VolumeType::Sampler& volIter) + { + static const int weights[3][3][3] = { { {2,3,2}, {3,6,3}, {2,3,2} }, { + {3,6,3}, {6,0,6}, {3,6,3} }, { {2,3,2}, {3,6,3}, {2,3,2} } }; + + //FIXME - Should actually use DensityType here, both in principle and because the maths may be + //faster (and to reduce casts). So it would be good to add a way to get DensityType from a voxel. + //But watch out for when the DensityType is unsigned and the difference could be negative. + const float pVoxel1nx1ny1nz = static_cast(m_controller.convertToDensity(volIter.peekVoxel1nx1ny1nz())); + const float pVoxel1nx1ny0pz = static_cast(m_controller.convertToDensity(volIter.peekVoxel1nx1ny0pz())); + const float pVoxel1nx1ny1pz = static_cast(m_controller.convertToDensity(volIter.peekVoxel1nx1ny1pz())); + const float pVoxel1nx0py1nz = static_cast(m_controller.convertToDensity(volIter.peekVoxel1nx0py1nz())); + const float pVoxel1nx0py0pz = static_cast(m_controller.convertToDensity(volIter.peekVoxel1nx0py0pz())); + const float pVoxel1nx0py1pz = static_cast(m_controller.convertToDensity(volIter.peekVoxel1nx0py1pz())); + const float pVoxel1nx1py1nz = static_cast(m_controller.convertToDensity(volIter.peekVoxel1nx1py1nz())); + const float pVoxel1nx1py0pz = static_cast(m_controller.convertToDensity(volIter.peekVoxel1nx1py0pz())); + const float pVoxel1nx1py1pz = static_cast(m_controller.convertToDensity(volIter.peekVoxel1nx1py1pz())); + + const float pVoxel0px1ny1nz = static_cast(m_controller.convertToDensity(volIter.peekVoxel0px1ny1nz())); + const float pVoxel0px1ny0pz = static_cast(m_controller.convertToDensity(volIter.peekVoxel0px1ny0pz())); + const float pVoxel0px1ny1pz = static_cast(m_controller.convertToDensity(volIter.peekVoxel0px1ny1pz())); + const float pVoxel0px0py1nz = static_cast(m_controller.convertToDensity(volIter.peekVoxel0px0py1nz())); + //const float pVoxel0px0py0pz = static_cast(m_controller.convertToDensity(volIter.peekVoxel0px0py0pz())); + const float pVoxel0px0py1pz = static_cast(m_controller.convertToDensity(volIter.peekVoxel0px0py1pz())); + const float pVoxel0px1py1nz = static_cast(m_controller.convertToDensity(volIter.peekVoxel0px1py1nz())); + const float pVoxel0px1py0pz = static_cast(m_controller.convertToDensity(volIter.peekVoxel0px1py0pz())); + const float pVoxel0px1py1pz = static_cast(m_controller.convertToDensity(volIter.peekVoxel0px1py1pz())); + + const float pVoxel1px1ny1nz = static_cast(m_controller.convertToDensity(volIter.peekVoxel1px1ny1nz())); + const float pVoxel1px1ny0pz = static_cast(m_controller.convertToDensity(volIter.peekVoxel1px1ny0pz())); + const float pVoxel1px1ny1pz = static_cast(m_controller.convertToDensity(volIter.peekVoxel1px1ny1pz())); + const float pVoxel1px0py1nz = static_cast(m_controller.convertToDensity(volIter.peekVoxel1px0py1nz())); + const float pVoxel1px0py0pz = static_cast(m_controller.convertToDensity(volIter.peekVoxel1px0py0pz())); + const float pVoxel1px0py1pz = static_cast(m_controller.convertToDensity(volIter.peekVoxel1px0py1pz())); + const float pVoxel1px1py1nz = static_cast(m_controller.convertToDensity(volIter.peekVoxel1px1py1nz())); + const float pVoxel1px1py0pz = static_cast(m_controller.convertToDensity(volIter.peekVoxel1px1py0pz())); + const float pVoxel1px1py1pz = static_cast(m_controller.convertToDensity(volIter.peekVoxel1px1py1pz())); + + const float xGrad(- weights[0][0][0] * pVoxel1nx1ny1nz - + weights[1][0][0] * pVoxel1nx1ny0pz - weights[2][0][0] * + pVoxel1nx1ny1pz - weights[0][1][0] * pVoxel1nx0py1nz - + weights[1][1][0] * pVoxel1nx0py0pz - weights[2][1][0] * + pVoxel1nx0py1pz - weights[0][2][0] * pVoxel1nx1py1nz - + weights[1][2][0] * pVoxel1nx1py0pz - weights[2][2][0] * + pVoxel1nx1py1pz + weights[0][0][2] * pVoxel1px1ny1nz + + weights[1][0][2] * pVoxel1px1ny0pz + weights[2][0][2] * + pVoxel1px1ny1pz + weights[0][1][2] * pVoxel1px0py1nz + + weights[1][1][2] * pVoxel1px0py0pz + weights[2][1][2] * + pVoxel1px0py1pz + weights[0][2][2] * pVoxel1px1py1nz + + weights[1][2][2] * pVoxel1px1py0pz + weights[2][2][2] * + pVoxel1px1py1pz); + + const float yGrad(- weights[0][0][0] * pVoxel1nx1ny1nz - + weights[1][0][0] * pVoxel1nx1ny0pz - weights[2][0][0] * + pVoxel1nx1ny1pz + weights[0][2][0] * pVoxel1nx1py1nz + + weights[1][2][0] * pVoxel1nx1py0pz + weights[2][2][0] * + pVoxel1nx1py1pz - weights[0][0][1] * pVoxel0px1ny1nz - + weights[1][0][1] * pVoxel0px1ny0pz - weights[2][0][1] * + pVoxel0px1ny1pz + weights[0][2][1] * pVoxel0px1py1nz + + weights[1][2][1] * pVoxel0px1py0pz + weights[2][2][1] * + pVoxel0px1py1pz - weights[0][0][2] * pVoxel1px1ny1nz - + weights[1][0][2] * pVoxel1px1ny0pz - weights[2][0][2] * + pVoxel1px1ny1pz + weights[0][2][2] * pVoxel1px1py1nz + + weights[1][2][2] * pVoxel1px1py0pz + weights[2][2][2] * + pVoxel1px1py1pz); + + const float zGrad(- weights[0][0][0] * pVoxel1nx1ny1nz + + weights[2][0][0] * pVoxel1nx1ny1pz - weights[0][1][0] * + pVoxel1nx0py1nz + weights[2][1][0] * pVoxel1nx0py1pz - + weights[0][2][0] * pVoxel1nx1py1nz + weights[2][2][0] * + pVoxel1nx1py1pz - weights[0][0][1] * pVoxel0px1ny1nz + + weights[2][0][1] * pVoxel0px1ny1pz - weights[0][1][1] * + pVoxel0px0py1nz + weights[2][1][1] * pVoxel0px0py1pz - + weights[0][2][1] * pVoxel0px1py1nz + weights[2][2][1] * + pVoxel0px1py1pz - weights[0][0][2] * pVoxel1px1ny1nz + + weights[2][0][2] * pVoxel1px1ny1pz - weights[0][1][2] * + pVoxel1px0py1nz + weights[2][1][2] * pVoxel1px0py1pz - + weights[0][2][2] * pVoxel1px1py1nz + weights[2][2][2] * + pVoxel1px1py1pz); + + //Note: The above actually give gradients going from low density to high density. + //For our normals we want the the other way around, so we switch the components as we return them. + return Vector3DFloat(-xGrad,-yGrad,-zGrad); + } + //////////////////////////////////////////////////////////////////////////////// + // End of compiler bug workaroumd. + //////////////////////////////////////////////////////////////////////////////// + + //Use the cell bitmasks to generate all the indices needed for that slice + void generateIndicesForSlice(const Array2DUint8& pPreviousBitmask, + const Array2DInt32& m_pPreviousVertexIndicesX, + const Array2DInt32& m_pPreviousVertexIndicesY, + const Array2DInt32& m_pPreviousVertexIndicesZ, + const Array2DInt32& m_pCurrentVertexIndicesX, + const Array2DInt32& m_pCurrentVertexIndicesY); + + //The volume data and a sampler to access it. + VolumeType* m_volData; + typename VolumeType::Sampler m_sampVolume; + + //Holds a position in volume space. + int32_t iXVolSpace; + int32_t iYVolSpace; + int32_t iZVolSpace; + + //Holds a position in region space. + uint32_t uXRegSpace; + uint32_t uYRegSpace; + uint32_t uZRegSpace; + + //Used to return the number of cells in a slice which contain triangles. + uint32_t m_uNoOfOccupiedCells; + + //The surface patch we are currently filling. + SurfaceMesh >* m_meshCurrent; + + //Information about the region we are currently processing + Region m_regSizeInVoxels; + Region m_regSizeInCells; + /*Region m_regSizeInVoxelsCropped; + Region m_regSizeInVoxelsUncropped; + Region m_regVolumeCropped;*/ + Region m_regSlicePrevious; + Region m_regSliceCurrent; + + //Our threshold value + typename Controller::DensityType m_tThreshold; + + //Used to convert arbitrary voxel types in densities and materials. + Controller m_controller; + }; +} + +#include "PolyVoxCore/MarchingCubesSurfaceExtractor.inl" + +#endif diff --git a/library/PolyVoxCore/include/PolyVoxCore/MarchingCubesSurfaceExtractor.inl b/library/PolyVoxCore/include/PolyVoxCore/MarchingCubesSurfaceExtractor.inl index 23617603..e9761d1e 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/MarchingCubesSurfaceExtractor.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/MarchingCubesSurfaceExtractor.inl @@ -24,19 +24,18 @@ freely, subject to the following restrictions: namespace PolyVox { template - MarchingCubesSurfaceExtractor::MarchingCubesSurfaceExtractor(VolumeType* volData, Region region, SurfaceMesh* result, Controller controller) + MarchingCubesSurfaceExtractor::MarchingCubesSurfaceExtractor(VolumeType* volData, Region region, SurfaceMesh >* result, Controller controller) :m_volData(volData) ,m_sampVolume(volData) ,m_meshCurrent(result) ,m_regSizeInVoxels(region) - ,m_controller(controller) - ,m_tThreshold(m_controller.getThreshold()) { //m_regSizeInVoxels.cropTo(m_volData->getEnclosingRegion()); m_regSizeInCells = m_regSizeInVoxels; m_regSizeInCells.setUpperCorner(m_regSizeInCells.getUpperCorner() - Vector3DInt32(1,1,1)); - m_sampVolume.setWrapMode(m_controller.getWrapMode(), m_controller.getBorderValue()); + m_controller = controller; + m_tThreshold = m_controller.getThreshold(); } template @@ -44,9 +43,9 @@ namespace PolyVox { m_meshCurrent->clear(); - const uint32_t uArrayWidth = m_regSizeInVoxels.getUpperCorner().getX() - m_regSizeInVoxels.getLowerCorner().getX() + 1; - const uint32_t uArrayHeight = m_regSizeInVoxels.getUpperCorner().getY() - m_regSizeInVoxels.getLowerCorner().getY() + 1; - const uint32_t arraySizes[2]= {uArrayWidth, uArrayHeight}; // Array dimensions + uint32_t uArrayWidth = m_regSizeInVoxels.getUpperCorner().getX() - m_regSizeInVoxels.getLowerCorner().getX() + 1; + uint32_t uArrayHeight = m_regSizeInVoxels.getUpperCorner().getY() - m_regSizeInVoxels.getLowerCorner().getY() + 1; + uint32_t arraySizes[2]= {uArrayWidth, uArrayHeight}; // Array dimensions //For edge indices Array2DInt32 m_pPreviousVertexIndicesX(arraySizes); @@ -137,18 +136,18 @@ namespace PolyVox const int32_t iMaxXVolSpace = m_regSliceCurrent.getUpperCorner().getX(); const int32_t iMaxYVolSpace = m_regSliceCurrent.getUpperCorner().getY(); - const int32_t iZVolSpace = m_regSliceCurrent.getLowerCorner().getZ(); + iZVolSpace = m_regSliceCurrent.getLowerCorner().getZ(); + uZRegSpace = iZVolSpace - m_regSizeInVoxels.getLowerCorner().getZ(); //Process the lower left corner - int32_t iYVolSpace = m_regSliceCurrent.getLowerCorner().getY(); - int32_t iXVolSpace = m_regSliceCurrent.getLowerCorner().getX(); + iYVolSpace = m_regSliceCurrent.getLowerCorner().getY(); + iXVolSpace = m_regSliceCurrent.getLowerCorner().getX(); - uint32_t uXRegSpace = iXVolSpace - m_regSizeInVoxels.getLowerCorner().getX(); - uint32_t uYRegSpace = iYVolSpace - m_regSizeInVoxels.getLowerCorner().getY(); + uXRegSpace = iXVolSpace - m_regSizeInVoxels.getLowerCorner().getX(); + uYRegSpace = iYVolSpace - m_regSizeInVoxels.getLowerCorner().getY(); - m_sampVolume.setPosition(iXVolSpace,iYVolSpace,iZVolSpace); - computeBitmaskForCell(pPreviousBitmask, pCurrentBitmask, uXRegSpace, uYRegSpace); + computeBitmaskForCell(pPreviousBitmask, pCurrentBitmask); //Process the edge where x is minimal. iXVolSpace = m_regSliceCurrent.getLowerCorner().getX(); @@ -160,7 +159,7 @@ namespace PolyVox m_sampVolume.movePositiveY(); - computeBitmaskForCell(pPreviousBitmask, pCurrentBitmask, uXRegSpace, uYRegSpace); + computeBitmaskForCell(pPreviousBitmask, pCurrentBitmask); } //Process the edge where y is minimal. @@ -173,7 +172,7 @@ namespace PolyVox m_sampVolume.movePositiveX(); - computeBitmaskForCell(pPreviousBitmask, pCurrentBitmask, uXRegSpace, uYRegSpace); + computeBitmaskForCell(pPreviousBitmask, pCurrentBitmask); } //Process all remaining elemnents of the slice. In this case, previous x and y values are always available @@ -187,7 +186,7 @@ namespace PolyVox m_sampVolume.movePositiveX(); - computeBitmaskForCell(pPreviousBitmask, pCurrentBitmask, uXRegSpace, uYRegSpace); + computeBitmaskForCell(pPreviousBitmask, pCurrentBitmask); } } @@ -196,7 +195,7 @@ namespace PolyVox template template - void MarchingCubesSurfaceExtractor::computeBitmaskForCell(const Array2DUint8& pPreviousBitmask, Array2DUint8& pCurrentBitmask, uint32_t uXRegSpace, uint32_t uYRegSpace) + void MarchingCubesSurfaceExtractor::computeBitmaskForCell(const Array2DUint8& pPreviousBitmask, Array2DUint8& pCurrentBitmask) { uint8_t iCubeIndex = 0; @@ -386,7 +385,7 @@ namespace PolyVox } //Save the bitmask - pCurrentBitmask[uXRegSpace][uYRegSpace] = iCubeIndex; + pCurrentBitmask[uXRegSpace][iYVolSpace- m_regSizeInVoxels.getLowerCorner().getY()] = iCubeIndex; if(edgeTable[iCubeIndex] != 0) { @@ -400,7 +399,7 @@ namespace PolyVox Array2DInt32& m_pCurrentVertexIndicesY, Array2DInt32& m_pCurrentVertexIndicesZ) { - const int32_t iZVolSpace = m_regSliceCurrent.getLowerCorner().getZ(); + int32_t iZVolSpace = m_regSliceCurrent.getLowerCorner().getZ(); //Iterate over each cell in the region for(int32_t iYVolSpace = m_regSliceCurrent.getLowerCorner().getY(); iYVolSpace <= m_regSliceCurrent.getUpperCorner().getY(); iYVolSpace++) @@ -413,7 +412,7 @@ namespace PolyVox const uint32_t uXRegSpace = iXVolSpace - m_regSizeInVoxels.getLowerCorner().getX(); //Determine the index into the edge table which tells us which vertices are inside of the surface - const uint8_t iCubeIndex = pCurrentBitmask[uXRegSpace][uYRegSpace]; + uint8_t iCubeIndex = pCurrentBitmask[uXRegSpace][uYRegSpace]; /* Cube is entirely in/out of the surface */ if (edgeTable[iCubeIndex] == 0) @@ -426,16 +425,16 @@ namespace PolyVox m_sampVolume.setPosition(iXVolSpace,iYVolSpace,iZVolSpace); const typename VolumeType::VoxelType v000 = m_sampVolume.getVoxel(); - const Vector3DFloat n000 = computeCentralDifferenceGradient(m_sampVolume); + const Vector3DFloat n000 = computeSobelGradient(m_sampVolume); /* Find the vertices where the surface intersects the cube */ if (edgeTable[iCubeIndex] & 1) { m_sampVolume.movePositiveX(); const typename VolumeType::VoxelType v100 = m_sampVolume.getVoxel(); - const Vector3DFloat n100 = computeCentralDifferenceGradient(m_sampVolume); + const Vector3DFloat n100 = computeSobelGradient(m_sampVolume); - const float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v000)) / static_cast(m_controller.convertToDensity(v100) - m_controller.convertToDensity(v000)); + float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v000)) / static_cast(m_controller.convertToDensity(v100) - m_controller.convertToDensity(v000)); const Vector3DFloat v3dPosition(static_cast(iXVolSpace - m_regSizeInVoxels.getLowerCorner().getX()) + fInterp, static_cast(iYVolSpace - m_regSizeInVoxels.getLowerCorner().getY()), static_cast(iZVolSpace - m_regSizeInCells.getLowerCorner().getZ())); @@ -445,12 +444,13 @@ namespace PolyVox //Choose one of the two materials to use for the vertex (we don't interpolate as interpolation of //material IDs does not make sense). We take the largest, so that if we are working on a material-only //volume we get the one which is non-zero. Both materials can be non-zero if our volume has a density component. - const typename Controller::MaterialType uMaterial000 = m_controller.convertToMaterial(v000); - const typename Controller::MaterialType uMaterial100 = m_controller.convertToMaterial(v100); - const typename Controller::MaterialType uMaterial = (std::max)(uMaterial000, uMaterial100); + typename Controller::MaterialType uMaterial000 = m_controller.convertToMaterial(v000); + typename Controller::MaterialType uMaterial100 = m_controller.convertToMaterial(v100); + //typename Controller::MaterialType uMaterial = (std::max)(uMaterial000, uMaterial100); + typename Controller::MaterialType uMaterial = m_controller.blendMaterials(uMaterial000, uMaterial100, fInterp); - const PositionMaterialNormal surfaceVertex(v3dPosition, v3dNormal, static_cast(uMaterial)); - const uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex); + PositionMaterialNormal surfaceVertex(v3dPosition, v3dNormal, uMaterial); + uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex); m_pCurrentVertexIndicesX[iXVolSpace - m_regSizeInVoxels.getLowerCorner().getX()][iYVolSpace - m_regSizeInVoxels.getLowerCorner().getY()] = uLastVertexIndex; m_sampVolume.moveNegativeX(); @@ -459,9 +459,9 @@ namespace PolyVox { m_sampVolume.movePositiveY(); const typename VolumeType::VoxelType v010 = m_sampVolume.getVoxel(); - const Vector3DFloat n010 = computeCentralDifferenceGradient(m_sampVolume); + const Vector3DFloat n010 = computeSobelGradient(m_sampVolume); - const float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v000)) / static_cast(m_controller.convertToDensity(v010) - m_controller.convertToDensity(v000)); + float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v000)) / static_cast(m_controller.convertToDensity(v010) - m_controller.convertToDensity(v000)); const Vector3DFloat v3dPosition(static_cast(iXVolSpace - m_regSizeInVoxels.getLowerCorner().getX()), static_cast(iYVolSpace - m_regSizeInVoxels.getLowerCorner().getY()) + fInterp, static_cast(iZVolSpace - m_regSizeInVoxels.getLowerCorner().getZ())); @@ -471,12 +471,13 @@ namespace PolyVox //Choose one of the two materials to use for the vertex (we don't interpolate as interpolation of //material IDs does not make sense). We take the largest, so that if we are working on a material-only //volume we get the one which is non-zero. Both materials can be non-zero if our volume has a density component. - const typename Controller::MaterialType uMaterial000 = m_controller.convertToMaterial(v000); - const typename Controller::MaterialType uMaterial010 = m_controller.convertToMaterial(v010); - const typename Controller::MaterialType uMaterial = (std::max)(uMaterial000, uMaterial010); + typename Controller::MaterialType uMaterial000 = m_controller.convertToMaterial(v000); + typename Controller::MaterialType uMaterial010 = m_controller.convertToMaterial(v010); + //typename Controller::MaterialType uMaterial = (std::max)(uMaterial000, uMaterial010); + typename Controller::MaterialType uMaterial = m_controller.blendMaterials(uMaterial000, uMaterial010, fInterp); - const PositionMaterialNormal surfaceVertex(v3dPosition, v3dNormal, static_cast(uMaterial)); - const uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex); + PositionMaterialNormal surfaceVertex(v3dPosition, v3dNormal, uMaterial); + uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex); m_pCurrentVertexIndicesY[iXVolSpace - m_regSizeInVoxels.getLowerCorner().getX()][iYVolSpace - m_regSizeInVoxels.getLowerCorner().getY()] = uLastVertexIndex; m_sampVolume.moveNegativeY(); @@ -485,9 +486,9 @@ namespace PolyVox { m_sampVolume.movePositiveZ(); const typename VolumeType::VoxelType v001 = m_sampVolume.getVoxel(); - const Vector3DFloat n001 = computeCentralDifferenceGradient(m_sampVolume); + const Vector3DFloat n001 = computeSobelGradient(m_sampVolume); - const float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v000)) / static_cast(m_controller.convertToDensity(v001) - m_controller.convertToDensity(v000)); + float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v000)) / static_cast(m_controller.convertToDensity(v001) - m_controller.convertToDensity(v000)); const Vector3DFloat v3dPosition(static_cast(iXVolSpace - m_regSizeInVoxels.getLowerCorner().getX()), static_cast(iYVolSpace - m_regSizeInVoxels.getLowerCorner().getY()), static_cast(iZVolSpace - m_regSizeInVoxels.getLowerCorner().getZ()) + fInterp); @@ -497,12 +498,13 @@ namespace PolyVox //Choose one of the two materials to use for the vertex (we don't interpolate as interpolation of //material IDs does not make sense). We take the largest, so that if we are working on a material-only //volume we get the one which is non-zero. Both materials can be non-zero if our volume has a density component. - const typename Controller::MaterialType uMaterial000 = m_controller.convertToMaterial(v000); - const typename Controller::MaterialType uMaterial001 = m_controller.convertToMaterial(v001); - const typename Controller::MaterialType uMaterial = (std::max)(uMaterial000, uMaterial001); + typename Controller::MaterialType uMaterial000 = m_controller.convertToMaterial(v000); + typename Controller::MaterialType uMaterial001 = m_controller.convertToMaterial(v001); + //typename Controller::MaterialType uMaterial = (std::max)(uMaterial000, uMaterial001); + typename Controller::MaterialType uMaterial = m_controller.blendMaterials(uMaterial000, uMaterial001, fInterp); - const PositionMaterialNormal surfaceVertex(v3dPosition, v3dNormal, static_cast(uMaterial)); - const uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex); + PositionMaterialNormal surfaceVertex(v3dPosition, v3dNormal, uMaterial); + uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex); m_pCurrentVertexIndicesZ[iXVolSpace - m_regSizeInVoxels.getLowerCorner().getX()][iYVolSpace - m_regSizeInVoxels.getLowerCorner().getY()] = uLastVertexIndex; m_sampVolume.moveNegativeZ(); @@ -525,12 +527,11 @@ namespace PolyVox indlist[i] = -1; } - const int32_t iZVolSpace = m_regSlicePrevious.getLowerCorner().getZ(); - for(int32_t iYVolSpace = m_regSlicePrevious.getLowerCorner().getY(); iYVolSpace <= m_regSizeInCells.getUpperCorner().getY(); iYVolSpace++) { for(int32_t iXVolSpace = m_regSlicePrevious.getLowerCorner().getX(); iXVolSpace <= m_regSizeInCells.getUpperCorner().getX(); iXVolSpace++) - { + { + int32_t iZVolSpace = m_regSlicePrevious.getLowerCorner().getZ(); m_sampVolume.setPosition(iXVolSpace,iYVolSpace,iZVolSpace); //Current position @@ -538,7 +539,7 @@ namespace PolyVox const uint32_t uYRegSpace = m_sampVolume.getPosition().getY() - m_regSizeInVoxels.getLowerCorner().getY(); //Determine the index into the edge table which tells us which vertices are inside of the surface - const uint8_t iCubeIndex = pPreviousBitmask[uXRegSpace][uYRegSpace]; + uint8_t iCubeIndex = pPreviousBitmask[uXRegSpace][uYRegSpace]; /* Cube is entirely in/out of the surface */ if (edgeTable[iCubeIndex] == 0) @@ -610,9 +611,9 @@ namespace PolyVox for (int i=0;triTable[iCubeIndex][i]!=-1;i+=3) { - const int32_t ind0 = indlist[triTable[iCubeIndex][i ]]; - const int32_t ind1 = indlist[triTable[iCubeIndex][i+1]]; - const int32_t ind2 = indlist[triTable[iCubeIndex][i+2]]; + int32_t ind0 = indlist[triTable[iCubeIndex][i ]]; + int32_t ind1 = indlist[triTable[iCubeIndex][i+1]]; + int32_t ind2 = indlist[triTable[iCubeIndex][i+2]]; if((ind0 != -1) && (ind1 != -1) && (ind2 != -1)) { diff --git a/library/PolyVoxCore/include/PolyVoxCore/PolyVoxForwardDeclarations.h b/library/PolyVoxCore/include/PolyVoxCore/PolyVoxForwardDeclarations.h index addaa962..b8d6b995 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/PolyVoxForwardDeclarations.h +++ b/library/PolyVoxCore/include/PolyVoxCore/PolyVoxForwardDeclarations.h @@ -110,12 +110,12 @@ namespace PolyVox //////////////////////////////////////////////////////////////////////////////// // PositionMaterial //////////////////////////////////////////////////////////////////////////////// - class PositionMaterial; + template class PositionMaterial; //////////////////////////////////////////////////////////////////////////////// // PositionMaterialNormal //////////////////////////////////////////////////////////////////////////////// - class PositionMaterialNormal; + template class PositionMaterialNormal; //////////////////////////////////////////////////////////////////////////////// // RawVolume diff --git a/library/PolyVoxCore/include/PolyVoxCore/SurfaceMesh.h b/library/PolyVoxCore/include/PolyVoxCore/SurfaceMesh.h index 9ccc58fb..ce96c227 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/SurfaceMesh.h +++ b/library/PolyVoxCore/include/PolyVoxCore/SurfaceMesh.h @@ -95,8 +95,8 @@ namespace PolyVox std::vector m_vecLodRecords; }; - template - polyvox_shared_ptr< SurfaceMesh > extractSubset(SurfaceMesh& inputMesh, std::set setMaterials); + /*template + polyvox_shared_ptr< SurfaceMesh > extractSubset(SurfaceMesh& inputMesh, std::set setMaterials);*/ } #include "PolyVoxCore/SurfaceMesh.inl" diff --git a/library/PolyVoxCore/include/PolyVoxCore/SurfaceMesh.inl b/library/PolyVoxCore/include/PolyVoxCore/SurfaceMesh.inl index 45d24ada..af9f852b 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/SurfaceMesh.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/SurfaceMesh.inl @@ -365,7 +365,7 @@ namespace PolyVox void SurfaceMesh::removeUnusedVertices(void) { std::vector isVertexUsed(m_vecVertices.size()); - fill(isVertexUsed.begin(), isVertexUsed.end(), false); + std::fill(isVertexUsed.begin(), isVertexUsed.end(), false); for(uint32_t triCt = 0; triCt < m_vecTriangleIndices.size(); triCt++) { @@ -394,7 +394,7 @@ namespace PolyVox } //Currently a free function - think where this needs to go. - template + /*template polyvox_shared_ptr< SurfaceMesh > extractSubset(SurfaceMesh& inputMesh, std::set setMaterials) { polyvox_shared_ptr< SurfaceMesh > result(new SurfaceMesh); @@ -460,7 +460,7 @@ namespace PolyVox result->m_vecLodRecords.push_back(lodRecord); return result; - } + }*/ template void SurfaceMesh::scaleVertices(float amount) diff --git a/library/PolyVoxCore/include/PolyVoxCore/Vector.inl b/library/PolyVoxCore/include/PolyVoxCore/Vector.inl index 09501f18..9e65543a 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/Vector.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/Vector.inl @@ -54,7 +54,7 @@ namespace PolyVox Vector::Vector(StorageType x, StorageType y) { #ifndef SWIGPYTHON // SWIG instantiates all constructors, unless we can find a way around that. Should we use SWIGIMPORT here, and then %import this file rather then %include it? - static_assert(Size == 2, "This constructor should only be used for vectors with two elements."); + //static_assert(Size == 2, "This constructor should only be used for vectors with two elements."); #endif m_tElements[0] = x; @@ -71,7 +71,7 @@ namespace PolyVox Vector::Vector(StorageType x, StorageType y, StorageType z) { #ifndef SWIGPYTHON // SWIG instantiates all constructors, unless we can find a way around that. Should we use SWIGIMPORT here, and then %import this file rather then %include it? - static_assert(Size == 3, "This constructor should only be used for vectors with three elements."); + //static_assert(Size == 3, "This constructor should only be used for vectors with three elements."); #endif m_tElements[0] = x; @@ -91,7 +91,7 @@ namespace PolyVox Vector::Vector(StorageType x, StorageType y, StorageType z, StorageType w) { #ifndef SWIGPYTHON // SWIG instantiates all constructors, unless we can find a way around that. Should we use SWIGIMPORT here, and then %import this file rather then %include it? - static_assert(Size == 4, "This constructor should only be used for vectors with four elements."); + //static_assert(Size == 4, "This constructor should only be used for vectors with four elements."); #endif m_tElements[0] = x; @@ -142,7 +142,7 @@ namespace PolyVox // vector with one element, and supporting this would cause confusion over the // behaviour of the constructor taking a single value, as this fills all elements // to that value rather than just the first one. - static_assert(Size > 1, "Vector must have a length greater than one."); + //static_assert(Size > 1, "Vector must have a length greater than one."); } /** @@ -449,7 +449,7 @@ namespace PolyVox inline StorageType Vector::getZ(void) const { #ifndef SWIGPYTHON // SWIG instantiates all getters, unless we can find a way around that. Should we use SWIGIMPORT here, and then %import this file rather then %include it? - static_assert(Size >= 3, "You can only get the 'z' component from a vector with at least three elements."); + //static_assert(Size >= 3, "You can only get the 'z' component from a vector with at least three elements."); #endif return m_tElements[2]; @@ -462,7 +462,7 @@ namespace PolyVox inline StorageType Vector::getW(void) const { #ifndef SWIGPYTHON // SWIG instantiates all getters, unless we can find a way around that. Should we use SWIGIMPORT here, and then %import this file rather then %include it? - static_assert(Size >= 4, "You can only get the 'w' component from a vector with at least four elements."); + //static_assert(Size >= 4, "You can only get the 'w' component from a vector with at least four elements."); #endif return m_tElements[3]; @@ -502,7 +502,7 @@ namespace PolyVox inline void Vector::setElements(StorageType x, StorageType y, StorageType z) { #ifndef SWIGPYTHON // SWIG instantiates all setters, unless we can find a way around that. Should we use SWIGIMPORT here, and then %import this file rather then %include it? - static_assert(Size >= 3, "You can only use this version of setElements() on a vector with at least three elements."); + //static_assert(Size >= 3, "You can only use this version of setElements() on a vector with at least three elements."); #endif m_tElements[0] = x; m_tElements[1] = y; @@ -520,7 +520,7 @@ namespace PolyVox inline void Vector::setElements(StorageType x, StorageType y, StorageType z, StorageType w) { #ifndef SWIGPYTHON // SWIG instantiates all setters, unless we can find a way around that. Should we use SWIGIMPORT here, and then %import this file rather then %include it? - static_assert(Size >= 4, "You can only use this version of setElements() on a vector with at least four elements."); + //static_assert(Size >= 4, "You can only use this version of setElements() on a vector with at least four elements."); #endif m_tElements[0] = x; m_tElements[1] = y; @@ -553,7 +553,7 @@ namespace PolyVox inline void Vector::setZ(StorageType tZ) { #ifndef SWIGPYTHON // SWIG instantiates all setters, unless we can find a way around that. Should we use SWIGIMPORT here, and then %import this file rather then %include it? - static_assert(Size >= 3, "You can only set the 'w' component from a vector with at least three elements."); + //static_assert(Size >= 3, "You can only set the 'w' component from a vector with at least three elements."); #endif m_tElements[2] = tZ; } @@ -565,7 +565,7 @@ namespace PolyVox inline void Vector::setW(StorageType tW) { #ifndef SWIGPYTHON // SWIG instantiates all setters, unless we can find a way around that. Should we use SWIGIMPORT here, and then %import this file rather then %include it? - static_assert(Size >= 4, "You can only set the 'w' component from a vector with at least four elements."); + //static_assert(Size >= 4, "You can only set the 'w' component from a vector with at least four elements."); #endif m_tElements[3] = tW; } diff --git a/library/PolyVoxCore/include/PolyVoxCore/VertexTypes.h b/library/PolyVoxCore/include/PolyVoxCore/VertexTypes.h index 033fad6b..3eb18072 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/VertexTypes.h +++ b/library/PolyVoxCore/include/PolyVoxCore/VertexTypes.h @@ -36,49 +36,107 @@ namespace PolyVox #ifdef SWIG class PositionMaterial #else + template class POLYVOX_API PositionMaterial #endif { public: - PositionMaterial(); - PositionMaterial(Vector3DFloat positionToSet, float materialToSet); + PositionMaterial() + { + } - float getMaterial(void) const; - const Vector3DFloat& getPosition(void) const; + PositionMaterial(Vector3DFloat positionToSet, MaterialType materialToSet) + :position(positionToSet) + ,material(materialToSet) + { + } - void setMaterial(float materialToSet); - void setPosition(const Vector3DFloat& positionToSet); + MaterialType getMaterial(void) const + { + return material; + } + + const Vector3DFloat& getPosition(void) const + { + return position; + } + + void setMaterial(MaterialType materialToSet) + { + material = materialToSet; + } + + void setPosition(const Vector3DFloat& positionToSet) + { + position = positionToSet; + } public: //Nicely fits into four floats. Vector3DFloat position; - float material; + MaterialType material; }; #ifdef SWIG class PositionMaterialNormal #else + template class POLYVOX_API PositionMaterialNormal #endif { public: - PositionMaterialNormal(); - PositionMaterialNormal(Vector3DFloat positionToSet, float materialToSet); - PositionMaterialNormal(Vector3DFloat positionToSet, Vector3DFloat normalToSet, float materialToSet); + PositionMaterialNormal() + { + } - float getMaterial(void) const; - const Vector3DFloat& getNormal(void) const; - const Vector3DFloat& getPosition(void) const; + PositionMaterialNormal(Vector3DFloat positionToSet, MaterialType materialToSet) + :position(positionToSet) + ,material(materialToSet) + { + } - void setMaterial(float materialToSet); - void setNormal(const Vector3DFloat& normalToSet); - void setPosition(const Vector3DFloat& positionToSet); + PositionMaterialNormal(Vector3DFloat positionToSet, Vector3DFloat normalToSet, MaterialType materialToSet) + :position(positionToSet) + ,normal(normalToSet) + ,material(materialToSet) + { + } + + MaterialType getMaterial(void) const + { + return material; + } + + const Vector3DFloat& getNormal(void) const + { + return normal; + } + + const Vector3DFloat& getPosition(void) const + { + return position; + } + + void setMaterial(MaterialType materialToSet) + { + material = materialToSet; + } + + void setNormal(const Vector3DFloat& normalToSet) + { + normal = normalToSet; + } + + void setPosition(const Vector3DFloat& positionToSet) + { + position = positionToSet; + } public: //Nicely fits into seven floats, meaning we //can squeeze in one more for material blending. Vector3DFloat position; Vector3DFloat normal; - float material; //FIXME: This shouldn't be float on CPU? + MaterialType material; //FIXME: This shouldn't be float on CPU? }; } diff --git a/library/PolyVoxCore/include/PolyVoxCore/VolumeResampler.inl b/library/PolyVoxCore/include/PolyVoxCore/VolumeResampler.inl index b76281b9..72dcc573 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/VolumeResampler.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/VolumeResampler.inl @@ -127,7 +127,7 @@ namespace PolyVox sy = modf(sy, &dummy); sz = modf(sz, &dummy); - typename SrcVolumeType::VoxelType tInterpolatedValue = trilerp(voxel000,voxel100,voxel010,voxel110,voxel001,voxel101,voxel011,voxel111,sx,sy,sz); + typename SrcVolumeType::VoxelType tInterpolatedValue = trilerp(voxel000,voxel100,voxel010,voxel110,voxel001,voxel101,voxel011,voxel111,sx,sy,sz); typename DstVolumeType::VoxelType result = static_cast(tInterpolatedValue); m_pVolDst->setVoxelAt(dx,dy,dz,result); diff --git a/library/PolyVoxCore/source/Impl/Utility.cpp b/library/PolyVoxCore/source/Impl/Utility.cpp index 6e907ab9..a56d0210 100644 --- a/library/PolyVoxCore/source/Impl/Utility.cpp +++ b/library/PolyVoxCore/source/Impl/Utility.cpp @@ -1,65 +1,65 @@ -/******************************************************************************* -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 "PolyVoxCore/Impl/Utility.h" - -#include -#include - -namespace PolyVox -{ - //Note: this function only works for inputs which are a power of two and not zero - //If this is not the case then the output is undefined. - uint8_t logBase2(uint32_t uInput) - { - //Debug mode validation - assert(uInput != 0); - assert(isPowerOf2(uInput)); - - //Release mode validation - if(uInput == 0) - { - throw std::invalid_argument("Cannot compute the log of zero."); - } - if(!isPowerOf2(uInput)) - { - throw std::invalid_argument("Input must be a power of two in order to compute the log."); - } - - uint32_t uResult = 0; - while( (uInput >> uResult) != 0) - { - ++uResult; - } - return static_cast(uResult-1); - } - - - bool isPowerOf2(uint32_t uInput) - { - if(uInput == 0) - return false; - else - return ((uInput & (uInput-1)) == 0); - } -} +/******************************************************************************* +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 "PolyVoxCore/Impl/Utility.h" + +#include +#include + +namespace PolyVox +{ + //Note: this function only works for inputs which are a power of two and not zero + //If this is not the case then the output is undefined. + uint8_t logBase2(uint32_t uInput) + { + //Debug mode validation + assert(uInput != 0); + assert(isPowerOf2(uInput)); + + //Release mode validation + if(uInput == 0) + { + //throw std::invalid_argument("Cannot compute the log of zero."); + } + if(!isPowerOf2(uInput)) + { + //throw std::invalid_argument("Input must be a power of two in order to compute the log."); + } + + uint32_t uResult = 0; + while( (uInput >> uResult) != 0) + { + ++uResult; + } + return static_cast(uResult-1); + } + + + bool isPowerOf2(uint32_t uInput) + { + if(uInput == 0) + return false; + else + return ((uInput & (uInput-1)) == 0); + } +} diff --git a/library/PolyVoxCore/source/VertexTypes.cpp b/library/PolyVoxCore/source/VertexTypes.cpp index db41759e..b4dca237 100644 --- a/library/PolyVoxCore/source/VertexTypes.cpp +++ b/library/PolyVoxCore/source/VertexTypes.cpp @@ -25,86 +25,9 @@ freely, subject to the following restrictions: namespace PolyVox { - PositionMaterialNormal::PositionMaterialNormal() - { - } - - PositionMaterialNormal::PositionMaterialNormal(Vector3DFloat positionToSet, float materialToSet) - :position(positionToSet) - ,material(materialToSet) - { - - } - - PositionMaterialNormal::PositionMaterialNormal(Vector3DFloat positionToSet, Vector3DFloat normalToSet, float materialToSet) - :position(positionToSet) - ,normal(normalToSet) - ,material(materialToSet) - { - } - - float PositionMaterialNormal::getMaterial(void) const - { - return material; - } - - const Vector3DFloat& PositionMaterialNormal::getNormal(void) const - { - return normal; - } - - const Vector3DFloat& PositionMaterialNormal::getPosition(void) const - { - return position; - } - - void PositionMaterialNormal::setMaterial(float materialToSet) - { - material = materialToSet; - } - - void PositionMaterialNormal::setNormal(const Vector3DFloat& normalToSet) - { - normal = normalToSet; - } - - void PositionMaterialNormal::setPosition(const Vector3DFloat& positionToSet) - { - position = positionToSet; - } - //////////////////////////////////////////////////////////////////////////////// // PositionMaterial //////////////////////////////////////////////////////////////////////////////// - PositionMaterial::PositionMaterial() - { - } - - PositionMaterial::PositionMaterial(Vector3DFloat positionToSet, float materialToSet) - :position(positionToSet) - ,material(materialToSet) - { - - } - - float PositionMaterial::getMaterial(void) const - { - return material; - } - - const Vector3DFloat& PositionMaterial::getPosition(void) const - { - return position; - } - - void PositionMaterial::setMaterial(float materialToSet) - { - material = materialToSet; - } - - void PositionMaterial::setPosition(const Vector3DFloat& positionToSet) - { - position = positionToSet; - } + } From 342efec3faa5ac13e20a8048519be5b046a0ba7b Mon Sep 17 00:00:00 2001 From: David Williams Date: Sun, 16 Dec 2012 14:43:18 +0100 Subject: [PATCH 02/30] More merging for Cubiquity version of PolyVox. --- .../DefaultMarchingCubesController.h | 150 +- .../MarchingCubesSurfaceExtractor.inl | 1254 +++++++++-------- 2 files changed, 710 insertions(+), 694 deletions(-) diff --git a/library/PolyVoxCore/include/PolyVoxCore/DefaultMarchingCubesController.h b/library/PolyVoxCore/include/PolyVoxCore/DefaultMarchingCubesController.h index 43aa0956..fd0d00ef 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/DefaultMarchingCubesController.h +++ b/library/PolyVoxCore/include/PolyVoxCore/DefaultMarchingCubesController.h @@ -30,34 +30,34 @@ freely, subject to the following restrictions: namespace PolyVox { - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// This class provides a default implementation of a controller for the MarchingCubesSurfaceExtractor. It controls the behaviour of the - /// MarchingCubesSurfaceExtractor and provides the required properties from the underlying voxel type. - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// PolyVox does not enforce any requirements regarding what data must be present in a voxel, and instead allows any primitive or user-defined - /// type to be used. However, the Marching Cubes algorithm does have some requirents about the underlying data in that conceptually it operates - /// on a density field. In addition, the PolyVox implementation of the Marching Cubes algorithm also understands the idea of each voxel - /// having a material which is copied into the vertex data. - /// - /// Because we want the MarchingCubesSurfaceExtractor to work on any voxel type, we use a Marching Cubes controller (passed as - /// a parameter of the MarchingCubesSurfaceExtractor) to expose the required properties. This parameter defaults to the DefaultMarchingCubesController. - /// The main implementation of this class is designed to work with primitives data types, and the class is also specialised for the Material, - /// Density and MaterialdensityPair classes. - /// - /// If you create a custom class for your voxel data then you probably want to include a specialisation of DefaultMarchingCubesController, - /// though you don't have to if you don't want to use the Marching Cubes algorithm or if you prefer to define a seperate Marching Cubes controller - /// and pass it as an explicit parameter (rather than relying on the default). - /// - /// For primitive types, the DefaultMarchingCubesController considers the value of the voxel to represent it's density and just returns a constant - /// for the material. So you can, for example, run the MarchingCubesSurfaceExtractor on a volume of floats or ints. - /// - /// It is possible to customise the behaviour of the controller by providing a threshold value through the constructor. The extracted surface - /// will pass through the density value specified by the threshold, and so you should make sure that the threshold value you choose is between - /// the minimum and maximum values found in your volume data. By default it is in the middle of the representable range of the underlying type. - /// - /// \sa MarchingCubesSurfaceExtractor - /// - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * This class provides a default implementation of a controller for the MarchingCubesSurfaceExtractor. It controls the behaviour of the + * MarchingCubesSurfaceExtractor and provides the required properties from the underlying voxel type. + * + * PolyVox does not enforce any requirements regarding what data must be present in a voxel, and instead allows any primitive or user-defined + * type to be used. However, the Marching Cubes algorithm does have some requirents about the underlying data in that conceptually it operates + * on a density field. In addition, the PolyVox implementation of the Marching Cubes algorithm also understands the idea of each voxel + * having a material which is copied into the vertex data. + * + * Because we want the MarchingCubesSurfaceExtractor to work on any voxel type, we use a Marching Cubes controller (passed as + * a parameter of the MarchingCubesSurfaceExtractor) to expose the required properties. This parameter defaults to the DefaultMarchingCubesController. + * The main implementation of this class is designed to work with primitives data types, and the class is also specialised for the Material, + * Density and MaterialdensityPair classes. + * + * If you create a custom class for your voxel data then you probably want to include a specialisation of DefaultMarchingCubesController, + * though you don't have to if you don't want to use the Marching Cubes algorithm or if you prefer to define a seperate Marching Cubes controller + * and pass it as an explicit parameter (rather than relying on the default). + * + * For primitive types, the DefaultMarchingCubesController considers the value of the voxel to represent it's density and just returns a constant + * for the material. So you can, for example, run the MarchingCubesSurfaceExtractor on a volume of floats or ints. + * + * It is possible to customise the behaviour of the controller by providing a threshold value through the constructor. The extracted surface + * will pass through the density value specified by the threshold, and so you should make sure that the threshold value you choose is between + * the minimum and maximum values found in your volume data. By default it is in the middle of the representable range of the underlying type. + * + * \sa MarchingCubesSurfaceExtractor + * + */ template class DefaultMarchingCubesController { @@ -69,65 +69,79 @@ namespace PolyVox /// but this is not really desirable on modern hardware. We'll probably come back to material representation in the future. typedef float MaterialType; - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// Constructor - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// This version of the constructor takes no parameters and sets the threshold to the middle of the representable range of the underlying type. - /// For example, if the voxel type is 'uint8_t' then the representable range is 0-255, and the threshold will be set to 127. On the other hand, - /// if the voxel type is 'float' then the representable range is -FLT_MAX to FLT_MAX and the threshold will be set to zero. - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Constructor + * + * This version of the constructor takes no parameters and sets the threshold to the middle of the representable range of the underlying type. + * For example, if the voxel type is 'uint8_t' then the representable range is 0-255, and the threshold will be set to 127. On the other hand, + * if the voxel type is 'float' then the representable range is -FLT_MAX to FLT_MAX and the threshold will be set to zero. + */ DefaultMarchingCubesController(void) - { - m_tThreshold = ((std::numeric_limits::min)() + (std::numeric_limits::max)()) / 2; + :m_tThreshold(((std::numeric_limits::min)() + (std::numeric_limits::max)()) / 2) + ,m_eWrapMode(WrapModes::Border) + ,m_tBorder(VoxelType(0)) + { } - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// Constructor - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// This version of the constructor allows you to set a custom threshold. - /// \param tThreshold The threshold to use. - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - DefaultMarchingCubesController(DensityType tThreshold) - { - m_tThreshold = tThreshold; - } - - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// Converts the underlying voxel type into a density value. - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// The default implementation of this function just returns the voxel type directly and is suitable for primitives types. Specialisations of - /// this class can modify this behaviour. - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Converts the underlying voxel type into a density value. + * + * The default implementation of this function just returns the voxel type directly and is suitable for primitives types. Specialisations of + * this class can modify this behaviour. + */ DensityType convertToDensity(VoxelType voxel) { return voxel; } - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// Converts the underlying voxel type into a material value. - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// The default implementation of this function just returns the constant '1'. There's not much else it can do, as it needs to work with primitive - /// types and the actual value of the type is already being considered to be the density. Specialisations of this class can modify this behaviour. - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - MaterialType convertToMaterial(VoxelType voxel) + /** + * Converts the underlying voxel type into a material value. + * + * The default implementation of this function just returns the constant '1'. There's not much else it can do, as it needs to work with primitive + * types and the actual value of the type is already being considered to be the density. Specialisations of this class can modify this behaviour. + */ + MaterialType convertToMaterial(VoxelType /*voxel*/) { return 1; } - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// Returns the density value which was passed to the constructor. - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /// As mentioned in the class description, the extracted surface will pass through the density value specified by the threshold, and so you - /// should make sure that the threshold value you choose is between the minimum and maximum values found in your volume data. By default it - ///is in the middle of the representable range of the underlying type. - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + VoxelType getBorderValue(void) + { + return m_tBorder; + } + + /** + * Returns the density value which was passed to the constructor. + * + * As mentioned in the class description, the extracted surface will pass through the density value specified by the threshold, and so you + * should make sure that the threshold value you choose is between the minimum and maximum values found in your volume data. By default it + * is in the middle of the representable range of the underlying type. + */ DensityType getThreshold(void) { return m_tThreshold; } + WrapMode getWrapMode(void) + { + return m_eWrapMode; + } + + void setThreshold(DensityType tThreshold) + { + m_tThreshold = tThreshold; + } + + void setWrapMode(WrapMode eWrapMode, VoxelType tBorder = VoxelType(0)) + { + m_eWrapMode = eWrapMode; + m_tBorder = tBorder; + } + private: DensityType m_tThreshold; + WrapMode m_eWrapMode; + VoxelType m_tBorder; }; } diff --git a/library/PolyVoxCore/include/PolyVoxCore/MarchingCubesSurfaceExtractor.inl b/library/PolyVoxCore/include/PolyVoxCore/MarchingCubesSurfaceExtractor.inl index e9761d1e..be2a6674 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/MarchingCubesSurfaceExtractor.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/MarchingCubesSurfaceExtractor.inl @@ -1,626 +1,628 @@ -/******************************************************************************* -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. -*******************************************************************************/ - -namespace PolyVox -{ - template - MarchingCubesSurfaceExtractor::MarchingCubesSurfaceExtractor(VolumeType* volData, Region region, SurfaceMesh >* result, Controller controller) - :m_volData(volData) - ,m_sampVolume(volData) - ,m_meshCurrent(result) - ,m_regSizeInVoxels(region) - { - //m_regSizeInVoxels.cropTo(m_volData->getEnclosingRegion()); - m_regSizeInCells = m_regSizeInVoxels; - m_regSizeInCells.setUpperCorner(m_regSizeInCells.getUpperCorner() - Vector3DInt32(1,1,1)); - - m_controller = controller; - m_tThreshold = m_controller.getThreshold(); - } - - template - void MarchingCubesSurfaceExtractor::execute() - { - m_meshCurrent->clear(); - - uint32_t uArrayWidth = m_regSizeInVoxels.getUpperCorner().getX() - m_regSizeInVoxels.getLowerCorner().getX() + 1; - uint32_t uArrayHeight = m_regSizeInVoxels.getUpperCorner().getY() - m_regSizeInVoxels.getLowerCorner().getY() + 1; - uint32_t arraySizes[2]= {uArrayWidth, uArrayHeight}; // Array dimensions - - //For edge indices - Array2DInt32 m_pPreviousVertexIndicesX(arraySizes); - Array2DInt32 m_pPreviousVertexIndicesY(arraySizes); - Array2DInt32 m_pPreviousVertexIndicesZ(arraySizes); - Array2DInt32 m_pCurrentVertexIndicesX(arraySizes); - Array2DInt32 m_pCurrentVertexIndicesY(arraySizes); - Array2DInt32 m_pCurrentVertexIndicesZ(arraySizes); - - Array2DUint8 pPreviousBitmask(arraySizes); - Array2DUint8 pCurrentBitmask(arraySizes); - - //Create a region corresponding to the first slice - m_regSlicePrevious = m_regSizeInVoxels; - Vector3DInt32 v3dUpperCorner = m_regSlicePrevious.getUpperCorner(); - v3dUpperCorner.setZ(m_regSlicePrevious.getLowerCorner().getZ()); //Set the upper z to the lower z to make it one slice thick. - m_regSlicePrevious.setUpperCorner(v3dUpperCorner); - m_regSliceCurrent = m_regSlicePrevious; - - uint32_t uNoOfNonEmptyCellsForSlice0 = 0; - uint32_t uNoOfNonEmptyCellsForSlice1 = 0; - - //Process the first slice (previous slice not available) - computeBitmaskForSlice(pPreviousBitmask, pCurrentBitmask); - uNoOfNonEmptyCellsForSlice1 = m_uNoOfOccupiedCells; - - if(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); - generateVerticesForSlice(pCurrentBitmask, m_pCurrentVertexIndicesX, m_pCurrentVertexIndicesY, m_pCurrentVertexIndicesZ); - } - - std::swap(uNoOfNonEmptyCellsForSlice0, uNoOfNonEmptyCellsForSlice1); - pPreviousBitmask.swap(pCurrentBitmask); - m_pPreviousVertexIndicesX.swap(m_pCurrentVertexIndicesX); - m_pPreviousVertexIndicesY.swap(m_pCurrentVertexIndicesY); - m_pPreviousVertexIndicesZ.swap(m_pCurrentVertexIndicesZ); - - m_regSlicePrevious = m_regSliceCurrent; - m_regSliceCurrent.shift(Vector3DInt32(0,0,1)); - - //Process the other slices (previous slice is available) - for(int32_t uSlice = 1; uSlice <= m_regSizeInVoxels.getUpperCorner().getZ() - m_regSizeInVoxels.getLowerCorner().getZ(); uSlice++) - { - computeBitmaskForSlice(pPreviousBitmask, pCurrentBitmask); - uNoOfNonEmptyCellsForSlice1 = m_uNoOfOccupiedCells; - - if(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); - generateVerticesForSlice(pCurrentBitmask, m_pCurrentVertexIndicesX, m_pCurrentVertexIndicesY, m_pCurrentVertexIndicesZ); - } - - if((uNoOfNonEmptyCellsForSlice0 != 0) || (uNoOfNonEmptyCellsForSlice1 != 0)) - { - generateIndicesForSlice(pPreviousBitmask, m_pPreviousVertexIndicesX, m_pPreviousVertexIndicesY, m_pPreviousVertexIndicesZ, m_pCurrentVertexIndicesX, m_pCurrentVertexIndicesY); - } - - std::swap(uNoOfNonEmptyCellsForSlice0, uNoOfNonEmptyCellsForSlice1); - pPreviousBitmask.swap(pCurrentBitmask); - m_pPreviousVertexIndicesX.swap(m_pCurrentVertexIndicesX); - m_pPreviousVertexIndicesY.swap(m_pCurrentVertexIndicesY); - m_pPreviousVertexIndicesZ.swap(m_pCurrentVertexIndicesZ); - - m_regSlicePrevious = m_regSliceCurrent; - m_regSliceCurrent.shift(Vector3DInt32(0,0,1)); - } - - 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); - } - - template - template - uint32_t MarchingCubesSurfaceExtractor::computeBitmaskForSlice(const Array2DUint8& pPreviousBitmask, Array2DUint8& pCurrentBitmask) - { - m_uNoOfOccupiedCells = 0; - - const int32_t iMaxXVolSpace = m_regSliceCurrent.getUpperCorner().getX(); - const int32_t iMaxYVolSpace = m_regSliceCurrent.getUpperCorner().getY(); - - iZVolSpace = m_regSliceCurrent.getLowerCorner().getZ(); - uZRegSpace = iZVolSpace - m_regSizeInVoxels.getLowerCorner().getZ(); - - //Process the lower left corner - iYVolSpace = m_regSliceCurrent.getLowerCorner().getY(); - iXVolSpace = m_regSliceCurrent.getLowerCorner().getX(); - - uXRegSpace = iXVolSpace - m_regSizeInVoxels.getLowerCorner().getX(); - uYRegSpace = iYVolSpace - m_regSizeInVoxels.getLowerCorner().getY(); - - m_sampVolume.setPosition(iXVolSpace,iYVolSpace,iZVolSpace); - computeBitmaskForCell(pPreviousBitmask, pCurrentBitmask); - - //Process the edge where x is minimal. - iXVolSpace = m_regSliceCurrent.getLowerCorner().getX(); - m_sampVolume.setPosition(iXVolSpace, m_regSliceCurrent.getLowerCorner().getY(), iZVolSpace); - for(iYVolSpace = m_regSliceCurrent.getLowerCorner().getY() + 1; iYVolSpace <= iMaxYVolSpace; iYVolSpace++) - { - uXRegSpace = iXVolSpace - m_regSizeInVoxels.getLowerCorner().getX(); - uYRegSpace = iYVolSpace - m_regSizeInVoxels.getLowerCorner().getY(); - - m_sampVolume.movePositiveY(); - - computeBitmaskForCell(pPreviousBitmask, pCurrentBitmask); - } - - //Process the edge where y is minimal. - iYVolSpace = m_regSliceCurrent.getLowerCorner().getY(); - m_sampVolume.setPosition(m_regSliceCurrent.getLowerCorner().getX(), iYVolSpace, iZVolSpace); - for(iXVolSpace = m_regSliceCurrent.getLowerCorner().getX() + 1; iXVolSpace <= iMaxXVolSpace; iXVolSpace++) - { - uXRegSpace = iXVolSpace - m_regSizeInVoxels.getLowerCorner().getX(); - uYRegSpace = iYVolSpace - m_regSizeInVoxels.getLowerCorner().getY(); - - m_sampVolume.movePositiveX(); - - computeBitmaskForCell(pPreviousBitmask, pCurrentBitmask); - } - - //Process all remaining elemnents of the slice. In this case, previous x and y values are always available - for(iYVolSpace = m_regSliceCurrent.getLowerCorner().getY() + 1; iYVolSpace <= iMaxYVolSpace; iYVolSpace++) - { - m_sampVolume.setPosition(m_regSliceCurrent.getLowerCorner().getX(), iYVolSpace, iZVolSpace); - for(iXVolSpace = m_regSliceCurrent.getLowerCorner().getX() + 1; iXVolSpace <= iMaxXVolSpace; iXVolSpace++) - { - uXRegSpace = iXVolSpace - m_regSizeInVoxels.getLowerCorner().getX(); - uYRegSpace = iYVolSpace - m_regSizeInVoxels.getLowerCorner().getY(); - - m_sampVolume.movePositiveX(); - - computeBitmaskForCell(pPreviousBitmask, pCurrentBitmask); - } - } - - return m_uNoOfOccupiedCells; - } - - template - template - void MarchingCubesSurfaceExtractor::computeBitmaskForCell(const Array2DUint8& pPreviousBitmask, Array2DUint8& pCurrentBitmask) - { - uint8_t iCubeIndex = 0; - - typename VolumeType::VoxelType v000; - typename VolumeType::VoxelType v100; - typename VolumeType::VoxelType v010; - typename VolumeType::VoxelType v110; - typename VolumeType::VoxelType v001; - typename VolumeType::VoxelType v101; - typename VolumeType::VoxelType v011; - typename VolumeType::VoxelType v111; - - if(isPrevZAvail) - { - if(isPrevYAvail) - { - if(isPrevXAvail) - { - v111 = m_sampVolume.peekVoxel1px1py1pz(); - - //z - uint8_t iPreviousCubeIndexZ = pPreviousBitmask[uXRegSpace][uYRegSpace]; - iPreviousCubeIndexZ >>= 4; - - //y - uint8_t iPreviousCubeIndexY = pCurrentBitmask[uXRegSpace][uYRegSpace-1]; - iPreviousCubeIndexY &= 192; //192 = 128 + 64 - iPreviousCubeIndexY >>= 2; - - //x - uint8_t iPreviousCubeIndexX = pCurrentBitmask[uXRegSpace-1][uYRegSpace]; - iPreviousCubeIndexX &= 128; - iPreviousCubeIndexX >>= 1; - - iCubeIndex = iPreviousCubeIndexX | iPreviousCubeIndexY | iPreviousCubeIndexZ; - - if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128; - } - else //previous X not available - { - v011 = m_sampVolume.peekVoxel0px1py1pz(); - v111 = m_sampVolume.peekVoxel1px1py1pz(); - - //z - uint8_t iPreviousCubeIndexZ = pPreviousBitmask[uXRegSpace][uYRegSpace]; - iPreviousCubeIndexZ >>= 4; - - //y - uint8_t iPreviousCubeIndexY = pCurrentBitmask[uXRegSpace][uYRegSpace-1]; - iPreviousCubeIndexY &= 192; //192 = 128 + 64 - iPreviousCubeIndexY >>= 2; - - iCubeIndex = iPreviousCubeIndexY | iPreviousCubeIndexZ; - - if (m_controller.convertToDensity(v011) < m_tThreshold) iCubeIndex |= 64; - if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128; - } - } - else //previous Y not available - { - if(isPrevXAvail) - { - v101 = m_sampVolume.peekVoxel1px0py1pz(); - v111 = m_sampVolume.peekVoxel1px1py1pz(); - - //z - uint8_t iPreviousCubeIndexZ = pPreviousBitmask[uXRegSpace][uYRegSpace]; - iPreviousCubeIndexZ >>= 4; - - //x - uint8_t iPreviousCubeIndexX = pCurrentBitmask[uXRegSpace-1][uYRegSpace]; - iPreviousCubeIndexX &= 160; //160 = 128+32 - iPreviousCubeIndexX >>= 1; - - iCubeIndex = iPreviousCubeIndexX | iPreviousCubeIndexZ; - - if (m_controller.convertToDensity(v101) < m_tThreshold) iCubeIndex |= 32; - if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128; - } - else //previous X not available - { - v001 = m_sampVolume.peekVoxel0px0py1pz(); - v101 = m_sampVolume.peekVoxel1px0py1pz(); - v011 = m_sampVolume.peekVoxel0px1py1pz(); - v111 = m_sampVolume.peekVoxel1px1py1pz(); - - //z - uint8_t iPreviousCubeIndexZ = pPreviousBitmask[uXRegSpace][uYRegSpace]; - iCubeIndex = iPreviousCubeIndexZ >> 4; - - if (m_controller.convertToDensity(v001) < m_tThreshold) iCubeIndex |= 16; - if (m_controller.convertToDensity(v101) < m_tThreshold) iCubeIndex |= 32; - if (m_controller.convertToDensity(v011) < m_tThreshold) iCubeIndex |= 64; - if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128; - } - } - } - else //previous Z not available - { - if(isPrevYAvail) - { - if(isPrevXAvail) - { - v110 = m_sampVolume.peekVoxel1px1py0pz(); - v111 = m_sampVolume.peekVoxel1px1py1pz(); - - //y - uint8_t iPreviousCubeIndexY = pCurrentBitmask[uXRegSpace][uYRegSpace-1]; - iPreviousCubeIndexY &= 204; //204 = 128+64+8+4 - iPreviousCubeIndexY >>= 2; - - //x - uint8_t iPreviousCubeIndexX = pCurrentBitmask[uXRegSpace-1][uYRegSpace]; - iPreviousCubeIndexX &= 170; //170 = 128+32+8+2 - iPreviousCubeIndexX >>= 1; - - iCubeIndex = iPreviousCubeIndexX | iPreviousCubeIndexY; - - if (m_controller.convertToDensity(v110) < m_tThreshold) iCubeIndex |= 8; - if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128; - } - else //previous X not available - { - v010 = m_sampVolume.peekVoxel0px1py0pz(); - v110 = m_sampVolume.peekVoxel1px1py0pz(); - - v011 = m_sampVolume.peekVoxel0px1py1pz(); - v111 = m_sampVolume.peekVoxel1px1py1pz(); - - //y - uint8_t iPreviousCubeIndexY = pCurrentBitmask[uXRegSpace][uYRegSpace-1]; - iPreviousCubeIndexY &= 204; //204 = 128+64+8+4 - iPreviousCubeIndexY >>= 2; - - iCubeIndex = iPreviousCubeIndexY; - - if (m_controller.convertToDensity(v010) < m_tThreshold) iCubeIndex |= 4; - if (m_controller.convertToDensity(v110) < m_tThreshold) iCubeIndex |= 8; - if (m_controller.convertToDensity(v011) < m_tThreshold) iCubeIndex |= 64; - if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128; - } - } - else //previous Y not available - { - if(isPrevXAvail) - { - v100 = m_sampVolume.peekVoxel1px0py0pz(); - v110 = m_sampVolume.peekVoxel1px1py0pz(); - - v101 = m_sampVolume.peekVoxel1px0py1pz(); - v111 = m_sampVolume.peekVoxel1px1py1pz(); - - //x - uint8_t iPreviousCubeIndexX = pCurrentBitmask[uXRegSpace-1][uYRegSpace]; - iPreviousCubeIndexX &= 170; //170 = 128+32+8+2 - iPreviousCubeIndexX >>= 1; - - iCubeIndex = iPreviousCubeIndexX; - - if (m_controller.convertToDensity(v100) < m_tThreshold) iCubeIndex |= 2; - if (m_controller.convertToDensity(v110) < m_tThreshold) iCubeIndex |= 8; - if (m_controller.convertToDensity(v101) < m_tThreshold) iCubeIndex |= 32; - if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128; - } - else //previous X not available - { - v000 = m_sampVolume.getVoxel(); - v100 = m_sampVolume.peekVoxel1px0py0pz(); - v010 = m_sampVolume.peekVoxel0px1py0pz(); - v110 = m_sampVolume.peekVoxel1px1py0pz(); - - v001 = m_sampVolume.peekVoxel0px0py1pz(); - v101 = m_sampVolume.peekVoxel1px0py1pz(); - v011 = m_sampVolume.peekVoxel0px1py1pz(); - v111 = m_sampVolume.peekVoxel1px1py1pz(); - - if (m_controller.convertToDensity(v000) < m_tThreshold) iCubeIndex |= 1; - if (m_controller.convertToDensity(v100) < m_tThreshold) iCubeIndex |= 2; - if (m_controller.convertToDensity(v010) < m_tThreshold) iCubeIndex |= 4; - if (m_controller.convertToDensity(v110) < m_tThreshold) iCubeIndex |= 8; - if (m_controller.convertToDensity(v001) < m_tThreshold) iCubeIndex |= 16; - if (m_controller.convertToDensity(v101) < m_tThreshold) iCubeIndex |= 32; - if (m_controller.convertToDensity(v011) < m_tThreshold) iCubeIndex |= 64; - if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128; - } - } - } - - //Save the bitmask - pCurrentBitmask[uXRegSpace][iYVolSpace- m_regSizeInVoxels.getLowerCorner().getY()] = iCubeIndex; - - if(edgeTable[iCubeIndex] != 0) - { - ++m_uNoOfOccupiedCells; - } - } - - template - void MarchingCubesSurfaceExtractor::generateVerticesForSlice(const Array2DUint8& pCurrentBitmask, - Array2DInt32& m_pCurrentVertexIndicesX, - Array2DInt32& m_pCurrentVertexIndicesY, - Array2DInt32& m_pCurrentVertexIndicesZ) - { - int32_t iZVolSpace = m_regSliceCurrent.getLowerCorner().getZ(); - - //Iterate over each cell in the region - for(int32_t iYVolSpace = m_regSliceCurrent.getLowerCorner().getY(); iYVolSpace <= m_regSliceCurrent.getUpperCorner().getY(); iYVolSpace++) - { - const uint32_t uYRegSpace = iYVolSpace - m_regSizeInVoxels.getLowerCorner().getY(); - - for(int32_t iXVolSpace = m_regSliceCurrent.getLowerCorner().getX(); iXVolSpace <= m_regSliceCurrent.getUpperCorner().getX(); iXVolSpace++) - { - //Current position - const uint32_t uXRegSpace = iXVolSpace - m_regSizeInVoxels.getLowerCorner().getX(); - - //Determine the index into the edge table which tells us which vertices are inside of the surface - uint8_t iCubeIndex = pCurrentBitmask[uXRegSpace][uYRegSpace]; - - /* Cube is entirely in/out of the surface */ - if (edgeTable[iCubeIndex] == 0) - { - continue; - } - - //Check whether the generated vertex will lie on the edge of the region - - - m_sampVolume.setPosition(iXVolSpace,iYVolSpace,iZVolSpace); - const typename VolumeType::VoxelType v000 = m_sampVolume.getVoxel(); - const Vector3DFloat n000 = computeSobelGradient(m_sampVolume); - - /* Find the vertices where the surface intersects the cube */ - if (edgeTable[iCubeIndex] & 1) - { - m_sampVolume.movePositiveX(); - const typename VolumeType::VoxelType v100 = m_sampVolume.getVoxel(); - const Vector3DFloat n100 = computeSobelGradient(m_sampVolume); - - float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v000)) / static_cast(m_controller.convertToDensity(v100) - m_controller.convertToDensity(v000)); - - const Vector3DFloat v3dPosition(static_cast(iXVolSpace - m_regSizeInVoxels.getLowerCorner().getX()) + fInterp, static_cast(iYVolSpace - m_regSizeInVoxels.getLowerCorner().getY()), static_cast(iZVolSpace - m_regSizeInCells.getLowerCorner().getZ())); - - Vector3DFloat v3dNormal = (n100*fInterp) + (n000*(1-fInterp)); - v3dNormal.normalise(); - - //Choose one of the two materials to use for the vertex (we don't interpolate as interpolation of - //material IDs does not make sense). We take the largest, so that if we are working on a material-only - //volume we get the one which is non-zero. Both materials can be non-zero if our volume has a density component. - typename Controller::MaterialType uMaterial000 = m_controller.convertToMaterial(v000); - typename Controller::MaterialType uMaterial100 = m_controller.convertToMaterial(v100); - //typename Controller::MaterialType uMaterial = (std::max)(uMaterial000, uMaterial100); - typename Controller::MaterialType uMaterial = m_controller.blendMaterials(uMaterial000, uMaterial100, fInterp); - - PositionMaterialNormal surfaceVertex(v3dPosition, v3dNormal, uMaterial); - uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex); - m_pCurrentVertexIndicesX[iXVolSpace - m_regSizeInVoxels.getLowerCorner().getX()][iYVolSpace - m_regSizeInVoxels.getLowerCorner().getY()] = uLastVertexIndex; - - m_sampVolume.moveNegativeX(); - } - if (edgeTable[iCubeIndex] & 8) - { - m_sampVolume.movePositiveY(); - const typename VolumeType::VoxelType v010 = m_sampVolume.getVoxel(); - const Vector3DFloat n010 = computeSobelGradient(m_sampVolume); - - float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v000)) / static_cast(m_controller.convertToDensity(v010) - m_controller.convertToDensity(v000)); - - const Vector3DFloat v3dPosition(static_cast(iXVolSpace - m_regSizeInVoxels.getLowerCorner().getX()), static_cast(iYVolSpace - m_regSizeInVoxels.getLowerCorner().getY()) + fInterp, static_cast(iZVolSpace - m_regSizeInVoxels.getLowerCorner().getZ())); - - Vector3DFloat v3dNormal = (n010*fInterp) + (n000*(1-fInterp)); - v3dNormal.normalise(); - - //Choose one of the two materials to use for the vertex (we don't interpolate as interpolation of - //material IDs does not make sense). We take the largest, so that if we are working on a material-only - //volume we get the one which is non-zero. Both materials can be non-zero if our volume has a density component. - typename Controller::MaterialType uMaterial000 = m_controller.convertToMaterial(v000); - typename Controller::MaterialType uMaterial010 = m_controller.convertToMaterial(v010); - //typename Controller::MaterialType uMaterial = (std::max)(uMaterial000, uMaterial010); - typename Controller::MaterialType uMaterial = m_controller.blendMaterials(uMaterial000, uMaterial010, fInterp); - - PositionMaterialNormal surfaceVertex(v3dPosition, v3dNormal, uMaterial); - uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex); - m_pCurrentVertexIndicesY[iXVolSpace - m_regSizeInVoxels.getLowerCorner().getX()][iYVolSpace - m_regSizeInVoxels.getLowerCorner().getY()] = uLastVertexIndex; - - m_sampVolume.moveNegativeY(); - } - if (edgeTable[iCubeIndex] & 256) - { - m_sampVolume.movePositiveZ(); - const typename VolumeType::VoxelType v001 = m_sampVolume.getVoxel(); - const Vector3DFloat n001 = computeSobelGradient(m_sampVolume); - - float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v000)) / static_cast(m_controller.convertToDensity(v001) - m_controller.convertToDensity(v000)); - - const Vector3DFloat v3dPosition(static_cast(iXVolSpace - m_regSizeInVoxels.getLowerCorner().getX()), static_cast(iYVolSpace - m_regSizeInVoxels.getLowerCorner().getY()), static_cast(iZVolSpace - m_regSizeInVoxels.getLowerCorner().getZ()) + fInterp); - - Vector3DFloat v3dNormal = (n001*fInterp) + (n000*(1-fInterp)); - v3dNormal.normalise(); - - //Choose one of the two materials to use for the vertex (we don't interpolate as interpolation of - //material IDs does not make sense). We take the largest, so that if we are working on a material-only - //volume we get the one which is non-zero. Both materials can be non-zero if our volume has a density component. - typename Controller::MaterialType uMaterial000 = m_controller.convertToMaterial(v000); - typename Controller::MaterialType uMaterial001 = m_controller.convertToMaterial(v001); - //typename Controller::MaterialType uMaterial = (std::max)(uMaterial000, uMaterial001); - typename Controller::MaterialType uMaterial = m_controller.blendMaterials(uMaterial000, uMaterial001, fInterp); - - PositionMaterialNormal surfaceVertex(v3dPosition, v3dNormal, uMaterial); - uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex); - m_pCurrentVertexIndicesZ[iXVolSpace - m_regSizeInVoxels.getLowerCorner().getX()][iYVolSpace - m_regSizeInVoxels.getLowerCorner().getY()] = uLastVertexIndex; - - m_sampVolume.moveNegativeZ(); - } - }//For each cell - } - } - - template - void MarchingCubesSurfaceExtractor::generateIndicesForSlice(const Array2DUint8& pPreviousBitmask, - const Array2DInt32& m_pPreviousVertexIndicesX, - const Array2DInt32& m_pPreviousVertexIndicesY, - const Array2DInt32& m_pPreviousVertexIndicesZ, - const Array2DInt32& m_pCurrentVertexIndicesX, - const Array2DInt32& m_pCurrentVertexIndicesY) - { - int32_t indlist[12]; - for(int i = 0; i < 12; i++) - { - indlist[i] = -1; - } - - for(int32_t iYVolSpace = m_regSlicePrevious.getLowerCorner().getY(); iYVolSpace <= m_regSizeInCells.getUpperCorner().getY(); iYVolSpace++) - { - for(int32_t iXVolSpace = m_regSlicePrevious.getLowerCorner().getX(); iXVolSpace <= m_regSizeInCells.getUpperCorner().getX(); iXVolSpace++) - { - int32_t iZVolSpace = m_regSlicePrevious.getLowerCorner().getZ(); - m_sampVolume.setPosition(iXVolSpace,iYVolSpace,iZVolSpace); - - //Current position - const uint32_t uXRegSpace = m_sampVolume.getPosition().getX() - m_regSizeInVoxels.getLowerCorner().getX(); - const uint32_t uYRegSpace = m_sampVolume.getPosition().getY() - m_regSizeInVoxels.getLowerCorner().getY(); - - //Determine the index into the edge table which tells us which vertices are inside of the surface - uint8_t iCubeIndex = pPreviousBitmask[uXRegSpace][uYRegSpace]; - - /* 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) - { - indlist[0] = m_pPreviousVertexIndicesX[uXRegSpace][uYRegSpace]; - //assert(indlist[0] != -1); - } - if (edgeTable[iCubeIndex] & 2) - { - indlist[1] = m_pPreviousVertexIndicesY[uXRegSpace+1][uYRegSpace]; - //assert(indlist[1] != -1); - } - if (edgeTable[iCubeIndex] & 4) - { - indlist[2] = m_pPreviousVertexIndicesX[uXRegSpace][uYRegSpace+1]; - //assert(indlist[2] != -1); - } - if (edgeTable[iCubeIndex] & 8) - { - indlist[3] = m_pPreviousVertexIndicesY[uXRegSpace][uYRegSpace]; - //assert(indlist[3] != -1); - } - if (edgeTable[iCubeIndex] & 16) - { - indlist[4] = m_pCurrentVertexIndicesX[uXRegSpace][uYRegSpace]; - //assert(indlist[4] != -1); - } - if (edgeTable[iCubeIndex] & 32) - { - indlist[5] = m_pCurrentVertexIndicesY[uXRegSpace+1][uYRegSpace]; - //assert(indlist[5] != -1); - } - if (edgeTable[iCubeIndex] & 64) - { - indlist[6] = m_pCurrentVertexIndicesX[uXRegSpace][uYRegSpace+1]; - //assert(indlist[6] != -1); - } - if (edgeTable[iCubeIndex] & 128) - { - indlist[7] = m_pCurrentVertexIndicesY[uXRegSpace][uYRegSpace]; - //assert(indlist[7] != -1); - } - if (edgeTable[iCubeIndex] & 256) - { - indlist[8] = m_pPreviousVertexIndicesZ[uXRegSpace][uYRegSpace]; - //assert(indlist[8] != -1); - } - if (edgeTable[iCubeIndex] & 512) - { - indlist[9] = m_pPreviousVertexIndicesZ[uXRegSpace+1][uYRegSpace]; - //assert(indlist[9] != -1); - } - if (edgeTable[iCubeIndex] & 1024) - { - indlist[10] = m_pPreviousVertexIndicesZ[uXRegSpace+1][uYRegSpace+1]; - //assert(indlist[10] != -1); - } - if (edgeTable[iCubeIndex] & 2048) - { - indlist[11] = m_pPreviousVertexIndicesZ[uXRegSpace][uYRegSpace+1]; - //assert(indlist[11] != -1); - } - - for (int i=0;triTable[iCubeIndex][i]!=-1;i+=3) - { - int32_t ind0 = indlist[triTable[iCubeIndex][i ]]; - int32_t ind1 = indlist[triTable[iCubeIndex][i+1]]; - int32_t ind2 = indlist[triTable[iCubeIndex][i+2]]; - - if((ind0 != -1) && (ind1 != -1) && (ind2 != -1)) - { - m_meshCurrent->addTriangle(ind0, ind1, ind2); - } - }//For each triangle - }//For each cell - } - } -} +/******************************************************************************* +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. +*******************************************************************************/ + +namespace PolyVox +{ + template + MarchingCubesSurfaceExtractor::MarchingCubesSurfaceExtractor(VolumeType* volData, Region region, SurfaceMesh >* result, Controller controller) + :m_volData(volData) + ,m_sampVolume(volData) + ,m_meshCurrent(result) + ,m_regSizeInVoxels(region) + { + //m_regSizeInVoxels.cropTo(m_volData->getEnclosingRegion()); + m_regSizeInCells = m_regSizeInVoxels; + m_regSizeInCells.setUpperCorner(m_regSizeInCells.getUpperCorner() - Vector3DInt32(1,1,1)); + + m_controller = controller; + m_tThreshold = m_controller.getThreshold(); + + m_sampVolume.setWrapMode(m_controller.getWrapMode(), m_controller.getBorderValue()); + } + + template + void MarchingCubesSurfaceExtractor::execute() + { + m_meshCurrent->clear(); + + uint32_t uArrayWidth = m_regSizeInVoxels.getUpperCorner().getX() - m_regSizeInVoxels.getLowerCorner().getX() + 1; + uint32_t uArrayHeight = m_regSizeInVoxels.getUpperCorner().getY() - m_regSizeInVoxels.getLowerCorner().getY() + 1; + uint32_t arraySizes[2]= {uArrayWidth, uArrayHeight}; // Array dimensions + + //For edge indices + Array2DInt32 m_pPreviousVertexIndicesX(arraySizes); + Array2DInt32 m_pPreviousVertexIndicesY(arraySizes); + Array2DInt32 m_pPreviousVertexIndicesZ(arraySizes); + Array2DInt32 m_pCurrentVertexIndicesX(arraySizes); + Array2DInt32 m_pCurrentVertexIndicesY(arraySizes); + Array2DInt32 m_pCurrentVertexIndicesZ(arraySizes); + + Array2DUint8 pPreviousBitmask(arraySizes); + Array2DUint8 pCurrentBitmask(arraySizes); + + //Create a region corresponding to the first slice + m_regSlicePrevious = m_regSizeInVoxels; + Vector3DInt32 v3dUpperCorner = m_regSlicePrevious.getUpperCorner(); + v3dUpperCorner.setZ(m_regSlicePrevious.getLowerCorner().getZ()); //Set the upper z to the lower z to make it one slice thick. + m_regSlicePrevious.setUpperCorner(v3dUpperCorner); + m_regSliceCurrent = m_regSlicePrevious; + + uint32_t uNoOfNonEmptyCellsForSlice0 = 0; + uint32_t uNoOfNonEmptyCellsForSlice1 = 0; + + //Process the first slice (previous slice not available) + computeBitmaskForSlice(pPreviousBitmask, pCurrentBitmask); + uNoOfNonEmptyCellsForSlice1 = m_uNoOfOccupiedCells; + + if(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); + generateVerticesForSlice(pCurrentBitmask, m_pCurrentVertexIndicesX, m_pCurrentVertexIndicesY, m_pCurrentVertexIndicesZ); + } + + std::swap(uNoOfNonEmptyCellsForSlice0, uNoOfNonEmptyCellsForSlice1); + pPreviousBitmask.swap(pCurrentBitmask); + m_pPreviousVertexIndicesX.swap(m_pCurrentVertexIndicesX); + m_pPreviousVertexIndicesY.swap(m_pCurrentVertexIndicesY); + m_pPreviousVertexIndicesZ.swap(m_pCurrentVertexIndicesZ); + + m_regSlicePrevious = m_regSliceCurrent; + m_regSliceCurrent.shift(Vector3DInt32(0,0,1)); + + //Process the other slices (previous slice is available) + for(int32_t uSlice = 1; uSlice <= m_regSizeInVoxels.getUpperCorner().getZ() - m_regSizeInVoxels.getLowerCorner().getZ(); uSlice++) + { + computeBitmaskForSlice(pPreviousBitmask, pCurrentBitmask); + uNoOfNonEmptyCellsForSlice1 = m_uNoOfOccupiedCells; + + if(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); + generateVerticesForSlice(pCurrentBitmask, m_pCurrentVertexIndicesX, m_pCurrentVertexIndicesY, m_pCurrentVertexIndicesZ); + } + + if((uNoOfNonEmptyCellsForSlice0 != 0) || (uNoOfNonEmptyCellsForSlice1 != 0)) + { + generateIndicesForSlice(pPreviousBitmask, m_pPreviousVertexIndicesX, m_pPreviousVertexIndicesY, m_pPreviousVertexIndicesZ, m_pCurrentVertexIndicesX, m_pCurrentVertexIndicesY); + } + + std::swap(uNoOfNonEmptyCellsForSlice0, uNoOfNonEmptyCellsForSlice1); + pPreviousBitmask.swap(pCurrentBitmask); + m_pPreviousVertexIndicesX.swap(m_pCurrentVertexIndicesX); + m_pPreviousVertexIndicesY.swap(m_pCurrentVertexIndicesY); + m_pPreviousVertexIndicesZ.swap(m_pCurrentVertexIndicesZ); + + m_regSlicePrevious = m_regSliceCurrent; + m_regSliceCurrent.shift(Vector3DInt32(0,0,1)); + } + + 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); + } + + template + template + uint32_t MarchingCubesSurfaceExtractor::computeBitmaskForSlice(const Array2DUint8& pPreviousBitmask, Array2DUint8& pCurrentBitmask) + { + m_uNoOfOccupiedCells = 0; + + const int32_t iMaxXVolSpace = m_regSliceCurrent.getUpperCorner().getX(); + const int32_t iMaxYVolSpace = m_regSliceCurrent.getUpperCorner().getY(); + + iZVolSpace = m_regSliceCurrent.getLowerCorner().getZ(); + uZRegSpace = iZVolSpace - m_regSizeInVoxels.getLowerCorner().getZ(); + + //Process the lower left corner + iYVolSpace = m_regSliceCurrent.getLowerCorner().getY(); + iXVolSpace = m_regSliceCurrent.getLowerCorner().getX(); + + uXRegSpace = iXVolSpace - m_regSizeInVoxels.getLowerCorner().getX(); + uYRegSpace = iYVolSpace - m_regSizeInVoxels.getLowerCorner().getY(); + + m_sampVolume.setPosition(iXVolSpace,iYVolSpace,iZVolSpace); + computeBitmaskForCell(pPreviousBitmask, pCurrentBitmask); + + //Process the edge where x is minimal. + iXVolSpace = m_regSliceCurrent.getLowerCorner().getX(); + m_sampVolume.setPosition(iXVolSpace, m_regSliceCurrent.getLowerCorner().getY(), iZVolSpace); + for(iYVolSpace = m_regSliceCurrent.getLowerCorner().getY() + 1; iYVolSpace <= iMaxYVolSpace; iYVolSpace++) + { + uXRegSpace = iXVolSpace - m_regSizeInVoxels.getLowerCorner().getX(); + uYRegSpace = iYVolSpace - m_regSizeInVoxels.getLowerCorner().getY(); + + m_sampVolume.movePositiveY(); + + computeBitmaskForCell(pPreviousBitmask, pCurrentBitmask); + } + + //Process the edge where y is minimal. + iYVolSpace = m_regSliceCurrent.getLowerCorner().getY(); + m_sampVolume.setPosition(m_regSliceCurrent.getLowerCorner().getX(), iYVolSpace, iZVolSpace); + for(iXVolSpace = m_regSliceCurrent.getLowerCorner().getX() + 1; iXVolSpace <= iMaxXVolSpace; iXVolSpace++) + { + uXRegSpace = iXVolSpace - m_regSizeInVoxels.getLowerCorner().getX(); + uYRegSpace = iYVolSpace - m_regSizeInVoxels.getLowerCorner().getY(); + + m_sampVolume.movePositiveX(); + + computeBitmaskForCell(pPreviousBitmask, pCurrentBitmask); + } + + //Process all remaining elemnents of the slice. In this case, previous x and y values are always available + for(iYVolSpace = m_regSliceCurrent.getLowerCorner().getY() + 1; iYVolSpace <= iMaxYVolSpace; iYVolSpace++) + { + m_sampVolume.setPosition(m_regSliceCurrent.getLowerCorner().getX(), iYVolSpace, iZVolSpace); + for(iXVolSpace = m_regSliceCurrent.getLowerCorner().getX() + 1; iXVolSpace <= iMaxXVolSpace; iXVolSpace++) + { + uXRegSpace = iXVolSpace - m_regSizeInVoxels.getLowerCorner().getX(); + uYRegSpace = iYVolSpace - m_regSizeInVoxels.getLowerCorner().getY(); + + m_sampVolume.movePositiveX(); + + computeBitmaskForCell(pPreviousBitmask, pCurrentBitmask); + } + } + + return m_uNoOfOccupiedCells; + } + + template + template + void MarchingCubesSurfaceExtractor::computeBitmaskForCell(const Array2DUint8& pPreviousBitmask, Array2DUint8& pCurrentBitmask) + { + uint8_t iCubeIndex = 0; + + typename VolumeType::VoxelType v000; + typename VolumeType::VoxelType v100; + typename VolumeType::VoxelType v010; + typename VolumeType::VoxelType v110; + typename VolumeType::VoxelType v001; + typename VolumeType::VoxelType v101; + typename VolumeType::VoxelType v011; + typename VolumeType::VoxelType v111; + + if(isPrevZAvail) + { + if(isPrevYAvail) + { + if(isPrevXAvail) + { + v111 = m_sampVolume.peekVoxel1px1py1pz(); + + //z + uint8_t iPreviousCubeIndexZ = pPreviousBitmask[uXRegSpace][uYRegSpace]; + iPreviousCubeIndexZ >>= 4; + + //y + uint8_t iPreviousCubeIndexY = pCurrentBitmask[uXRegSpace][uYRegSpace-1]; + iPreviousCubeIndexY &= 192; //192 = 128 + 64 + iPreviousCubeIndexY >>= 2; + + //x + uint8_t iPreviousCubeIndexX = pCurrentBitmask[uXRegSpace-1][uYRegSpace]; + iPreviousCubeIndexX &= 128; + iPreviousCubeIndexX >>= 1; + + iCubeIndex = iPreviousCubeIndexX | iPreviousCubeIndexY | iPreviousCubeIndexZ; + + if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128; + } + else //previous X not available + { + v011 = m_sampVolume.peekVoxel0px1py1pz(); + v111 = m_sampVolume.peekVoxel1px1py1pz(); + + //z + uint8_t iPreviousCubeIndexZ = pPreviousBitmask[uXRegSpace][uYRegSpace]; + iPreviousCubeIndexZ >>= 4; + + //y + uint8_t iPreviousCubeIndexY = pCurrentBitmask[uXRegSpace][uYRegSpace-1]; + iPreviousCubeIndexY &= 192; //192 = 128 + 64 + iPreviousCubeIndexY >>= 2; + + iCubeIndex = iPreviousCubeIndexY | iPreviousCubeIndexZ; + + if (m_controller.convertToDensity(v011) < m_tThreshold) iCubeIndex |= 64; + if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128; + } + } + else //previous Y not available + { + if(isPrevXAvail) + { + v101 = m_sampVolume.peekVoxel1px0py1pz(); + v111 = m_sampVolume.peekVoxel1px1py1pz(); + + //z + uint8_t iPreviousCubeIndexZ = pPreviousBitmask[uXRegSpace][uYRegSpace]; + iPreviousCubeIndexZ >>= 4; + + //x + uint8_t iPreviousCubeIndexX = pCurrentBitmask[uXRegSpace-1][uYRegSpace]; + iPreviousCubeIndexX &= 160; //160 = 128+32 + iPreviousCubeIndexX >>= 1; + + iCubeIndex = iPreviousCubeIndexX | iPreviousCubeIndexZ; + + if (m_controller.convertToDensity(v101) < m_tThreshold) iCubeIndex |= 32; + if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128; + } + else //previous X not available + { + v001 = m_sampVolume.peekVoxel0px0py1pz(); + v101 = m_sampVolume.peekVoxel1px0py1pz(); + v011 = m_sampVolume.peekVoxel0px1py1pz(); + v111 = m_sampVolume.peekVoxel1px1py1pz(); + + //z + uint8_t iPreviousCubeIndexZ = pPreviousBitmask[uXRegSpace][uYRegSpace]; + iCubeIndex = iPreviousCubeIndexZ >> 4; + + if (m_controller.convertToDensity(v001) < m_tThreshold) iCubeIndex |= 16; + if (m_controller.convertToDensity(v101) < m_tThreshold) iCubeIndex |= 32; + if (m_controller.convertToDensity(v011) < m_tThreshold) iCubeIndex |= 64; + if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128; + } + } + } + else //previous Z not available + { + if(isPrevYAvail) + { + if(isPrevXAvail) + { + v110 = m_sampVolume.peekVoxel1px1py0pz(); + v111 = m_sampVolume.peekVoxel1px1py1pz(); + + //y + uint8_t iPreviousCubeIndexY = pCurrentBitmask[uXRegSpace][uYRegSpace-1]; + iPreviousCubeIndexY &= 204; //204 = 128+64+8+4 + iPreviousCubeIndexY >>= 2; + + //x + uint8_t iPreviousCubeIndexX = pCurrentBitmask[uXRegSpace-1][uYRegSpace]; + iPreviousCubeIndexX &= 170; //170 = 128+32+8+2 + iPreviousCubeIndexX >>= 1; + + iCubeIndex = iPreviousCubeIndexX | iPreviousCubeIndexY; + + if (m_controller.convertToDensity(v110) < m_tThreshold) iCubeIndex |= 8; + if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128; + } + else //previous X not available + { + v010 = m_sampVolume.peekVoxel0px1py0pz(); + v110 = m_sampVolume.peekVoxel1px1py0pz(); + + v011 = m_sampVolume.peekVoxel0px1py1pz(); + v111 = m_sampVolume.peekVoxel1px1py1pz(); + + //y + uint8_t iPreviousCubeIndexY = pCurrentBitmask[uXRegSpace][uYRegSpace-1]; + iPreviousCubeIndexY &= 204; //204 = 128+64+8+4 + iPreviousCubeIndexY >>= 2; + + iCubeIndex = iPreviousCubeIndexY; + + if (m_controller.convertToDensity(v010) < m_tThreshold) iCubeIndex |= 4; + if (m_controller.convertToDensity(v110) < m_tThreshold) iCubeIndex |= 8; + if (m_controller.convertToDensity(v011) < m_tThreshold) iCubeIndex |= 64; + if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128; + } + } + else //previous Y not available + { + if(isPrevXAvail) + { + v100 = m_sampVolume.peekVoxel1px0py0pz(); + v110 = m_sampVolume.peekVoxel1px1py0pz(); + + v101 = m_sampVolume.peekVoxel1px0py1pz(); + v111 = m_sampVolume.peekVoxel1px1py1pz(); + + //x + uint8_t iPreviousCubeIndexX = pCurrentBitmask[uXRegSpace-1][uYRegSpace]; + iPreviousCubeIndexX &= 170; //170 = 128+32+8+2 + iPreviousCubeIndexX >>= 1; + + iCubeIndex = iPreviousCubeIndexX; + + if (m_controller.convertToDensity(v100) < m_tThreshold) iCubeIndex |= 2; + if (m_controller.convertToDensity(v110) < m_tThreshold) iCubeIndex |= 8; + if (m_controller.convertToDensity(v101) < m_tThreshold) iCubeIndex |= 32; + if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128; + } + else //previous X not available + { + v000 = m_sampVolume.getVoxel(); + v100 = m_sampVolume.peekVoxel1px0py0pz(); + v010 = m_sampVolume.peekVoxel0px1py0pz(); + v110 = m_sampVolume.peekVoxel1px1py0pz(); + + v001 = m_sampVolume.peekVoxel0px0py1pz(); + v101 = m_sampVolume.peekVoxel1px0py1pz(); + v011 = m_sampVolume.peekVoxel0px1py1pz(); + v111 = m_sampVolume.peekVoxel1px1py1pz(); + + if (m_controller.convertToDensity(v000) < m_tThreshold) iCubeIndex |= 1; + if (m_controller.convertToDensity(v100) < m_tThreshold) iCubeIndex |= 2; + if (m_controller.convertToDensity(v010) < m_tThreshold) iCubeIndex |= 4; + if (m_controller.convertToDensity(v110) < m_tThreshold) iCubeIndex |= 8; + if (m_controller.convertToDensity(v001) < m_tThreshold) iCubeIndex |= 16; + if (m_controller.convertToDensity(v101) < m_tThreshold) iCubeIndex |= 32; + if (m_controller.convertToDensity(v011) < m_tThreshold) iCubeIndex |= 64; + if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128; + } + } + } + + //Save the bitmask + pCurrentBitmask[uXRegSpace][iYVolSpace- m_regSizeInVoxels.getLowerCorner().getY()] = iCubeIndex; + + if(edgeTable[iCubeIndex] != 0) + { + ++m_uNoOfOccupiedCells; + } + } + + template + void MarchingCubesSurfaceExtractor::generateVerticesForSlice(const Array2DUint8& pCurrentBitmask, + Array2DInt32& m_pCurrentVertexIndicesX, + Array2DInt32& m_pCurrentVertexIndicesY, + Array2DInt32& m_pCurrentVertexIndicesZ) + { + int32_t iZVolSpace = m_regSliceCurrent.getLowerCorner().getZ(); + + //Iterate over each cell in the region + for(int32_t iYVolSpace = m_regSliceCurrent.getLowerCorner().getY(); iYVolSpace <= m_regSliceCurrent.getUpperCorner().getY(); iYVolSpace++) + { + const uint32_t uYRegSpace = iYVolSpace - m_regSizeInVoxels.getLowerCorner().getY(); + + for(int32_t iXVolSpace = m_regSliceCurrent.getLowerCorner().getX(); iXVolSpace <= m_regSliceCurrent.getUpperCorner().getX(); iXVolSpace++) + { + //Current position + const uint32_t uXRegSpace = iXVolSpace - m_regSizeInVoxels.getLowerCorner().getX(); + + //Determine the index into the edge table which tells us which vertices are inside of the surface + uint8_t iCubeIndex = pCurrentBitmask[uXRegSpace][uYRegSpace]; + + /* Cube is entirely in/out of the surface */ + if (edgeTable[iCubeIndex] == 0) + { + continue; + } + + //Check whether the generated vertex will lie on the edge of the region + + + m_sampVolume.setPosition(iXVolSpace,iYVolSpace,iZVolSpace); + const typename VolumeType::VoxelType v000 = m_sampVolume.getVoxel(); + const Vector3DFloat n000 = computeSobelGradient(m_sampVolume); + + /* Find the vertices where the surface intersects the cube */ + if (edgeTable[iCubeIndex] & 1) + { + m_sampVolume.movePositiveX(); + const typename VolumeType::VoxelType v100 = m_sampVolume.getVoxel(); + const Vector3DFloat n100 = computeSobelGradient(m_sampVolume); + + float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v000)) / static_cast(m_controller.convertToDensity(v100) - m_controller.convertToDensity(v000)); + + const Vector3DFloat v3dPosition(static_cast(iXVolSpace - m_regSizeInVoxels.getLowerCorner().getX()) + fInterp, static_cast(iYVolSpace - m_regSizeInVoxels.getLowerCorner().getY()), static_cast(iZVolSpace - m_regSizeInCells.getLowerCorner().getZ())); + + Vector3DFloat v3dNormal = (n100*fInterp) + (n000*(1-fInterp)); + v3dNormal.normalise(); + + //Choose one of the two materials to use for the vertex (we don't interpolate as interpolation of + //material IDs does not make sense). We take the largest, so that if we are working on a material-only + //volume we get the one which is non-zero. Both materials can be non-zero if our volume has a density component. + typename Controller::MaterialType uMaterial000 = m_controller.convertToMaterial(v000); + typename Controller::MaterialType uMaterial100 = m_controller.convertToMaterial(v100); + //typename Controller::MaterialType uMaterial = (std::max)(uMaterial000, uMaterial100); + typename Controller::MaterialType uMaterial = m_controller.blendMaterials(uMaterial000, uMaterial100, fInterp); + + PositionMaterialNormal surfaceVertex(v3dPosition, v3dNormal, uMaterial); + uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex); + m_pCurrentVertexIndicesX[iXVolSpace - m_regSizeInVoxels.getLowerCorner().getX()][iYVolSpace - m_regSizeInVoxels.getLowerCorner().getY()] = uLastVertexIndex; + + m_sampVolume.moveNegativeX(); + } + if (edgeTable[iCubeIndex] & 8) + { + m_sampVolume.movePositiveY(); + const typename VolumeType::VoxelType v010 = m_sampVolume.getVoxel(); + const Vector3DFloat n010 = computeSobelGradient(m_sampVolume); + + float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v000)) / static_cast(m_controller.convertToDensity(v010) - m_controller.convertToDensity(v000)); + + const Vector3DFloat v3dPosition(static_cast(iXVolSpace - m_regSizeInVoxels.getLowerCorner().getX()), static_cast(iYVolSpace - m_regSizeInVoxels.getLowerCorner().getY()) + fInterp, static_cast(iZVolSpace - m_regSizeInVoxels.getLowerCorner().getZ())); + + Vector3DFloat v3dNormal = (n010*fInterp) + (n000*(1-fInterp)); + v3dNormal.normalise(); + + //Choose one of the two materials to use for the vertex (we don't interpolate as interpolation of + //material IDs does not make sense). We take the largest, so that if we are working on a material-only + //volume we get the one which is non-zero. Both materials can be non-zero if our volume has a density component. + typename Controller::MaterialType uMaterial000 = m_controller.convertToMaterial(v000); + typename Controller::MaterialType uMaterial010 = m_controller.convertToMaterial(v010); + //typename Controller::MaterialType uMaterial = (std::max)(uMaterial000, uMaterial010); + typename Controller::MaterialType uMaterial = m_controller.blendMaterials(uMaterial000, uMaterial010, fInterp); + + PositionMaterialNormal surfaceVertex(v3dPosition, v3dNormal, uMaterial); + uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex); + m_pCurrentVertexIndicesY[iXVolSpace - m_regSizeInVoxels.getLowerCorner().getX()][iYVolSpace - m_regSizeInVoxels.getLowerCorner().getY()] = uLastVertexIndex; + + m_sampVolume.moveNegativeY(); + } + if (edgeTable[iCubeIndex] & 256) + { + m_sampVolume.movePositiveZ(); + const typename VolumeType::VoxelType v001 = m_sampVolume.getVoxel(); + const Vector3DFloat n001 = computeSobelGradient(m_sampVolume); + + float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v000)) / static_cast(m_controller.convertToDensity(v001) - m_controller.convertToDensity(v000)); + + const Vector3DFloat v3dPosition(static_cast(iXVolSpace - m_regSizeInVoxels.getLowerCorner().getX()), static_cast(iYVolSpace - m_regSizeInVoxels.getLowerCorner().getY()), static_cast(iZVolSpace - m_regSizeInVoxels.getLowerCorner().getZ()) + fInterp); + + Vector3DFloat v3dNormal = (n001*fInterp) + (n000*(1-fInterp)); + v3dNormal.normalise(); + + //Choose one of the two materials to use for the vertex (we don't interpolate as interpolation of + //material IDs does not make sense). We take the largest, so that if we are working on a material-only + //volume we get the one which is non-zero. Both materials can be non-zero if our volume has a density component. + typename Controller::MaterialType uMaterial000 = m_controller.convertToMaterial(v000); + typename Controller::MaterialType uMaterial001 = m_controller.convertToMaterial(v001); + //typename Controller::MaterialType uMaterial = (std::max)(uMaterial000, uMaterial001); + typename Controller::MaterialType uMaterial = m_controller.blendMaterials(uMaterial000, uMaterial001, fInterp); + + PositionMaterialNormal surfaceVertex(v3dPosition, v3dNormal, uMaterial); + uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex); + m_pCurrentVertexIndicesZ[iXVolSpace - m_regSizeInVoxels.getLowerCorner().getX()][iYVolSpace - m_regSizeInVoxels.getLowerCorner().getY()] = uLastVertexIndex; + + m_sampVolume.moveNegativeZ(); + } + }//For each cell + } + } + + template + void MarchingCubesSurfaceExtractor::generateIndicesForSlice(const Array2DUint8& pPreviousBitmask, + const Array2DInt32& m_pPreviousVertexIndicesX, + const Array2DInt32& m_pPreviousVertexIndicesY, + const Array2DInt32& m_pPreviousVertexIndicesZ, + const Array2DInt32& m_pCurrentVertexIndicesX, + const Array2DInt32& m_pCurrentVertexIndicesY) + { + int32_t indlist[12]; + for(int i = 0; i < 12; i++) + { + indlist[i] = -1; + } + + for(int32_t iYVolSpace = m_regSlicePrevious.getLowerCorner().getY(); iYVolSpace <= m_regSizeInCells.getUpperCorner().getY(); iYVolSpace++) + { + for(int32_t iXVolSpace = m_regSlicePrevious.getLowerCorner().getX(); iXVolSpace <= m_regSizeInCells.getUpperCorner().getX(); iXVolSpace++) + { + int32_t iZVolSpace = m_regSlicePrevious.getLowerCorner().getZ(); + m_sampVolume.setPosition(iXVolSpace,iYVolSpace,iZVolSpace); + + //Current position + const uint32_t uXRegSpace = m_sampVolume.getPosition().getX() - m_regSizeInVoxels.getLowerCorner().getX(); + const uint32_t uYRegSpace = m_sampVolume.getPosition().getY() - m_regSizeInVoxels.getLowerCorner().getY(); + + //Determine the index into the edge table which tells us which vertices are inside of the surface + uint8_t iCubeIndex = pPreviousBitmask[uXRegSpace][uYRegSpace]; + + /* 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) + { + indlist[0] = m_pPreviousVertexIndicesX[uXRegSpace][uYRegSpace]; + //assert(indlist[0] != -1); + } + if (edgeTable[iCubeIndex] & 2) + { + indlist[1] = m_pPreviousVertexIndicesY[uXRegSpace+1][uYRegSpace]; + //assert(indlist[1] != -1); + } + if (edgeTable[iCubeIndex] & 4) + { + indlist[2] = m_pPreviousVertexIndicesX[uXRegSpace][uYRegSpace+1]; + //assert(indlist[2] != -1); + } + if (edgeTable[iCubeIndex] & 8) + { + indlist[3] = m_pPreviousVertexIndicesY[uXRegSpace][uYRegSpace]; + //assert(indlist[3] != -1); + } + if (edgeTable[iCubeIndex] & 16) + { + indlist[4] = m_pCurrentVertexIndicesX[uXRegSpace][uYRegSpace]; + //assert(indlist[4] != -1); + } + if (edgeTable[iCubeIndex] & 32) + { + indlist[5] = m_pCurrentVertexIndicesY[uXRegSpace+1][uYRegSpace]; + //assert(indlist[5] != -1); + } + if (edgeTable[iCubeIndex] & 64) + { + indlist[6] = m_pCurrentVertexIndicesX[uXRegSpace][uYRegSpace+1]; + //assert(indlist[6] != -1); + } + if (edgeTable[iCubeIndex] & 128) + { + indlist[7] = m_pCurrentVertexIndicesY[uXRegSpace][uYRegSpace]; + //assert(indlist[7] != -1); + } + if (edgeTable[iCubeIndex] & 256) + { + indlist[8] = m_pPreviousVertexIndicesZ[uXRegSpace][uYRegSpace]; + //assert(indlist[8] != -1); + } + if (edgeTable[iCubeIndex] & 512) + { + indlist[9] = m_pPreviousVertexIndicesZ[uXRegSpace+1][uYRegSpace]; + //assert(indlist[9] != -1); + } + if (edgeTable[iCubeIndex] & 1024) + { + indlist[10] = m_pPreviousVertexIndicesZ[uXRegSpace+1][uYRegSpace+1]; + //assert(indlist[10] != -1); + } + if (edgeTable[iCubeIndex] & 2048) + { + indlist[11] = m_pPreviousVertexIndicesZ[uXRegSpace][uYRegSpace+1]; + //assert(indlist[11] != -1); + } + + for (int i=0;triTable[iCubeIndex][i]!=-1;i+=3) + { + int32_t ind0 = indlist[triTable[iCubeIndex][i ]]; + int32_t ind1 = indlist[triTable[iCubeIndex][i+1]]; + int32_t ind2 = indlist[triTable[iCubeIndex][i+2]]; + + if((ind0 != -1) && (ind1 != -1) && (ind2 != -1)) + { + m_meshCurrent->addTriangle(ind0, ind1, ind2); + } + }//For each triangle + }//For each cell + } + } +} From 8473b1e3e6138ec8b2e265b77097ad326eef5a48 Mon Sep 17 00:00:00 2001 From: David Williams Date: Sun, 16 Dec 2012 18:04:33 +0100 Subject: [PATCH 03/30] Added support for getting interpolated voxel value. --- .../include/PolyVoxCore/Impl/Utility.h | 4 +- .../include/PolyVoxCore/RawVolume.h | 2 + .../include/PolyVoxCore/RawVolume.inl | 39 +++++++++++++++++++ 3 files changed, 43 insertions(+), 2 deletions(-) diff --git a/library/PolyVoxCore/include/PolyVoxCore/Impl/Utility.h b/library/PolyVoxCore/include/PolyVoxCore/Impl/Utility.h index 2053c351..77dac7a4 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/Impl/Utility.h +++ b/library/PolyVoxCore/include/PolyVoxCore/Impl/Utility.h @@ -40,12 +40,12 @@ namespace PolyVox inline int32_t roundTowardsNegInf(float r) { - return (r > 0.0) ? static_cast(r) : static_cast(r - 1.0f); + return (r >= 0.0) ? static_cast(r) : static_cast(r - 1.0f); } inline int32_t roundToNearestInteger(float r) { - return (r > 0.0) ? static_cast(r + 0.5f) : static_cast(r - 0.5f); + return (r >= 0.0) ? static_cast(r + 0.5f) : static_cast(r - 0.5f); } template diff --git a/library/PolyVoxCore/include/PolyVoxCore/RawVolume.h b/library/PolyVoxCore/include/PolyVoxCore/RawVolume.h index f0ef1c6e..cae21b67 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/RawVolume.h +++ b/library/PolyVoxCore/include/PolyVoxCore/RawVolume.h @@ -117,6 +117,8 @@ namespace PolyVox /// Destructor ~RawVolume(); + VoxelType getInterpolatedValue(float fXPos, float fYPos, float fZPos); //Should be const + VoxelType getInterpolatedValue(const Vector3DFloat& v3dPos); //Should be const /// Gets a voxel at the position given by x,y,z coordinates VoxelType getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos) const; /// Gets a voxel at the position given by a 3D vector diff --git a/library/PolyVoxCore/include/PolyVoxCore/RawVolume.inl b/library/PolyVoxCore/include/PolyVoxCore/RawVolume.inl index 1fafad5a..ae91695c 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/RawVolume.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/RawVolume.inl @@ -73,6 +73,45 @@ namespace PolyVox assert(false); // See function comment above. } + template + VoxelType RawVolume::getInterpolatedValue(float fXPos, float fYPos, float fZPos) //Should be const + { + Sampler sampler(this); + + int32_t iLowerX = roundTowardsNegInf(fXPos); + int32_t iLowerY = roundTowardsNegInf(fYPos); + int32_t iLowerZ = roundTowardsNegInf(fZPos); + + float fOffsetX = fXPos - iLowerX; + float fOffsetY = fYPos - iLowerY; + float fOffsetZ = fZPos - iLowerZ; + + /*int32_t iCeilX = iFloorX + 1; + int32_t iCeilY = iFloorY + 1; + int32_t iCeilZ = iFloorZ + 1;*/ + + sampler.setPosition(iLowerX, iLowerY, iLowerZ); + + VoxelType v000 = sampler.peekVoxel0px0py0pz(); + VoxelType v100 = sampler.peekVoxel1px0py0pz(); + VoxelType v010 = sampler.peekVoxel0px1py0pz(); + VoxelType v110 = sampler.peekVoxel1px1py0pz(); + VoxelType v001 = sampler.peekVoxel0px0py1pz(); + VoxelType v101 = sampler.peekVoxel1px0py1pz(); + VoxelType v011 = sampler.peekVoxel0px1py1pz(); + VoxelType v111 = sampler.peekVoxel1px1py1pz(); + + VoxelType result = trilerp(v000, v100, v010, v110, v001, v101, v011, v111, fOffsetX, fOffsetY, fOffsetZ); + + return result; + } + + template + VoxelType RawVolume::getInterpolatedValue(const Vector3DFloat& v3dPos) //Should be const + { + return getInterpolatedValue(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ()); + } + //////////////////////////////////////////////////////////////////////////////// /// \param uXPos The \c x position of the voxel /// \param uYPos The \c y position of the voxel From db16a3d602c885f2f44de6ea55f1347a5291d3e9 Mon Sep 17 00:00:00 2001 From: David Williams Date: Mon, 17 Dec 2012 23:42:03 +0100 Subject: [PATCH 04/30] Started implementing a more mathematically correct volume resampler. --- .../include/PolyVoxCore/VolumeResampler.h | 1 + .../include/PolyVoxCore/VolumeResampler.inl | 86 ++++++++++++++++++- 2 files changed, 85 insertions(+), 2 deletions(-) diff --git a/library/PolyVoxCore/include/PolyVoxCore/VolumeResampler.h b/library/PolyVoxCore/include/PolyVoxCore/VolumeResampler.h index 5074a92c..06b1f3d7 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/VolumeResampler.h +++ b/library/PolyVoxCore/include/PolyVoxCore/VolumeResampler.h @@ -39,6 +39,7 @@ namespace PolyVox private: void resampleSameSize(); void resampleArbitrary(); + void resampleBetter(); //Source data SrcVolumeType* m_pVolSrc; diff --git a/library/PolyVoxCore/include/PolyVoxCore/VolumeResampler.inl b/library/PolyVoxCore/include/PolyVoxCore/VolumeResampler.inl index 72dcc573..61b8f218 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/VolumeResampler.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/VolumeResampler.inl @@ -53,14 +53,16 @@ namespace PolyVox int32_t uDstHeight = m_regDst.getUpperCorner().getY() - m_regDst.getLowerCorner().getY() + 1; int32_t uDstDepth = m_regDst.getUpperCorner().getZ() - m_regDst.getLowerCorner().getZ() + 1; - if((uSrcWidth == uDstWidth) && (uSrcHeight == uDstHeight) && (uSrcDepth == uDstDepth)) + /*if((uSrcWidth == uDstWidth) && (uSrcHeight == uDstHeight) && (uSrcDepth == uDstDepth)) { resampleSameSize(); } else { resampleArbitrary(); - } + }*/ + + resampleBetter(); } template< typename SrcVolumeType, typename DstVolumeType> @@ -135,4 +137,84 @@ namespace PolyVox } } } + + template< typename SrcVolumeType, typename DstVolumeType> + void VolumeResampler::resampleBetter() + { + float srcWidth = m_regSrc.getWidthInCells(); + float srcHeight = m_regSrc.getHeightInCells(); + float srcDepth = m_regSrc.getDepthInCells(); + + float dstWidth = m_regDst.getWidthInCells(); + float dstHeight = m_regDst.getHeightInCells(); + float dstDepth = m_regDst.getDepthInCells(); + + float fScaleX = srcWidth / dstWidth; + float fScaleY = srcHeight / dstHeight; + float fScaleZ = srcDepth / dstDepth; + + typename SrcVolumeType::Sampler sampler(m_pVolSrc); + + // Should use SrcVolumeType? Or new template parameter? + Region regDownscaledX(0, 0, 0, m_regDst.getWidthInVoxels()-1, m_regSrc.getHeightInVoxels()-1, m_regSrc.getDepthInVoxels()-1); + SrcVolumeType volDownscaledX(regDownscaledX); + + for(int32_t tz = regDownscaledX.getLowerZ(); tz <= regDownscaledX.getUpperZ(); tz++) + { + for(int32_t ty = regDownscaledX.getLowerY(); ty <= regDownscaledX.getUpperY(); ty++) + { + for(int32_t tx = regDownscaledX.getLowerX(); tx <= regDownscaledX.getUpperX(); tx++) + { + float sx = (tx * fScaleX) + m_regSrc.getLowerCorner().getX(); + float sy = (ty ) + m_regSrc.getLowerCorner().getY(); + float sz = (tz ) + m_regSrc.getLowerCorner().getZ(); + + typename SrcVolumeType::VoxelType result = m_pVolSrc->getVoxelWithWrapping(sx, sy, sz, WrapModes::Clamp); + + volDownscaledX.setVoxelAt(tx, ty, tz, result); + } + } + } + + //Now downscale in y + Region regDownscaledXAndY(0, 0, 0, m_regDst.getWidthInVoxels()-1, m_regDst.getHeightInVoxels()-1, m_regSrc.getDepthInVoxels()-1); + SrcVolumeType volDownscaledXAndY(regDownscaledXAndY); + + for(int32_t tz = regDownscaledXAndY.getLowerZ(); tz <= regDownscaledXAndY.getUpperZ(); tz++) + { + for(int32_t ty = regDownscaledXAndY.getLowerY(); ty <= regDownscaledXAndY.getUpperY(); ty++) + { + for(int32_t tx = regDownscaledXAndY.getLowerX(); tx <= regDownscaledXAndY.getUpperX(); tx++) + { + float sx = (tx ); + float sy = (ty * fScaleY); + float sz = (tz ); + + typename SrcVolumeType::VoxelType result = volDownscaledX.getVoxelWithWrapping(sx, sy, sz, WrapModes::Clamp); + + volDownscaledXAndY.setVoxelAt(tx, ty, tz, result); + } + } + } + + //Now copy and downscale to dst. + //Region regDst = m_pVolDst->getEnclosingRegion(); + + for(int32_t tz = m_regDst.getLowerZ(); tz <= m_regDst.getUpperZ(); tz++) + { + for(int32_t ty = m_regDst.getLowerY(); ty <= m_regDst.getUpperY(); ty++) + { + for(int32_t tx = m_regDst.getLowerX(); tx <= m_regDst.getUpperX(); tx++) + { + float sx = (tx - m_regDst.getLowerX()); + float sy = (ty - m_regDst.getLowerY()); + float sz = (tz - m_regDst.getLowerZ()) * fScaleZ; + + typename SrcVolumeType::VoxelType result = volDownscaledXAndY.getVoxelWithWrapping(sx, sy, sz, WrapModes::Clamp); + + m_pVolDst->setVoxelAt(tx, ty, tz, result); + } + } + } + } } From 9c970bd11a3e55ee1df0db531dfb84f00dceb646 Mon Sep 17 00:00:00 2001 From: David Williams Date: Sat, 29 Dec 2012 21:16:36 +0100 Subject: [PATCH 05/30] Added missing .cpp file to cubiquity version of PolyVox. --- .../PolyVoxCore/source/Impl/ErrorHandling.cpp | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 library/PolyVoxCore/source/Impl/ErrorHandling.cpp diff --git a/library/PolyVoxCore/source/Impl/ErrorHandling.cpp b/library/PolyVoxCore/source/Impl/ErrorHandling.cpp new file mode 100644 index 00000000..bc7dc2c5 --- /dev/null +++ b/library/PolyVoxCore/source/Impl/ErrorHandling.cpp @@ -0,0 +1,71 @@ +/******************************************************************************* +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 "PolyVoxCore/Impl/ErrorHandling.h" + +#ifndef POLYVOX_THROW_ENABLED + namespace PolyVox + { + void defaultThrowHandler(std::exception& e, const char* file, int line) + { + std::cerr << std::endl << std::endl; \ + std::cerr << " PolyVox exception thrown!" << std::endl; \ + std::cerr << " =========================" << std::endl; \ + std::cerr << " PolyVox has tried to throw an exception but it was built without support" << std::endl; \ + std::cerr << " for exceptions. In this scenario PolyVox will call a 'throw handler'" << std::endl; \ + std::cerr << " and this message is being printed by the default throw handler." << std::endl << std::endl; \ + + std::cerr << " If you don't want to enable exceptions then you should try to determine why" << std::endl; \ + std::cerr << " this exception was thrown and make sure it doesn't happen again. If it was" << std::endl; \ + std::cerr << " due to something like an invalid argument to a function then you should be" << std::endl; \ + std::cerr << " able to fix it quite easily by validating parameters as appropriate. More" << std::endl; \ + std::cerr << " complex exception scenarios (out of memory, etc) might be harder to fix and" << std::endl; \ + std::cerr << " you should replace this default handler with something which is more" << std::endl; \ + std::cerr << " meaningful to your users." << std::endl << std::endl; \ + + std::cerr << " Exception details" << std::endl; \ + std::cerr << " -----------------" << std::endl; \ + std::cerr << " Line: " << line << std::endl; \ + std::cerr << " File: " << file << std::endl; \ + std::cerr << " Message: " << e.what() << std::endl << std::endl; \ + + POLYVOX_HALT(); \ + } + + ThrowHandler& getThrowHandlerInstance() + { + static ThrowHandler s_fThrowHandler = &defaultThrowHandler; + return s_fThrowHandler; + } + + ThrowHandler getThrowHandler() + { + return getThrowHandlerInstance(); + } + + void setThrowHandler(ThrowHandler fNewHandler) + { + getThrowHandlerInstance() = fNewHandler; + } + } +#endif From 9051e7558ee5339dde8a2aaea78d534b32fffd07 Mon Sep 17 00:00:00 2001 From: David Williams Date: Sat, 29 Dec 2012 21:32:07 +0100 Subject: [PATCH 06/30] Setting appropriate build variables for Android version. --- .../PolyVoxCore/include/PolyVoxCore/Impl/CompilerCapabilities.h | 2 +- library/PolyVoxCore/include/PolyVoxCore/Impl/ErrorHandling.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/PolyVoxCore/include/PolyVoxCore/Impl/CompilerCapabilities.h b/library/PolyVoxCore/include/PolyVoxCore/Impl/CompilerCapabilities.h index 9afbf506..0c52ac7e 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/Impl/CompilerCapabilities.h +++ b/library/PolyVoxCore/include/PolyVoxCore/Impl/CompilerCapabilities.h @@ -11,7 +11,7 @@ //#undef HAS_CXX11_CONSTEXPR -#define HAS_CXX11_STATIC_ASSERT +//#define HAS_CXX11_STATIC_ASSERT #define HAS_CXX11_CSTDINT_H diff --git a/library/PolyVoxCore/include/PolyVoxCore/Impl/ErrorHandling.h b/library/PolyVoxCore/include/PolyVoxCore/Impl/ErrorHandling.h index 65c2789d..d3ef8b49 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/Impl/ErrorHandling.h +++ b/library/PolyVoxCore/include/PolyVoxCore/Impl/ErrorHandling.h @@ -29,7 +29,7 @@ freely, subject to the following restrictions: #include #define POLYVOX_ASSERTS_ENABLED -#define POLYVOX_THROW_ENABLED +//#define POLYVOX_THROW_ENABLED #if defined(_MSC_VER) #define POLYVOX_HALT() __debugbreak() From d6c4cfb9f3ff86fbf67d8cd3a8e3fae5e7e8af31 Mon Sep 17 00:00:00 2001 From: David Williams Date: Sat, 29 Dec 2012 21:48:55 +0100 Subject: [PATCH 07/30] Eliminating some of the differences between this branch and 'develop'. --- .../include/PolyVoxCore/RawVolume.h | 2 - .../include/PolyVoxCore/RawVolume.inl | 39 ------------------- 2 files changed, 41 deletions(-) diff --git a/library/PolyVoxCore/include/PolyVoxCore/RawVolume.h b/library/PolyVoxCore/include/PolyVoxCore/RawVolume.h index cae21b67..f0ef1c6e 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/RawVolume.h +++ b/library/PolyVoxCore/include/PolyVoxCore/RawVolume.h @@ -117,8 +117,6 @@ namespace PolyVox /// Destructor ~RawVolume(); - VoxelType getInterpolatedValue(float fXPos, float fYPos, float fZPos); //Should be const - VoxelType getInterpolatedValue(const Vector3DFloat& v3dPos); //Should be const /// Gets a voxel at the position given by x,y,z coordinates VoxelType getVoxel(int32_t uXPos, int32_t uYPos, int32_t uZPos) const; /// Gets a voxel at the position given by a 3D vector diff --git a/library/PolyVoxCore/include/PolyVoxCore/RawVolume.inl b/library/PolyVoxCore/include/PolyVoxCore/RawVolume.inl index a1ca12ea..8a0a2e34 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/RawVolume.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/RawVolume.inl @@ -73,45 +73,6 @@ namespace PolyVox assert(false); // See function comment above. } - template - VoxelType RawVolume::getInterpolatedValue(float fXPos, float fYPos, float fZPos) //Should be const - { - Sampler sampler(this); - - int32_t iLowerX = roundTowardsNegInf(fXPos); - int32_t iLowerY = roundTowardsNegInf(fYPos); - int32_t iLowerZ = roundTowardsNegInf(fZPos); - - float fOffsetX = fXPos - iLowerX; - float fOffsetY = fYPos - iLowerY; - float fOffsetZ = fZPos - iLowerZ; - - /*int32_t iCeilX = iFloorX + 1; - int32_t iCeilY = iFloorY + 1; - int32_t iCeilZ = iFloorZ + 1;*/ - - sampler.setPosition(iLowerX, iLowerY, iLowerZ); - - VoxelType v000 = sampler.peekVoxel0px0py0pz(); - VoxelType v100 = sampler.peekVoxel1px0py0pz(); - VoxelType v010 = sampler.peekVoxel0px1py0pz(); - VoxelType v110 = sampler.peekVoxel1px1py0pz(); - VoxelType v001 = sampler.peekVoxel0px0py1pz(); - VoxelType v101 = sampler.peekVoxel1px0py1pz(); - VoxelType v011 = sampler.peekVoxel0px1py1pz(); - VoxelType v111 = sampler.peekVoxel1px1py1pz(); - - VoxelType result = trilerp(v000, v100, v010, v110, v001, v101, v011, v111, fOffsetX, fOffsetY, fOffsetZ); - - return result; - } - - template - VoxelType RawVolume::getInterpolatedValue(const Vector3DFloat& v3dPos) //Should be const - { - return getInterpolatedValue(v3dPos.getX(), v3dPos.getY(), v3dPos.getZ()); - } - //////////////////////////////////////////////////////////////////////////////// /// \param uXPos The \c x position of the voxel /// \param uYPos The \c y position of the voxel From 7e8af71e521c30740b4ec0e93ca6e377564ecaea Mon Sep 17 00:00:00 2001 From: David Williams Date: Sat, 29 Dec 2012 23:39:13 +0100 Subject: [PATCH 08/30] Not quite sure what the difference is here... --- .../include/PolyVoxCore/Vector.inl | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/library/PolyVoxCore/include/PolyVoxCore/Vector.inl b/library/PolyVoxCore/include/PolyVoxCore/Vector.inl index 8aea0d6d..57b3e2f0 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/Vector.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/Vector.inl @@ -52,8 +52,8 @@ namespace PolyVox */ template Vector::Vector(StorageType x, StorageType y) - { - POLYVOX_STATIC_ASSERT(Size == 2, "This constructor should only be used for vectors with two elements."); + { + POLYVOX_STATIC_ASSERT(Size == 2, "This constructor should only be used for vectors with two elements."); m_tElements[0] = x; m_tElements[1] = y; @@ -67,8 +67,8 @@ namespace PolyVox */ template Vector::Vector(StorageType x, StorageType y, StorageType z) - { - POLYVOX_STATIC_ASSERT(Size == 3, "This constructor should only be used for vectors with three elements."); + { + POLYVOX_STATIC_ASSERT(Size == 3, "This constructor should only be used for vectors with three elements."); m_tElements[0] = x; m_tElements[1] = y; @@ -85,8 +85,8 @@ namespace PolyVox */ template Vector::Vector(StorageType x, StorageType y, StorageType z, StorageType w) - { - POLYVOX_STATIC_ASSERT(Size == 4, "This constructor should only be used for vectors with four elements."); + { + POLYVOX_STATIC_ASSERT(Size == 4, "This constructor should only be used for vectors with four elements."); m_tElements[0] = x; m_tElements[1] = y; @@ -135,8 +135,8 @@ namespace PolyVox // Force a vector to have a length greater than one. There is no need for a // vector with one element, and supporting this would cause confusion over the // behaviour of the constructor taking a single value, as this fills all elements - // to that value rather than just the first one. - POLYVOX_STATIC_ASSERT(Size > 1, "Vector must have a length greater than one."); + // to that value rather than just the first one. + POLYVOX_STATIC_ASSERT(Size > 1, "Vector must have a length greater than one."); } /** @@ -441,8 +441,8 @@ namespace PolyVox */ template inline StorageType Vector::getZ(void) const - { - POLYVOX_STATIC_ASSERT(Size >= 3, "You can only get the 'z' component from a vector with at least three elements."); + { + POLYVOX_STATIC_ASSERT(Size >= 3, "You can only get the 'z' component from a vector with at least three elements."); return m_tElements[2]; } @@ -452,8 +452,8 @@ namespace PolyVox */ template inline StorageType Vector::getW(void) const - { - POLYVOX_STATIC_ASSERT(Size >= 4, "You can only get the 'w' component from a vector with at least four elements."); + { + POLYVOX_STATIC_ASSERT(Size >= 4, "You can only get the 'w' component from a vector with at least four elements."); return m_tElements[3]; } @@ -490,9 +490,9 @@ namespace PolyVox */ template inline void Vector::setElements(StorageType x, StorageType y, StorageType z) - { + { POLYVOX_STATIC_ASSERT(Size >= 3, "You can only use this version of setElements() on a vector with at least three elements."); - + m_tElements[0] = x; m_tElements[1] = y; m_tElements[2] = z; @@ -507,9 +507,9 @@ namespace PolyVox */ template inline void Vector::setElements(StorageType x, StorageType y, StorageType z, StorageType w) - { + { POLYVOX_STATIC_ASSERT(Size >= 4, "You can only use this version of setElements() on a vector with at least four elements."); - + m_tElements[0] = x; m_tElements[1] = y; m_tElements[2] = z; @@ -539,10 +539,10 @@ namespace PolyVox */ template inline void Vector::setZ(StorageType tZ) - { + { POLYVOX_STATIC_ASSERT(Size >= 3, "You can only set the 'w' component from a vector with at least three elements."); - m_tElements[2] = tZ; + m_tElements[2] = tZ; } /** @@ -550,10 +550,10 @@ namespace PolyVox */ template inline void Vector::setW(StorageType tW) - { + { POLYVOX_STATIC_ASSERT(Size >= 4, "You can only set the 'w' component from a vector with at least four elements."); - m_tElements[3] = tW; + m_tElements[3] = tW; } /** From 8e5a09d0fce3b629596405d57da9abe6b304cdeb Mon Sep 17 00:00:00 2001 From: David Williams Date: Sat, 29 Dec 2012 23:47:32 +0100 Subject: [PATCH 09/30] Android compile fixes. --- .../PolyVoxCore/include/PolyVoxCore/Impl/CompilerCapabilities.h | 2 +- library/PolyVoxCore/include/PolyVoxCore/Impl/Config.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/PolyVoxCore/include/PolyVoxCore/Impl/CompilerCapabilities.h b/library/PolyVoxCore/include/PolyVoxCore/Impl/CompilerCapabilities.h index 074c3555..1884e19e 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/Impl/CompilerCapabilities.h +++ b/library/PolyVoxCore/include/PolyVoxCore/Impl/CompilerCapabilities.h @@ -15,7 +15,7 @@ // is a recent version) then assume support for these. #if !defined(_MSC_VER) || (_MSC_VER >= 1600) #define HAS_CXX11_CONSTEXPR - #define HAS_CXX11_STATIC_ASSERT + //#define HAS_CXX11_STATIC_ASSERT //This seems to cause issues on Android. #define HAS_CXX11_CSTDINT_H #define HAS_CXX11_SHARED_PTR #endif diff --git a/library/PolyVoxCore/include/PolyVoxCore/Impl/Config.h b/library/PolyVoxCore/include/PolyVoxCore/Impl/Config.h index e97e27af..919950f2 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/Impl/Config.h +++ b/library/PolyVoxCore/include/PolyVoxCore/Impl/Config.h @@ -25,6 +25,6 @@ freely, subject to the following restrictions: #define __PolyVox_Config_H__ #define POLYVOX_ASSERTS_ENABLED -#define POLYVOX_THROW_ENABLED +//#define POLYVOX_THROW_ENABLED //Not allowed on Android. #endif From 8fe824eb58ab7b58ecffcf0c8f4c01dd8a053724 Mon Sep 17 00:00:00 2001 From: David Williams Date: Wed, 2 Jan 2013 21:52:44 +0100 Subject: [PATCH 10/30] Allowing boundary values to be negative. --- library/PolyVoxCore/include/PolyVoxCore/Region.h | 10 +++++----- library/PolyVoxCore/source/Region.cpp | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/library/PolyVoxCore/include/PolyVoxCore/Region.h b/library/PolyVoxCore/include/PolyVoxCore/Region.h index 55c51ee4..aa7681fa 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/Region.h +++ b/library/PolyVoxCore/include/PolyVoxCore/Region.h @@ -133,21 +133,21 @@ namespace PolyVox /// Tests whether the given point is contained in this Region. bool containsPoint(const Vector3DFloat& pos, float boundary = 0.0f) const; /// Tests whether the given point is contained in this Region. - bool containsPoint(int32_t iX, int32_t iY, int32_t iZ, uint8_t boundary = 0) const; + bool containsPoint(int32_t iX, int32_t iY, int32_t iZ, int8_t boundary = 0) const; /// Tests whether the given point is contained in this Region. - bool containsPoint(const Vector3DInt32& pos, uint8_t boundary = 0) const; + bool containsPoint(const Vector3DInt32& pos, int8_t boundary = 0) const; /// Tests whether the given position is contained in the 'x' range of this Region. bool containsPointInX(float pos, float boundary = 0.0f) const; /// Tests whether the given position is contained in the 'x' range of this Region. - bool containsPointInX(int32_t pos, uint8_t boundary = 0) const; + bool containsPointInX(int32_t pos, int8_t boundary = 0) const; /// Tests whether the given position is contained in the 'y' range of this Region. bool containsPointInY(float pos, float boundary = 0.0f) const; /// Tests whether the given position is contained in the 'y' range of this Region. - bool containsPointInY(int32_t pos, uint8_t boundary = 0) const; + bool containsPointInY(int32_t pos, int8_t boundary = 0) const; /// Tests whether the given position is contained in the 'z' range of this Region. bool containsPointInZ(float pos, float boundary = 0.0f) const; /// Tests whether the given position is contained in the 'z' range of this Region. - bool containsPointInZ(int32_t pos, uint8_t boundary = 0) const; + bool containsPointInZ(int32_t pos, int8_t boundary = 0) const; /// Enlarges the Region so that it contains the specified position. void accumulate(int32_t iX, int32_t iY, int32_t iZ); diff --git a/library/PolyVoxCore/source/Region.cpp b/library/PolyVoxCore/source/Region.cpp index 143a537a..dee56bb3 100644 --- a/library/PolyVoxCore/source/Region.cpp +++ b/library/PolyVoxCore/source/Region.cpp @@ -199,7 +199,7 @@ namespace PolyVox * \param iZ The 'z' position of the point to test. * \param boundary The desired boundary value. */ - bool Region::containsPoint(int32_t iX, int32_t iY, int32_t iZ, uint8_t boundary) const + bool Region::containsPoint(int32_t iX, int32_t iY, int32_t iZ, int8_t boundary) const { return (iX <= m_iUpperX - boundary) && (iY <= m_iUpperY - boundary) @@ -216,7 +216,7 @@ namespace PolyVox * \param pos The position to test. * \param boundary The desired boundary value. */ - bool Region::containsPoint(const Vector3DInt32& pos, uint8_t boundary) const + bool Region::containsPoint(const Vector3DInt32& pos, int8_t boundary) const { return containsPoint(pos.getX(), pos.getY(), pos.getZ(), boundary); } @@ -241,7 +241,7 @@ namespace PolyVox * \param pos The position to test. * \param boundary The desired boundary value. */ - bool Region::containsPointInX(int32_t pos, uint8_t boundary) const + bool Region::containsPointInX(int32_t pos, int8_t boundary) const { return (pos <= m_iUpperX - boundary) && (pos >= m_iLowerX + boundary); @@ -267,7 +267,7 @@ namespace PolyVox * \param pos The position to test. * \param boundary The desired boundary value. */ - bool Region::containsPointInY(int32_t pos, uint8_t boundary) const + bool Region::containsPointInY(int32_t pos, int8_t boundary) const { return (pos <= m_iUpperY - boundary) && (pos >= m_iLowerY + boundary); @@ -293,7 +293,7 @@ namespace PolyVox * \param pos The position to test. * \param boundary The desired boundary value. */ - bool Region::containsPointInZ(int32_t pos, uint8_t boundary) const + bool Region::containsPointInZ(int32_t pos, int8_t boundary) const { return (pos <= m_iUpperZ - boundary) && (pos >= m_iLowerZ + boundary); From bf5a9f7ab8c068461f491b384214036b892e4caf Mon Sep 17 00:00:00 2001 From: David Williams Date: Wed, 2 Jan 2013 23:03:07 +0100 Subject: [PATCH 11/30] Added getCentre() to Region class. --- .../PolyVoxCore/include/PolyVoxCore/Region.h | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/library/PolyVoxCore/include/PolyVoxCore/Region.h b/library/PolyVoxCore/include/PolyVoxCore/Region.h index aa7681fa..d65fb022 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/Region.h +++ b/library/PolyVoxCore/include/PolyVoxCore/Region.h @@ -74,6 +74,12 @@ namespace PolyVox /// Inequality Operator. bool operator!=(const Region& rhs) const; + /// Gets the 'x' position of the centre. + int32_t getCentreX(void) const; + /// Gets the 'y' position of the centre. + int32_t getCentreY(void) const; + /// Gets the 'z' position of the centrer. + int32_t getCentreZ(void) const; /// Gets the 'x' position of the lower corner. int32_t getLowerX(void) const; /// Gets the 'y' position of the lower corner. @@ -87,6 +93,8 @@ namespace PolyVox /// Gets the 'z' position of the upper corner. int32_t getUpperZ(void) const; + /// Gets the centre of the region + Vector3DInt32 getCentre(void) const; /// Gets the position of the lower corner. Vector3DInt32 getLowerCorner(void) const; /// Gets the position of the upper corner. @@ -203,6 +211,30 @@ namespace PolyVox // 'inline' keyword is used for the definition rather than the declaration. // See also http://www.parashift.com/c++-faq-lite/inline-functions.html + /** + * \return The 'x' position of the centre. + */ + inline int32_t Region::getCentreX(void) const + { + return (m_iLowerX + m_iUpperX) / 2; + } + + /** + * \return The 'y' position of the centre. + */ + inline int32_t Region::getCentreY(void) const + { + return (m_iLowerY + m_iUpperY) / 2; + } + + /** + * \return The 'z' position of the centre. + */ + inline int32_t Region::getCentreZ(void) const + { + return (m_iLowerZ + m_iUpperZ) / 2; + } + /** * \return The 'x' position of the lower corner. */ @@ -251,6 +283,14 @@ namespace PolyVox return m_iUpperZ; } + /** + * \return The position of the lower corner. + */ + inline Vector3DInt32 Region::getCentre(void) const + { + return Vector3DInt32(getCentreX(), getCentreY(), getCentreZ()); + } + /** * \return The position of the lower corner. */ From 575f4824cce8fc121f15107d3d90a1413b6e2dfb Mon Sep 17 00:00:00 2001 From: David Williams Date: Thu, 3 Jan 2013 00:05:28 +0100 Subject: [PATCH 12/30] Added 'upperPowerOfTwo' function. --- .../PolyVoxCore/include/PolyVoxCore/Impl/Utility.h | 1 + library/PolyVoxCore/source/Impl/Utility.cpp | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/library/PolyVoxCore/include/PolyVoxCore/Impl/Utility.h b/library/PolyVoxCore/include/PolyVoxCore/Impl/Utility.h index 77dac7a4..5b2e327c 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/Impl/Utility.h +++ b/library/PolyVoxCore/include/PolyVoxCore/Impl/Utility.h @@ -37,6 +37,7 @@ namespace PolyVox int32_t roundToInteger(float r); template Type clamp(const Type& value, const Type& low, const Type& high); + uint32_t upperPowerOfTwo(uint32_t v); inline int32_t roundTowardsNegInf(float r) { diff --git a/library/PolyVoxCore/source/Impl/Utility.cpp b/library/PolyVoxCore/source/Impl/Utility.cpp index c82c9630..bce4cd98 100644 --- a/library/PolyVoxCore/source/Impl/Utility.cpp +++ b/library/PolyVoxCore/source/Impl/Utility.cpp @@ -60,4 +60,17 @@ namespace PolyVox else return ((uInput & (uInput-1)) == 0); } + + // http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2 + uint32_t upperPowerOfTwo(uint32_t v) + { + v--; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + v++; + return v; + } } From e05cb1fefc0072ccfc45c63b4d81f4e2bca74cc0 Mon Sep 17 00:00:00 2001 From: David Williams Date: Mon, 14 Jan 2013 23:12:48 +0100 Subject: [PATCH 13/30] Fix for zero length normals causing a crash. --- .../MarchingCubesSurfaceExtractor.inl | 23 ++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/library/PolyVoxCore/include/PolyVoxCore/MarchingCubesSurfaceExtractor.inl b/library/PolyVoxCore/include/PolyVoxCore/MarchingCubesSurfaceExtractor.inl index 1f251862..33330741 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/MarchingCubesSurfaceExtractor.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/MarchingCubesSurfaceExtractor.inl @@ -440,7 +440,13 @@ namespace PolyVox const Vector3DFloat v3dPosition(static_cast(iXVolSpace - m_regSizeInVoxels.getLowerCorner().getX()) + fInterp, static_cast(iYVolSpace - m_regSizeInVoxels.getLowerCorner().getY()), static_cast(iZVolSpace - m_regSizeInCells.getLowerCorner().getZ())); Vector3DFloat v3dNormal = (n100*fInterp) + (n000*(1-fInterp)); - v3dNormal.normalise(); + + // The gradient for a voxel can be zero (e.g. solid voxel surrounded by empty ones) and so + // the interpolated normal can also be zero (e.g. a grid of alternating solid and empty voxels). + if(v3dNormal.lengthSquared() > 0.000001f) + { + v3dNormal.normalise(); + } //Choose one of the two materials to use for the vertex (we don't interpolate as interpolation of //material IDs does not make sense). We take the largest, so that if we are working on a material-only @@ -467,7 +473,13 @@ namespace PolyVox const Vector3DFloat v3dPosition(static_cast(iXVolSpace - m_regSizeInVoxels.getLowerCorner().getX()), static_cast(iYVolSpace - m_regSizeInVoxels.getLowerCorner().getY()) + fInterp, static_cast(iZVolSpace - m_regSizeInVoxels.getLowerCorner().getZ())); Vector3DFloat v3dNormal = (n010*fInterp) + (n000*(1-fInterp)); - v3dNormal.normalise(); + + // The gradient for a voxel can be zero (e.g. solid voxel surrounded by empty ones) and so + // the interpolated normal can also be zero (e.g. a grid of alternating solid and empty voxels). + if(v3dNormal.lengthSquared() > 0.000001f) + { + v3dNormal.normalise(); + } //Choose one of the two materials to use for the vertex (we don't interpolate as interpolation of //material IDs does not make sense). We take the largest, so that if we are working on a material-only @@ -494,7 +506,12 @@ namespace PolyVox const Vector3DFloat v3dPosition(static_cast(iXVolSpace - m_regSizeInVoxels.getLowerCorner().getX()), static_cast(iYVolSpace - m_regSizeInVoxels.getLowerCorner().getY()), static_cast(iZVolSpace - m_regSizeInVoxels.getLowerCorner().getZ()) + fInterp); Vector3DFloat v3dNormal = (n001*fInterp) + (n000*(1-fInterp)); - v3dNormal.normalise(); + // The gradient for a voxel can be zero (e.g. solid voxel surrounded by empty ones) and so + // the interpolated normal can also be zero (e.g. a grid of alternating solid and empty voxels). + if(v3dNormal.lengthSquared() > 0.000001f) + { + v3dNormal.normalise(); + } //Choose one of the two materials to use for the vertex (we don't interpolate as interpolation of //material IDs does not make sense). We take the largest, so that if we are working on a material-only From 1d1dcc875a8dcf55cb550f06f611f610710fd354 Mon Sep 17 00:00:00 2001 From: David Williams Date: Mon, 14 Jan 2013 23:13:17 +0100 Subject: [PATCH 14/30] Added 'intersects' function to Region. --- .../PolyVoxCore/include/PolyVoxCore/Region.h | 2 ++ library/PolyVoxCore/source/Region.cpp | 25 ++++++++++++++----- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/library/PolyVoxCore/include/PolyVoxCore/Region.h b/library/PolyVoxCore/include/PolyVoxCore/Region.h index d65fb022..32aa7715 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/Region.h +++ b/library/PolyVoxCore/include/PolyVoxCore/Region.h @@ -207,6 +207,8 @@ namespace PolyVox int32_t m_iUpperZ; }; + bool intersects(const Region& a, const Region& b); + // Functions to be inlined to to be in the header rather than the .cpp. // 'inline' keyword is used for the definition rather than the declaration. // See also http://www.parashift.com/c++-faq-lite/inline-functions.html diff --git a/library/PolyVoxCore/source/Region.cpp b/library/PolyVoxCore/source/Region.cpp index dee56bb3..b3512b6f 100644 --- a/library/PolyVoxCore/source/Region.cpp +++ b/library/PolyVoxCore/source/Region.cpp @@ -148,12 +148,12 @@ namespace PolyVox && (m_iUpperX == rhs.m_iUpperX) && (m_iUpperY == rhs.m_iUpperY) && (m_iUpperZ == rhs.m_iUpperZ)); } - //////////////////////////////////////////////////////////////////////////////// - /// Two regions are considered different if any of their extents differ. - /// \param rhs The Region to compare to. - /// \return true if the Regions are different. - /// \sa operator== - //////////////////////////////////////////////////////////////////////////////// + /** + * Two regions are considered different if any of their extents differ. + * \param rhs The Region to compare to. + * \return true if the Regions are different. + * \sa operator== + */ bool Region::operator!=(const Region& rhs) const { return !(*this == rhs); @@ -468,4 +468,17 @@ namespace PolyVox { shrink(v3dAmount.getX(), v3dAmount.getY(), v3dAmount.getZ()); } + /** + * This function only returns true if the regions are really intersecting and not simply touching. + */ + bool intersects(const Region& a, const Region& b) + { + // No intersection if seperated along an axis. + if(a.getUpperX() < b.getLowerX() || a.getLowerX() > b.getUpperX()) return false; + if(a.getUpperY() < b.getLowerY() || a.getLowerY() > b.getUpperY()) return false; + if(a.getUpperZ() < b.getLowerZ() || a.getLowerZ() > b.getUpperZ()) return false; + + // Overlapping on all axes means Regions are intersecting. + return true; + } } From 4df159dfd740f8f7d52e1b8ce7ce6f4f054745e3 Mon Sep 17 00:00:00 2001 From: David Williams Date: Thu, 17 Jan 2013 23:51:52 +0100 Subject: [PATCH 15/30] Changed volume sampler wrap mode. --- library/PolyVoxCore/include/PolyVoxCore/VolumeResampler.inl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/PolyVoxCore/include/PolyVoxCore/VolumeResampler.inl b/library/PolyVoxCore/include/PolyVoxCore/VolumeResampler.inl index 61b8f218..8a530c51 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/VolumeResampler.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/VolumeResampler.inl @@ -169,7 +169,7 @@ namespace PolyVox float sy = (ty ) + m_regSrc.getLowerCorner().getY(); float sz = (tz ) + m_regSrc.getLowerCorner().getZ(); - typename SrcVolumeType::VoxelType result = m_pVolSrc->getVoxelWithWrapping(sx, sy, sz, WrapModes::Clamp); + typename SrcVolumeType::VoxelType result = m_pVolSrc->getVoxelWithWrapping(sx, sy, sz, WrapModes::Border); volDownscaledX.setVoxelAt(tx, ty, tz, result); } @@ -190,7 +190,7 @@ namespace PolyVox float sy = (ty * fScaleY); float sz = (tz ); - typename SrcVolumeType::VoxelType result = volDownscaledX.getVoxelWithWrapping(sx, sy, sz, WrapModes::Clamp); + typename SrcVolumeType::VoxelType result = volDownscaledX.getVoxelWithWrapping(sx, sy, sz, WrapModes::Border); volDownscaledXAndY.setVoxelAt(tx, ty, tz, result); } @@ -210,7 +210,7 @@ namespace PolyVox float sy = (ty - m_regDst.getLowerY()); float sz = (tz - m_regDst.getLowerZ()) * fScaleZ; - typename SrcVolumeType::VoxelType result = volDownscaledXAndY.getVoxelWithWrapping(sx, sy, sz, WrapModes::Clamp); + typename SrcVolumeType::VoxelType result = volDownscaledXAndY.getVoxelWithWrapping(sx, sy, sz, WrapModes::Border); m_pVolDst->setVoxelAt(tx, ty, tz, result); } From d3aed35d81396be515779bfa56460080ee9d9713 Mon Sep 17 00:00:00 2001 From: David Williams Date: Sun, 27 Jan 2013 13:03:30 +0100 Subject: [PATCH 16/30] Added some (temporary) interpolation code. --- .../include/PolyVoxCore/VolumeResampler.h | 3 ++ .../include/PolyVoxCore/VolumeResampler.inl | 35 ++++++++++++++++++- 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/library/PolyVoxCore/include/PolyVoxCore/VolumeResampler.h b/library/PolyVoxCore/include/PolyVoxCore/VolumeResampler.h index 06b1f3d7..271f9d4d 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/VolumeResampler.h +++ b/library/PolyVoxCore/include/PolyVoxCore/VolumeResampler.h @@ -28,6 +28,9 @@ freely, subject to the following restrictions: namespace PolyVox { + template + typename VolumeType::VoxelType interpolatedSample(VolumeType* pVolume, float fPosX, float fPosY, float fPosZ, WrapMode eWrapMode, typename VolumeType::VoxelType tBorder); + template< typename SrcVolumeType, typename DstVolumeType> class VolumeResampler { diff --git a/library/PolyVoxCore/include/PolyVoxCore/VolumeResampler.inl b/library/PolyVoxCore/include/PolyVoxCore/VolumeResampler.inl index 8a530c51..f4abc452 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/VolumeResampler.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/VolumeResampler.inl @@ -27,6 +27,37 @@ freely, subject to the following restrictions: namespace PolyVox { + // Takes an interpolated sample of the volume data. + template + typename VolumeType::VoxelType interpolatedSample(VolumeType* pVolume, float fPosX, float fPosY, float fPosZ, WrapMode eWrapMode, typename VolumeType::VoxelType tBorder) + { + float fFloorX = floor(fPosX); + float fFloorY = floor(fPosY); + float fFloorZ = floor(fPosZ); + + float fInterpX = fPosX - fFloorX; + float fInterpY = fPosY - fFloorY; + float fInterpZ = fPosZ - fFloorZ; + + // Conditional logic required to round negative floats correctly + int32_t iX = static_cast(fFloorX > 0.0f ? fFloorX + 0.5f : fFloorX - 0.5f); + int32_t iY = static_cast(fFloorY > 0.0f ? fFloorY + 0.5f : fFloorY - 0.5f); + int32_t iZ = static_cast(fFloorZ > 0.0f ? fFloorZ + 0.5f : fFloorZ - 0.5f); + + const typename VolumeType::VoxelType& voxel000 = pVolume->getVoxelWithWrapping(iX, iY, iZ, eWrapMode, tBorder); + const typename VolumeType::VoxelType& voxel001 = pVolume->getVoxelWithWrapping(iX, iY, iZ + 1, eWrapMode, tBorder); + const typename VolumeType::VoxelType& voxel010 = pVolume->getVoxelWithWrapping(iX, iY + 1, iZ, eWrapMode, tBorder); + const typename VolumeType::VoxelType& voxel011 = pVolume->getVoxelWithWrapping(iX, iY + 1, iZ + 1, eWrapMode, tBorder); + const typename VolumeType::VoxelType& voxel100 = pVolume->getVoxelWithWrapping(iX + 1, iY, iZ, eWrapMode, tBorder); + const typename VolumeType::VoxelType& voxel101 = pVolume->getVoxelWithWrapping(iX + 1, iY, iZ + 1, eWrapMode, tBorder); + const typename VolumeType::VoxelType& voxel110 = pVolume->getVoxelWithWrapping(iX + 1, iY + 1, iZ, eWrapMode, tBorder); + const typename VolumeType::VoxelType& voxel111 = pVolume->getVoxelWithWrapping(iX + 1, iY + 1, iZ + 1, eWrapMode, tBorder); + + typename VolumeType::VoxelType tInterpolatedValue = PolyVox::trilerp(voxel000,voxel100,voxel010,voxel110,voxel001,voxel101,voxel011,voxel111,fInterpX,fInterpY,fInterpZ); + + return tInterpolatedValue; + } + /** * \param pVolSrc * \param regSrc @@ -169,7 +200,9 @@ namespace PolyVox float sy = (ty ) + m_regSrc.getLowerCorner().getY(); float sz = (tz ) + m_regSrc.getLowerCorner().getZ(); - typename SrcVolumeType::VoxelType result = m_pVolSrc->getVoxelWithWrapping(sx, sy, sz, WrapModes::Border); + //typename SrcVolumeType::VoxelType result = m_pVolSrc->getVoxelWithWrapping(sx, sy, sz, WrapModes::Border); + + typename SrcVolumeType::VoxelType result = interpolatedSample(m_pVolSrc, sx, sy, sz, WrapModes::Border, SrcVolumeType::VoxelType(0)); volDownscaledX.setVoxelAt(tx, ty, tz, result); } From f76be64d6bed96207c68136c501d8739bae73940 Mon Sep 17 00:00:00 2001 From: David Williams Date: Sun, 27 Jan 2013 22:02:13 +0100 Subject: [PATCH 17/30] Work on VolumeResampler (using real convolution). --- .../include/PolyVoxCore/Impl/Utility.h | 2 ++ .../include/PolyVoxCore/VolumeResampler.inl | 33 ++++++++++++++++--- library/PolyVoxCore/source/Impl/Utility.cpp | 5 +++ 3 files changed, 35 insertions(+), 5 deletions(-) diff --git a/library/PolyVoxCore/include/PolyVoxCore/Impl/Utility.h b/library/PolyVoxCore/include/PolyVoxCore/Impl/Utility.h index 5b2e327c..1b635841 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/Impl/Utility.h +++ b/library/PolyVoxCore/include/PolyVoxCore/Impl/Utility.h @@ -54,6 +54,8 @@ namespace PolyVox { return (std::min)(high, (std::max)(low, value)); } + + float triangleFilter(float fInput); } #endif diff --git a/library/PolyVoxCore/include/PolyVoxCore/VolumeResampler.inl b/library/PolyVoxCore/include/PolyVoxCore/VolumeResampler.inl index f4abc452..eb9198b3 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/VolumeResampler.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/VolumeResampler.inl @@ -23,6 +23,8 @@ freely, subject to the following restrictions: #include "PolyVoxCore/Interpolation.h" +#include "PolyVoxCore/Impl/Utility.h" + #include namespace PolyVox @@ -200,9 +202,9 @@ namespace PolyVox float sy = (ty ) + m_regSrc.getLowerCorner().getY(); float sz = (tz ) + m_regSrc.getLowerCorner().getZ(); - //typename SrcVolumeType::VoxelType result = m_pVolSrc->getVoxelWithWrapping(sx, sy, sz, WrapModes::Border); + typename SrcVolumeType::VoxelType result = m_pVolSrc->getVoxelWithWrapping(sx, sy, sz, WrapModes::Border); - typename SrcVolumeType::VoxelType result = interpolatedSample(m_pVolSrc, sx, sy, sz, WrapModes::Border, SrcVolumeType::VoxelType(0)); + //typename SrcVolumeType::VoxelType result = interpolatedSample(m_pVolSrc, sx, sy, sz, WrapModes::Border, SrcVolumeType::VoxelType(0)); volDownscaledX.setVoxelAt(tx, ty, tz, result); } @@ -241,11 +243,32 @@ namespace PolyVox { float sx = (tx - m_regDst.getLowerX()); float sy = (ty - m_regDst.getLowerY()); - float sz = (tz - m_regDst.getLowerZ()) * fScaleZ; + float sLowerZ = ((tz - 1) - m_regDst.getLowerZ()) * fScaleZ; + float sCentreZ = ((tz ) - m_regDst.getLowerZ()) * fScaleZ; + float sUpperZ = ((tz + 1) - m_regDst.getLowerZ()) * fScaleZ; - typename SrcVolumeType::VoxelType result = volDownscaledXAndY.getVoxelWithWrapping(sx, sy, sz, WrapModes::Border); + float sumOfWeights = 0.0f; + //typename SrcVolumeType::VoxelType tSum = SrcVolumeType::VoxelType(0); - m_pVolDst->setVoxelAt(tx, ty, tz, result); + //We should be able to use a higher range MultiMaterial rather than needing to use a Vector of floats. + //We shouold also probably support an Accumulation type rather than hard coding. + Vector<4, float> vecSum(0.0, 0.0, 0.0, 0.0); + + for(float sz = sLowerZ; sz <= sUpperZ; sz += 1.0) + { + float weight = triangleFilter(sz - sCentreZ); + sumOfWeights += weight; + + Vector<4, float> sample = interpolatedSample(&volDownscaledXAndY, sx, sy, sz, WrapModes::Border, SrcVolumeType::VoxelType(0)); + + vecSum += (sample * weight); + } + + vecSum /= sumOfWeights; //Should divide by 'norm' + + typename SrcVolumeType::VoxelType tResult = vecSum; //Should divide by 'norm' + + m_pVolDst->setVoxelAt(tx, ty, tz, tResult); } } } diff --git a/library/PolyVoxCore/source/Impl/Utility.cpp b/library/PolyVoxCore/source/Impl/Utility.cpp index bce4cd98..4733f57f 100644 --- a/library/PolyVoxCore/source/Impl/Utility.cpp +++ b/library/PolyVoxCore/source/Impl/Utility.cpp @@ -73,4 +73,9 @@ namespace PolyVox v++; return v; } + + float triangleFilter(float fInput) + { + return (std::max)(1.0f - (std::abs)(fInput), 0.0f); + } } From dadcf03d8d0fae6f0356d19e7de5e557b414bd48 Mon Sep 17 00:00:00 2001 From: David Williams Date: Thu, 31 Jan 2013 21:04:01 +0100 Subject: [PATCH 18/30] Added note. --- .../include/PolyVoxCore/VolumeResampler.inl | 45 ++++++++++--------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/library/PolyVoxCore/include/PolyVoxCore/VolumeResampler.inl b/library/PolyVoxCore/include/PolyVoxCore/VolumeResampler.inl index eb9198b3..d5444ff8 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/VolumeResampler.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/VolumeResampler.inl @@ -33,28 +33,28 @@ namespace PolyVox template typename VolumeType::VoxelType interpolatedSample(VolumeType* pVolume, float fPosX, float fPosY, float fPosZ, WrapMode eWrapMode, typename VolumeType::VoxelType tBorder) { - float fFloorX = floor(fPosX); - float fFloorY = floor(fPosY); - float fFloorZ = floor(fPosZ); - - float fInterpX = fPosX - fFloorX; - float fInterpY = fPosY - fFloorY; - float fInterpZ = fPosZ - fFloorZ; - - // Conditional logic required to round negative floats correctly - int32_t iX = static_cast(fFloorX > 0.0f ? fFloorX + 0.5f : fFloorX - 0.5f); - int32_t iY = static_cast(fFloorY > 0.0f ? fFloorY + 0.5f : fFloorY - 0.5f); - int32_t iZ = static_cast(fFloorZ > 0.0f ? fFloorZ + 0.5f : fFloorZ - 0.5f); - - const typename VolumeType::VoxelType& voxel000 = pVolume->getVoxelWithWrapping(iX, iY, iZ, eWrapMode, tBorder); - const typename VolumeType::VoxelType& voxel001 = pVolume->getVoxelWithWrapping(iX, iY, iZ + 1, eWrapMode, tBorder); - const typename VolumeType::VoxelType& voxel010 = pVolume->getVoxelWithWrapping(iX, iY + 1, iZ, eWrapMode, tBorder); - const typename VolumeType::VoxelType& voxel011 = pVolume->getVoxelWithWrapping(iX, iY + 1, iZ + 1, eWrapMode, tBorder); - const typename VolumeType::VoxelType& voxel100 = pVolume->getVoxelWithWrapping(iX + 1, iY, iZ, eWrapMode, tBorder); - const typename VolumeType::VoxelType& voxel101 = pVolume->getVoxelWithWrapping(iX + 1, iY, iZ + 1, eWrapMode, tBorder); - const typename VolumeType::VoxelType& voxel110 = pVolume->getVoxelWithWrapping(iX + 1, iY + 1, iZ, eWrapMode, tBorder); - const typename VolumeType::VoxelType& voxel111 = pVolume->getVoxelWithWrapping(iX + 1, iY + 1, iZ + 1, eWrapMode, tBorder); - + float fFloorX = floor(fPosX); + float fFloorY = floor(fPosY); + float fFloorZ = floor(fPosZ); + + float fInterpX = fPosX - fFloorX; + float fInterpY = fPosY - fFloorY; + float fInterpZ = fPosZ - fFloorZ; + + // Conditional logic required to round negative floats correctly + int32_t iX = static_cast(fFloorX > 0.0f ? fFloorX + 0.5f : fFloorX - 0.5f); + int32_t iY = static_cast(fFloorY > 0.0f ? fFloorY + 0.5f : fFloorY - 0.5f); + int32_t iZ = static_cast(fFloorZ > 0.0f ? fFloorZ + 0.5f : fFloorZ - 0.5f); + + const typename VolumeType::VoxelType& voxel000 = pVolume->getVoxelWithWrapping(iX, iY, iZ, eWrapMode, tBorder); + const typename VolumeType::VoxelType& voxel001 = pVolume->getVoxelWithWrapping(iX, iY, iZ + 1, eWrapMode, tBorder); + const typename VolumeType::VoxelType& voxel010 = pVolume->getVoxelWithWrapping(iX, iY + 1, iZ, eWrapMode, tBorder); + const typename VolumeType::VoxelType& voxel011 = pVolume->getVoxelWithWrapping(iX, iY + 1, iZ + 1, eWrapMode, tBorder); + const typename VolumeType::VoxelType& voxel100 = pVolume->getVoxelWithWrapping(iX + 1, iY, iZ, eWrapMode, tBorder); + const typename VolumeType::VoxelType& voxel101 = pVolume->getVoxelWithWrapping(iX + 1, iY, iZ + 1, eWrapMode, tBorder); + const typename VolumeType::VoxelType& voxel110 = pVolume->getVoxelWithWrapping(iX + 1, iY + 1, iZ, eWrapMode, tBorder); + const typename VolumeType::VoxelType& voxel111 = pVolume->getVoxelWithWrapping(iX + 1, iY + 1, iZ + 1, eWrapMode, tBorder); + typename VolumeType::VoxelType tInterpolatedValue = PolyVox::trilerp(voxel000,voxel100,voxel010,voxel110,voxel001,voxel101,voxel011,voxel111,fInterpX,fInterpY,fInterpZ); return tInterpolatedValue; @@ -259,6 +259,7 @@ namespace PolyVox float weight = triangleFilter(sz - sCentreZ); sumOfWeights += weight; + //This is wrong! There's no need to do interpolation. Just multiply the sameple by the correct kernel value. Vector<4, float> sample = interpolatedSample(&volDownscaledXAndY, sx, sy, sz, WrapModes::Border, SrcVolumeType::VoxelType(0)); vecSum += (sample * weight); From f517137991bde40436d5c92580887f638b5362ef Mon Sep 17 00:00:00 2001 From: David Williams Date: Fri, 8 Feb 2013 22:19:02 +0100 Subject: [PATCH 19/30] Performance improvements brought across from develop. --- .../PolyVoxCore/CubicSurfaceExtractor.inl | 86 +++++++++---------- .../MarchingCubesSurfaceExtractor.inl | 84 +++++++++--------- 2 files changed, 84 insertions(+), 86 deletions(-) diff --git a/library/PolyVoxCore/include/PolyVoxCore/CubicSurfaceExtractor.inl b/library/PolyVoxCore/include/PolyVoxCore/CubicSurfaceExtractor.inl index 694aea52..8e7c6751 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/CubicSurfaceExtractor.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/CubicSurfaceExtractor.inl @@ -50,8 +50,8 @@ namespace PolyVox { m_meshCurrent->clear(); - uint32_t uArrayWidth = m_regSizeInVoxels.getUpperCorner().getX() - m_regSizeInVoxels.getLowerCorner().getX() + 2; - uint32_t uArrayHeight = m_regSizeInVoxels.getUpperCorner().getY() - m_regSizeInVoxels.getLowerCorner().getY() + 2; + uint32_t uArrayWidth = m_regSizeInVoxels.getUpperX() - m_regSizeInVoxels.getLowerX() + 2; + uint32_t uArrayHeight = m_regSizeInVoxels.getUpperY() - m_regSizeInVoxels.getLowerY() + 2; uint32_t arraySize[3]= {uArrayWidth, uArrayHeight, MaxVerticesPerPosition}; m_previousSliceVertices.resize(arraySize); @@ -59,35 +59,31 @@ namespace PolyVox memset(m_previousSliceVertices.getRawData(), 0xff, m_previousSliceVertices.getNoOfElements() * sizeof(IndexAndMaterial)); memset(m_currentSliceVertices.getRawData(), 0xff, m_currentSliceVertices.getNoOfElements() * sizeof(IndexAndMaterial)); - uint32_t uRegionWidth = m_regSizeInVoxels.getUpperCorner().getX() - m_regSizeInVoxels.getLowerCorner().getX() + 1; - uint32_t uRegionHeight = m_regSizeInVoxels.getUpperCorner().getY() - m_regSizeInVoxels.getLowerCorner().getY() + 1; - uint32_t uRegionDepth = m_regSizeInVoxels.getUpperCorner().getZ() - m_regSizeInVoxels.getLowerCorner().getZ() + 1; + m_vecQuads[NegativeX].resize(m_regSizeInVoxels.getUpperX() - m_regSizeInVoxels.getLowerX() + 2); + m_vecQuads[PositiveX].resize(m_regSizeInVoxels.getUpperX() - m_regSizeInVoxels.getLowerX() + 2); - m_vecQuads[NegativeX].resize(m_regSizeInVoxels.getUpperCorner().getX() - m_regSizeInVoxels.getLowerCorner().getX() + 2); - m_vecQuads[PositiveX].resize(m_regSizeInVoxels.getUpperCorner().getX() - m_regSizeInVoxels.getLowerCorner().getX() + 2); + m_vecQuads[NegativeY].resize(m_regSizeInVoxels.getUpperY() - m_regSizeInVoxels.getLowerY() + 2); + m_vecQuads[PositiveY].resize(m_regSizeInVoxels.getUpperY() - m_regSizeInVoxels.getLowerY() + 2); - m_vecQuads[NegativeY].resize(m_regSizeInVoxels.getUpperCorner().getY() - m_regSizeInVoxels.getLowerCorner().getY() + 2); - m_vecQuads[PositiveY].resize(m_regSizeInVoxels.getUpperCorner().getY() - m_regSizeInVoxels.getLowerCorner().getY() + 2); - - m_vecQuads[NegativeZ].resize(m_regSizeInVoxels.getUpperCorner().getZ() - m_regSizeInVoxels.getLowerCorner().getZ() + 2); - m_vecQuads[PositiveZ].resize(m_regSizeInVoxels.getUpperCorner().getZ() - m_regSizeInVoxels.getLowerCorner().getZ() + 2); + m_vecQuads[NegativeZ].resize(m_regSizeInVoxels.getUpperZ() - m_regSizeInVoxels.getLowerZ() + 2); + m_vecQuads[PositiveZ].resize(m_regSizeInVoxels.getUpperZ() - m_regSizeInVoxels.getLowerZ() + 2); typename VolumeType::Sampler volumeSampler(m_volData); volumeSampler.setWrapMode(m_eWrapMode, m_tBorderValue); - for(int32_t z = m_regSizeInVoxels.getLowerCorner().getZ(); z <= m_regSizeInVoxels.getUpperCorner().getZ(); z++) + for(int32_t z = m_regSizeInVoxels.getLowerZ(); z <= m_regSizeInVoxels.getUpperZ(); z++) { - uint32_t regZ = z - m_regSizeInVoxels.getLowerCorner().getZ(); + uint32_t regZ = z - m_regSizeInVoxels.getLowerZ(); - for(int32_t y = m_regSizeInVoxels.getLowerCorner().getY(); y <= m_regSizeInVoxels.getUpperCorner().getY(); y++) + for(int32_t y = m_regSizeInVoxels.getLowerY(); y <= m_regSizeInVoxels.getUpperY(); y++) { - uint32_t regY = y - m_regSizeInVoxels.getLowerCorner().getY(); + uint32_t regY = y - m_regSizeInVoxels.getLowerY(); - for(int32_t x = m_regSizeInVoxels.getLowerCorner().getX(); x <= m_regSizeInVoxels.getUpperCorner().getX(); x++) + volumeSampler.setPosition(m_regSizeInVoxels.getLowerX(),y,z); + + for(int32_t x = m_regSizeInVoxels.getLowerX(); x <= m_regSizeInVoxels.getUpperX(); x++) { - uint32_t regX = x - m_regSizeInVoxels.getLowerCorner().getX(); - - volumeSampler.setPosition(x,y,z); + uint32_t regX = x - m_regSizeInVoxels.getLowerX(); typename VolumeType::VoxelType material; //Filled in by callback typename VolumeType::VoxelType currentVoxel = volumeSampler.getVoxel(); @@ -98,20 +94,20 @@ namespace PolyVox // X if(m_funcIsQuadNeededCallback(currentVoxel, negXVoxel, material)) { - uint32_t v0 = addVertex(regX - 0.5f, regY - 0.5f, regZ - 0.5f, material, m_previousSliceVertices); - uint32_t v1 = addVertex(regX - 0.5f, regY - 0.5f, regZ + 0.5f, material, m_currentSliceVertices); - uint32_t v2 = addVertex(regX - 0.5f, regY + 0.5f, regZ + 0.5f, material, m_currentSliceVertices); - uint32_t v3 = addVertex(regX - 0.5f, regY + 0.5f, regZ - 0.5f, material, m_previousSliceVertices); + uint32_t v0 = addVertex(static_cast(regX) - 0.5f, static_cast(regY) - 0.5f, static_cast(regZ) - 0.5f, material, m_previousSliceVertices); + uint32_t v1 = addVertex(static_cast(regX) - 0.5f, static_cast(regY) - 0.5f, static_cast(regZ) + 0.5f, material, m_currentSliceVertices); + uint32_t v2 = addVertex(static_cast(regX) - 0.5f, static_cast(regY) + 0.5f, static_cast(regZ) + 0.5f, material, m_currentSliceVertices); + uint32_t v3 = addVertex(static_cast(regX) - 0.5f, static_cast(regY) + 0.5f, static_cast(regZ) - 0.5f, material, m_previousSliceVertices); m_vecQuads[NegativeX][regX].push_back(Quad(v0, v1, v2, v3)); } if(m_funcIsQuadNeededCallback(negXVoxel, currentVoxel, material)) { - uint32_t v0 = addVertex(regX - 0.5f, regY - 0.5f, regZ - 0.5f, material, m_previousSliceVertices); - uint32_t v1 = addVertex(regX - 0.5f, regY - 0.5f, regZ + 0.5f, material, m_currentSliceVertices); - uint32_t v2 = addVertex(regX - 0.5f, regY + 0.5f, regZ + 0.5f, material, m_currentSliceVertices); - uint32_t v3 = addVertex(regX - 0.5f, regY + 0.5f, regZ - 0.5f, material, m_previousSliceVertices); + uint32_t v0 = addVertex(static_cast(regX) - 0.5f, static_cast(regY) - 0.5f, static_cast(regZ) - 0.5f, material, m_previousSliceVertices); + uint32_t v1 = addVertex(static_cast(regX) - 0.5f, static_cast(regY) - 0.5f, static_cast(regZ) + 0.5f, material, m_currentSliceVertices); + uint32_t v2 = addVertex(static_cast(regX) - 0.5f, static_cast(regY) + 0.5f, static_cast(regZ) + 0.5f, material, m_currentSliceVertices); + uint32_t v3 = addVertex(static_cast(regX) - 0.5f, static_cast(regY) + 0.5f, static_cast(regZ) - 0.5f, material, m_previousSliceVertices); m_vecQuads[PositiveX][regX].push_back(Quad(v0, v3, v2, v1)); } @@ -119,20 +115,20 @@ namespace PolyVox // Y if(m_funcIsQuadNeededCallback(currentVoxel, negYVoxel, material)) { - uint32_t v0 = addVertex(regX - 0.5f, regY - 0.5f, regZ - 0.5f, material, m_previousSliceVertices); - uint32_t v1 = addVertex(regX + 0.5f, regY - 0.5f, regZ - 0.5f, material, m_previousSliceVertices); - uint32_t v2 = addVertex(regX + 0.5f, regY - 0.5f, regZ + 0.5f, material, m_currentSliceVertices); - uint32_t v3 = addVertex(regX - 0.5f, regY - 0.5f, regZ + 0.5f, material, m_currentSliceVertices); + uint32_t v0 = addVertex(static_cast(regX) - 0.5f, static_cast(regY) - 0.5f, static_cast(regZ) - 0.5f, material, m_previousSliceVertices); + uint32_t v1 = addVertex(static_cast(regX) + 0.5f, static_cast(regY) - 0.5f, static_cast(regZ) - 0.5f, material, m_previousSliceVertices); + uint32_t v2 = addVertex(static_cast(regX) + 0.5f, static_cast(regY) - 0.5f, static_cast(regZ) + 0.5f, material, m_currentSliceVertices); + uint32_t v3 = addVertex(static_cast(regX) - 0.5f, static_cast(regY) - 0.5f, static_cast(regZ) + 0.5f, material, m_currentSliceVertices); m_vecQuads[NegativeY][regY].push_back(Quad(v0, v1, v2, v3)); } if(m_funcIsQuadNeededCallback(negYVoxel, currentVoxel, material)) { - uint32_t v0 = addVertex(regX - 0.5f, regY - 0.5f, regZ - 0.5f, material, m_previousSliceVertices); - uint32_t v1 = addVertex(regX + 0.5f, regY - 0.5f, regZ - 0.5f, material, m_previousSliceVertices); - uint32_t v2 = addVertex(regX + 0.5f, regY - 0.5f, regZ + 0.5f, material, m_currentSliceVertices); - uint32_t v3 = addVertex(regX - 0.5f, regY - 0.5f, regZ + 0.5f, material, m_currentSliceVertices); + uint32_t v0 = addVertex(static_cast(regX) - 0.5f, static_cast(regY) - 0.5f, static_cast(regZ) - 0.5f, material, m_previousSliceVertices); + uint32_t v1 = addVertex(static_cast(regX) + 0.5f, static_cast(regY) - 0.5f, static_cast(regZ) - 0.5f, material, m_previousSliceVertices); + uint32_t v2 = addVertex(static_cast(regX) + 0.5f, static_cast(regY) - 0.5f, static_cast(regZ) + 0.5f, material, m_currentSliceVertices); + uint32_t v3 = addVertex(static_cast(regX) - 0.5f, static_cast(regY) - 0.5f, static_cast(regZ) + 0.5f, material, m_currentSliceVertices); m_vecQuads[PositiveY][regY].push_back(Quad(v0, v3, v2, v1)); } @@ -140,23 +136,25 @@ namespace PolyVox // Z if(m_funcIsQuadNeededCallback(currentVoxel, negZVoxel, material)) { - uint32_t v0 = addVertex(regX - 0.5f, regY - 0.5f, regZ - 0.5f, material, m_previousSliceVertices); - uint32_t v1 = addVertex(regX - 0.5f, regY + 0.5f, regZ - 0.5f, material, m_previousSliceVertices); - uint32_t v2 = addVertex(regX + 0.5f, regY + 0.5f, regZ - 0.5f, material, m_previousSliceVertices); - uint32_t v3 = addVertex(regX + 0.5f, regY - 0.5f, regZ - 0.5f, material, m_previousSliceVertices); + uint32_t v0 = addVertex(static_cast(regX) - 0.5f, static_cast(regY) - 0.5f, static_cast(regZ) - 0.5f, material, m_previousSliceVertices); + uint32_t v1 = addVertex(static_cast(regX) - 0.5f, static_cast(regY) + 0.5f, static_cast(regZ) - 0.5f, material, m_previousSliceVertices); + uint32_t v2 = addVertex(static_cast(regX) + 0.5f, static_cast(regY) + 0.5f, static_cast(regZ) - 0.5f, material, m_previousSliceVertices); + uint32_t v3 = addVertex(static_cast(regX) + 0.5f, static_cast(regY) - 0.5f, static_cast(regZ) - 0.5f, material, m_previousSliceVertices); m_vecQuads[NegativeZ][regZ].push_back(Quad(v0, v1, v2, v3)); } if(m_funcIsQuadNeededCallback(negZVoxel, currentVoxel, material)) { - uint32_t v0 = addVertex(regX - 0.5f, regY - 0.5f, regZ - 0.5f, material, m_previousSliceVertices); - uint32_t v1 = addVertex(regX - 0.5f, regY + 0.5f, regZ - 0.5f, material, m_previousSliceVertices); - uint32_t v2 = addVertex(regX + 0.5f, regY + 0.5f, regZ - 0.5f, material, m_previousSliceVertices); - uint32_t v3 = addVertex(regX + 0.5f, regY - 0.5f, regZ - 0.5f, material, m_previousSliceVertices); + uint32_t v0 = addVertex(static_cast(regX) - 0.5f, static_cast(regY) - 0.5f, static_cast(regZ) - 0.5f, material, m_previousSliceVertices); + uint32_t v1 = addVertex(static_cast(regX) - 0.5f, static_cast(regY) + 0.5f, static_cast(regZ) - 0.5f, material, m_previousSliceVertices); + uint32_t v2 = addVertex(static_cast(regX) + 0.5f, static_cast(regY) + 0.5f, static_cast(regZ) - 0.5f, material, m_previousSliceVertices); + uint32_t v3 = addVertex(static_cast(regX) + 0.5f, static_cast(regY) - 0.5f, static_cast(regZ) - 0.5f, material, m_previousSliceVertices); m_vecQuads[PositiveZ][regZ].push_back(Quad(v0, v3, v2, v1)); } + + volumeSampler.movePositiveX(); } } diff --git a/library/PolyVoxCore/include/PolyVoxCore/MarchingCubesSurfaceExtractor.inl b/library/PolyVoxCore/include/PolyVoxCore/MarchingCubesSurfaceExtractor.inl index 8e9b8b44..44ad5cbe 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/MarchingCubesSurfaceExtractor.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/MarchingCubesSurfaceExtractor.inl @@ -44,8 +44,8 @@ namespace PolyVox { m_meshCurrent->clear(); - const uint32_t uArrayWidth = m_regSizeInVoxels.getUpperCorner().getX() - m_regSizeInVoxels.getLowerCorner().getX() + 1; - const uint32_t uArrayHeight = m_regSizeInVoxels.getUpperCorner().getY() - m_regSizeInVoxels.getLowerCorner().getY() + 1; + const uint32_t uArrayWidth = m_regSizeInVoxels.getUpperX() - m_regSizeInVoxels.getLowerX() + 1; + const uint32_t uArrayHeight = m_regSizeInVoxels.getUpperY() - m_regSizeInVoxels.getLowerY() + 1; const uint32_t arraySizes[2]= {uArrayWidth, uArrayHeight}; // Array dimensions //For edge indices @@ -62,7 +62,7 @@ namespace PolyVox //Create a region corresponding to the first slice m_regSlicePrevious = m_regSizeInVoxels; Vector3DInt32 v3dUpperCorner = m_regSlicePrevious.getUpperCorner(); - v3dUpperCorner.setZ(m_regSlicePrevious.getLowerCorner().getZ()); //Set the upper z to the lower z to make it one slice thick. + v3dUpperCorner.setZ(m_regSlicePrevious.getLowerZ()); //Set the upper z to the lower z to make it one slice thick. m_regSlicePrevious.setUpperCorner(v3dUpperCorner); m_regSliceCurrent = m_regSlicePrevious; @@ -91,7 +91,7 @@ namespace PolyVox m_regSliceCurrent.shift(Vector3DInt32(0,0,1)); //Process the other slices (previous slice is available) - for(int32_t uSlice = 1; uSlice <= m_regSizeInVoxels.getUpperCorner().getZ() - m_regSizeInVoxels.getLowerCorner().getZ(); uSlice++) + for(int32_t uSlice = 1; uSlice <= m_regSizeInVoxels.getUpperZ() - m_regSizeInVoxels.getLowerZ(); uSlice++) { computeBitmaskForSlice(pPreviousBitmask, pCurrentBitmask); uNoOfNonEmptyCellsForSlice1 = m_uNoOfOccupiedCells; @@ -134,29 +134,29 @@ namespace PolyVox { m_uNoOfOccupiedCells = 0; - const int32_t iMaxXVolSpace = m_regSliceCurrent.getUpperCorner().getX(); - const int32_t iMaxYVolSpace = m_regSliceCurrent.getUpperCorner().getY(); + const int32_t iMaxXVolSpace = m_regSliceCurrent.getUpperX(); + const int32_t iMaxYVolSpace = m_regSliceCurrent.getUpperY(); - const int32_t iZVolSpace = m_regSliceCurrent.getLowerCorner().getZ(); + const int32_t iZVolSpace = m_regSliceCurrent.getLowerZ(); //Process the lower left corner - int32_t iYVolSpace = m_regSliceCurrent.getLowerCorner().getY(); - int32_t iXVolSpace = m_regSliceCurrent.getLowerCorner().getX(); + int32_t iYVolSpace = m_regSliceCurrent.getLowerY(); + int32_t iXVolSpace = m_regSliceCurrent.getLowerX(); - uint32_t uXRegSpace = iXVolSpace - m_regSizeInVoxels.getLowerCorner().getX(); - uint32_t uYRegSpace = iYVolSpace - m_regSizeInVoxels.getLowerCorner().getY(); + uint32_t uXRegSpace = iXVolSpace - m_regSizeInVoxels.getLowerX(); + uint32_t uYRegSpace = iYVolSpace - m_regSizeInVoxels.getLowerY(); m_sampVolume.setPosition(iXVolSpace,iYVolSpace,iZVolSpace); computeBitmaskForCell(pPreviousBitmask, pCurrentBitmask, uXRegSpace, uYRegSpace); //Process the edge where x is minimal. - iXVolSpace = m_regSliceCurrent.getLowerCorner().getX(); - m_sampVolume.setPosition(iXVolSpace, m_regSliceCurrent.getLowerCorner().getY(), iZVolSpace); - for(iYVolSpace = m_regSliceCurrent.getLowerCorner().getY() + 1; iYVolSpace <= iMaxYVolSpace; iYVolSpace++) + iXVolSpace = m_regSliceCurrent.getLowerX(); + m_sampVolume.setPosition(iXVolSpace, m_regSliceCurrent.getLowerY(), iZVolSpace); + for(iYVolSpace = m_regSliceCurrent.getLowerY() + 1; iYVolSpace <= iMaxYVolSpace; iYVolSpace++) { - uXRegSpace = iXVolSpace - m_regSizeInVoxels.getLowerCorner().getX(); - uYRegSpace = iYVolSpace - m_regSizeInVoxels.getLowerCorner().getY(); + uXRegSpace = iXVolSpace - m_regSizeInVoxels.getLowerX(); + uYRegSpace = iYVolSpace - m_regSizeInVoxels.getLowerY(); m_sampVolume.movePositiveY(); @@ -164,12 +164,12 @@ namespace PolyVox } //Process the edge where y is minimal. - iYVolSpace = m_regSliceCurrent.getLowerCorner().getY(); - m_sampVolume.setPosition(m_regSliceCurrent.getLowerCorner().getX(), iYVolSpace, iZVolSpace); - for(iXVolSpace = m_regSliceCurrent.getLowerCorner().getX() + 1; iXVolSpace <= iMaxXVolSpace; iXVolSpace++) + iYVolSpace = m_regSliceCurrent.getLowerY(); + m_sampVolume.setPosition(m_regSliceCurrent.getLowerX(), iYVolSpace, iZVolSpace); + for(iXVolSpace = m_regSliceCurrent.getLowerX() + 1; iXVolSpace <= iMaxXVolSpace; iXVolSpace++) { - uXRegSpace = iXVolSpace - m_regSizeInVoxels.getLowerCorner().getX(); - uYRegSpace = iYVolSpace - m_regSizeInVoxels.getLowerCorner().getY(); + uXRegSpace = iXVolSpace - m_regSizeInVoxels.getLowerX(); + uYRegSpace = iYVolSpace - m_regSizeInVoxels.getLowerY(); m_sampVolume.movePositiveX(); @@ -177,13 +177,13 @@ namespace PolyVox } //Process all remaining elemnents of the slice. In this case, previous x and y values are always available - for(iYVolSpace = m_regSliceCurrent.getLowerCorner().getY() + 1; iYVolSpace <= iMaxYVolSpace; iYVolSpace++) + for(iYVolSpace = m_regSliceCurrent.getLowerY() + 1; iYVolSpace <= iMaxYVolSpace; iYVolSpace++) { - m_sampVolume.setPosition(m_regSliceCurrent.getLowerCorner().getX(), iYVolSpace, iZVolSpace); - for(iXVolSpace = m_regSliceCurrent.getLowerCorner().getX() + 1; iXVolSpace <= iMaxXVolSpace; iXVolSpace++) + m_sampVolume.setPosition(m_regSliceCurrent.getLowerX(), iYVolSpace, iZVolSpace); + for(iXVolSpace = m_regSliceCurrent.getLowerX() + 1; iXVolSpace <= iMaxXVolSpace; iXVolSpace++) { - uXRegSpace = iXVolSpace - m_regSizeInVoxels.getLowerCorner().getX(); - uYRegSpace = iYVolSpace - m_regSizeInVoxels.getLowerCorner().getY(); + uXRegSpace = iXVolSpace - m_regSizeInVoxels.getLowerX(); + uYRegSpace = iYVolSpace - m_regSizeInVoxels.getLowerY(); m_sampVolume.movePositiveX(); @@ -400,17 +400,17 @@ namespace PolyVox Array2DInt32& m_pCurrentVertexIndicesY, Array2DInt32& m_pCurrentVertexIndicesZ) { - const int32_t iZVolSpace = m_regSliceCurrent.getLowerCorner().getZ(); + const int32_t iZVolSpace = m_regSliceCurrent.getLowerZ(); //Iterate over each cell in the region - for(int32_t iYVolSpace = m_regSliceCurrent.getLowerCorner().getY(); iYVolSpace <= m_regSliceCurrent.getUpperCorner().getY(); iYVolSpace++) + for(int32_t iYVolSpace = m_regSliceCurrent.getLowerY(); iYVolSpace <= m_regSliceCurrent.getUpperY(); iYVolSpace++) { - const uint32_t uYRegSpace = iYVolSpace - m_regSizeInVoxels.getLowerCorner().getY(); + const uint32_t uYRegSpace = iYVolSpace - m_regSizeInVoxels.getLowerY(); - for(int32_t iXVolSpace = m_regSliceCurrent.getLowerCorner().getX(); iXVolSpace <= m_regSliceCurrent.getUpperCorner().getX(); iXVolSpace++) + for(int32_t iXVolSpace = m_regSliceCurrent.getLowerX(); iXVolSpace <= m_regSliceCurrent.getUpperX(); iXVolSpace++) { //Current position - const uint32_t uXRegSpace = iXVolSpace - m_regSizeInVoxels.getLowerCorner().getX(); + const uint32_t uXRegSpace = iXVolSpace - m_regSizeInVoxels.getLowerX(); //Determine the index into the edge table which tells us which vertices are inside of the surface const uint8_t iCubeIndex = pCurrentBitmask[uXRegSpace][uYRegSpace]; @@ -437,7 +437,7 @@ namespace PolyVox const float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v000)) / static_cast(m_controller.convertToDensity(v100) - m_controller.convertToDensity(v000)); - const Vector3DFloat v3dPosition(static_cast(iXVolSpace - m_regSizeInVoxels.getLowerCorner().getX()) + fInterp, static_cast(iYVolSpace - m_regSizeInVoxels.getLowerCorner().getY()), static_cast(iZVolSpace - m_regSizeInCells.getLowerCorner().getZ())); + const Vector3DFloat v3dPosition(static_cast(iXVolSpace - m_regSizeInVoxels.getLowerX()) + fInterp, static_cast(iYVolSpace - m_regSizeInVoxels.getLowerY()), static_cast(iZVolSpace - m_regSizeInCells.getLowerZ())); Vector3DFloat v3dNormal = (n100*fInterp) + (n000*(1-fInterp)); @@ -458,7 +458,7 @@ namespace PolyVox const PositionMaterialNormal surfaceVertex(v3dPosition, v3dNormal, uMaterial); const uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex); - m_pCurrentVertexIndicesX[iXVolSpace - m_regSizeInVoxels.getLowerCorner().getX()][iYVolSpace - m_regSizeInVoxels.getLowerCorner().getY()] = uLastVertexIndex; + m_pCurrentVertexIndicesX[iXVolSpace - m_regSizeInVoxels.getLowerX()][iYVolSpace - m_regSizeInVoxels.getLowerY()] = uLastVertexIndex; m_sampVolume.moveNegativeX(); } @@ -470,7 +470,7 @@ namespace PolyVox const float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v000)) / static_cast(m_controller.convertToDensity(v010) - m_controller.convertToDensity(v000)); - const Vector3DFloat v3dPosition(static_cast(iXVolSpace - m_regSizeInVoxels.getLowerCorner().getX()), static_cast(iYVolSpace - m_regSizeInVoxels.getLowerCorner().getY()) + fInterp, static_cast(iZVolSpace - m_regSizeInVoxels.getLowerCorner().getZ())); + const Vector3DFloat v3dPosition(static_cast(iXVolSpace - m_regSizeInVoxels.getLowerX()), static_cast(iYVolSpace - m_regSizeInVoxels.getLowerY()) + fInterp, static_cast(iZVolSpace - m_regSizeInVoxels.getLowerZ())); Vector3DFloat v3dNormal = (n010*fInterp) + (n000*(1-fInterp)); @@ -491,7 +491,7 @@ namespace PolyVox PositionMaterialNormal surfaceVertex(v3dPosition, v3dNormal, uMaterial); uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex); - m_pCurrentVertexIndicesY[iXVolSpace - m_regSizeInVoxels.getLowerCorner().getX()][iYVolSpace - m_regSizeInVoxels.getLowerCorner().getY()] = uLastVertexIndex; + m_pCurrentVertexIndicesY[iXVolSpace - m_regSizeInVoxels.getLowerX()][iYVolSpace - m_regSizeInVoxels.getLowerY()] = uLastVertexIndex; m_sampVolume.moveNegativeY(); } @@ -503,7 +503,7 @@ namespace PolyVox const float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v000)) / static_cast(m_controller.convertToDensity(v001) - m_controller.convertToDensity(v000)); - const Vector3DFloat v3dPosition(static_cast(iXVolSpace - m_regSizeInVoxels.getLowerCorner().getX()), static_cast(iYVolSpace - m_regSizeInVoxels.getLowerCorner().getY()), static_cast(iZVolSpace - m_regSizeInVoxels.getLowerCorner().getZ()) + fInterp); + const Vector3DFloat v3dPosition(static_cast(iXVolSpace - m_regSizeInVoxels.getLowerX()), static_cast(iYVolSpace - m_regSizeInVoxels.getLowerY()), static_cast(iZVolSpace - m_regSizeInVoxels.getLowerZ()) + fInterp); Vector3DFloat v3dNormal = (n001*fInterp) + (n000*(1-fInterp)); // The gradient for a voxel can be zero (e.g. solid voxel surrounded by empty ones) and so @@ -523,7 +523,7 @@ namespace PolyVox const PositionMaterialNormal surfaceVertex(v3dPosition, v3dNormal, uMaterial); const uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex); - m_pCurrentVertexIndicesZ[iXVolSpace - m_regSizeInVoxels.getLowerCorner().getX()][iYVolSpace - m_regSizeInVoxels.getLowerCorner().getY()] = uLastVertexIndex; + m_pCurrentVertexIndicesZ[iXVolSpace - m_regSizeInVoxels.getLowerX()][iYVolSpace - m_regSizeInVoxels.getLowerY()] = uLastVertexIndex; m_sampVolume.moveNegativeZ(); } @@ -545,17 +545,17 @@ namespace PolyVox indlist[i] = -1; } - const int32_t iZVolSpace = m_regSlicePrevious.getLowerCorner().getZ(); + const int32_t iZVolSpace = m_regSlicePrevious.getLowerZ(); - for(int32_t iYVolSpace = m_regSlicePrevious.getLowerCorner().getY(); iYVolSpace <= m_regSizeInCells.getUpperCorner().getY(); iYVolSpace++) + for(int32_t iYVolSpace = m_regSlicePrevious.getLowerY(); iYVolSpace <= m_regSizeInCells.getUpperY(); iYVolSpace++) { - for(int32_t iXVolSpace = m_regSlicePrevious.getLowerCorner().getX(); iXVolSpace <= m_regSizeInCells.getUpperCorner().getX(); iXVolSpace++) + for(int32_t iXVolSpace = m_regSlicePrevious.getLowerX(); iXVolSpace <= m_regSizeInCells.getUpperX(); iXVolSpace++) { m_sampVolume.setPosition(iXVolSpace,iYVolSpace,iZVolSpace); //Current position - const uint32_t uXRegSpace = m_sampVolume.getPosition().getX() - m_regSizeInVoxels.getLowerCorner().getX(); - const uint32_t uYRegSpace = m_sampVolume.getPosition().getY() - m_regSizeInVoxels.getLowerCorner().getY(); + const uint32_t uXRegSpace = m_sampVolume.getPosition().getX() - m_regSizeInVoxels.getLowerX(); + const uint32_t uYRegSpace = m_sampVolume.getPosition().getY() - m_regSizeInVoxels.getLowerY(); //Determine the index into the edge table which tells us which vertices are inside of the surface const uint8_t iCubeIndex = pPreviousBitmask[uXRegSpace][uYRegSpace]; From 055539ef7595f51ee7e38f2b9517c2c385d6887a Mon Sep 17 00:00:00 2001 From: Daviw Williams Date: Tue, 26 Mar 2013 11:45:53 +0100 Subject: [PATCH 20/30] Reenabled exceptions as we're not using Cubiquity on mobile at the moment. --- library/PolyVoxCore/include/PolyVoxCore/Impl/Config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/PolyVoxCore/include/PolyVoxCore/Impl/Config.h b/library/PolyVoxCore/include/PolyVoxCore/Impl/Config.h index 919950f2..e97e27af 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/Impl/Config.h +++ b/library/PolyVoxCore/include/PolyVoxCore/Impl/Config.h @@ -25,6 +25,6 @@ freely, subject to the following restrictions: #define __PolyVox_Config_H__ #define POLYVOX_ASSERTS_ENABLED -//#define POLYVOX_THROW_ENABLED //Not allowed on Android. +#define POLYVOX_THROW_ENABLED #endif From 2a839e583d5e115c090248bdb14918201541cafb Mon Sep 17 00:00:00 2001 From: Daviw Williams Date: Tue, 7 May 2013 15:41:26 +0200 Subject: [PATCH 21/30] Added stream serialisation to Region. --- library/PolyVoxCore/include/PolyVoxCore/Region.h | 5 +++++ library/PolyVoxCore/source/Region.cpp | 14 ++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/library/PolyVoxCore/include/PolyVoxCore/Region.h b/library/PolyVoxCore/include/PolyVoxCore/Region.h index 32aa7715..a0b276cd 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/Region.h +++ b/library/PolyVoxCore/include/PolyVoxCore/Region.h @@ -207,8 +207,13 @@ namespace PolyVox int32_t m_iUpperZ; }; + // Non-member functions bool intersects(const Region& a, const Region& b); + // Non-member overloaded operators. + /// Stream insertion operator. + std::ostream& operator<<(std::ostream& os, const Region& region); + // Functions to be inlined to to be in the header rather than the .cpp. // 'inline' keyword is used for the definition rather than the declaration. // See also http://www.parashift.com/c++-faq-lite/inline-functions.html diff --git a/library/PolyVoxCore/source/Region.cpp b/library/PolyVoxCore/source/Region.cpp index 32d8454d..bf60ceb2 100644 --- a/library/PolyVoxCore/source/Region.cpp +++ b/library/PolyVoxCore/source/Region.cpp @@ -470,6 +470,7 @@ namespace PolyVox /** * This function only returns true if the regions are really intersecting and not simply touching. */ + bool intersects(const Region& a, const Region& b) { // No intersection if seperated along an axis. @@ -480,4 +481,17 @@ namespace PolyVox // Overlapping on all axes means Regions are intersecting. return true; } + + /** + * Enables the Region to be used intuitively with output streams such as cout. + * \param os The output stream to write to. + * \param region The Region to write to the stream. + * \return A reference to the output stream to allow chaining. + */ + std::ostream& operator<<(std::ostream& os, const Region& region) + { + os << "(" << region.getLowerX() << "," << region.getLowerY() << "," << region.getLowerZ() << + ") to (" << region.getUpperX() << "," << region.getUpperY() << "," << region.getUpperZ() << ")"; + return os; + } } From 618b09df464b742de1905b291f2195f28a26556c Mon Sep 17 00:00:00 2001 From: Daviw Williams Date: Thu, 16 May 2013 16:14:05 +0200 Subject: [PATCH 22/30] Fixed compile errors. --- .../PolyVoxCore/include/PolyVoxCore/Impl/ErrorHandling.h | 6 +++--- library/PolyVoxCore/source/Impl/ErrorHandling.cpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/library/PolyVoxCore/include/PolyVoxCore/Impl/ErrorHandling.h b/library/PolyVoxCore/include/PolyVoxCore/Impl/ErrorHandling.h index 8df554a3..c81c8221 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/Impl/ErrorHandling.h +++ b/library/PolyVoxCore/include/PolyVoxCore/Impl/ErrorHandling.h @@ -121,7 +121,7 @@ namespace PolyVox ss << " Condition: " << #condition << std::endl; \ ss << " Message: " << (message) << std::endl; \ ss << " Location: " << "Line " << __LINE__ << " of " << __FILE__ << std::endl << std::endl; \ - logFatal(ss.str()); \ + PolyVox::logFatal(ss.str()); \ POLYVOX_HALT(); \ } \ } while(0) \ @@ -176,7 +176,7 @@ namespace PolyVox */ #ifdef POLYVOX_THROW_ENABLED #define POLYVOX_THROW(type, message) \ - log(message, LogLevels::Error); \ + PolyVox::logError(message); \ throw type((message)) #else namespace PolyVox @@ -188,7 +188,7 @@ namespace PolyVox } #define POLYVOX_THROW(type, message) \ - log(message, LogLevels::Error); \ + PolyVox::logError(message); \ type except = (type)((message)); \ getThrowHandler()((except), __FILE__, __LINE__) #endif diff --git a/library/PolyVoxCore/source/Impl/ErrorHandling.cpp b/library/PolyVoxCore/source/Impl/ErrorHandling.cpp index c07429df..8e90bb3e 100644 --- a/library/PolyVoxCore/source/Impl/ErrorHandling.cpp +++ b/library/PolyVoxCore/source/Impl/ErrorHandling.cpp @@ -133,7 +133,7 @@ namespace PolyVox ss << " Line: " << line << std::endl; \ ss << " File: " << file << std::endl; \ ss << " Message: " << e.what() << std::endl << std::endl; \ - logFatal(ss.str()); \ + PolyVox::logFatal(ss.str()); \ POLYVOX_HALT(); \ } From 51f9898467abd672fbf207a67074008ee15502d5 Mon Sep 17 00:00:00 2001 From: David Williams Date: Sat, 22 Jun 2013 06:32:26 +0200 Subject: [PATCH 23/30] Reenabled unused vertex removal. --- .../PolyVoxCore/include/PolyVoxCore/CubicSurfaceExtractor.inl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/PolyVoxCore/include/PolyVoxCore/CubicSurfaceExtractor.inl b/library/PolyVoxCore/include/PolyVoxCore/CubicSurfaceExtractor.inl index 331cc99c..79b0b196 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/CubicSurfaceExtractor.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/CubicSurfaceExtractor.inl @@ -188,7 +188,7 @@ namespace PolyVox } m_meshCurrent->m_Region = m_regSizeInVoxels; - //m_meshCurrent->removeUnusedVertices(); + m_meshCurrent->removeUnusedVertices(); m_meshCurrent->m_vecLodRecords.clear(); LodRecord lodRecord; From a10fcf8eccd15bb4695aa557fd27ee40ed48b980 Mon Sep 17 00:00:00 2001 From: David Williams Date: Sat, 27 Jul 2013 15:02:16 +0200 Subject: [PATCH 24/30] Small changes for debugging Cubiquity. --- library/PolyVoxCore/include/PolyVoxCore/Impl/TypeDef.h | 7 +++++++ library/PolyVoxCore/include/PolyVoxCore/Vector.inl | 5 ++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/library/PolyVoxCore/include/PolyVoxCore/Impl/TypeDef.h b/library/PolyVoxCore/include/PolyVoxCore/Impl/TypeDef.h index 4500207e..191e34f4 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/Impl/TypeDef.h +++ b/library/PolyVoxCore/include/PolyVoxCore/Impl/TypeDef.h @@ -117,4 +117,11 @@ freely, subject to the following restrictions: #define polyvox_shared_ptr boost::shared_ptr #endif +//#define USE_LARGE_VOLUME +#ifdef USE_LARGE_VOLUME + #define POLYVOX_VOLUME LargeVolume +#else + #define POLYVOX_VOLUME SimpleVolume +#endif + #endif diff --git a/library/PolyVoxCore/include/PolyVoxCore/Vector.inl b/library/PolyVoxCore/include/PolyVoxCore/Vector.inl index a877fea0..7d7cd207 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/Vector.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/Vector.inl @@ -653,7 +653,10 @@ namespace PolyVox inline void Vector::normalise(void) { float fLength = this->length(); - if(fLength <= 0.0) + + // We could wait until the NAN occurs before throwing, but then we'd have to add some roll-back code. + // This seems like a lot of overhead for a common operation which should rarely go wrong. + if(fLength <= 0.0001) { POLYVOX_THROW(invalid_operation, "Cannot normalise a vector with a length of zero"); } From 0c8013317e070bc7e134dd50d6e0984d7ef4b616 Mon Sep 17 00:00:00 2001 From: David Williams Date: Sun, 28 Jul 2013 16:43:43 +0200 Subject: [PATCH 25/30] Added asserts to catch corrupt data probably resulting from multithreading. --- .../include/PolyVoxCore/MarchingCubesSurfaceExtractor.inl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/PolyVoxCore/include/PolyVoxCore/MarchingCubesSurfaceExtractor.inl b/library/PolyVoxCore/include/PolyVoxCore/MarchingCubesSurfaceExtractor.inl index 44ad5cbe..1702049f 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/MarchingCubesSurfaceExtractor.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/MarchingCubesSurfaceExtractor.inl @@ -433,6 +433,7 @@ namespace PolyVox { m_sampVolume.movePositiveX(); const typename VolumeType::VoxelType v100 = m_sampVolume.getVoxel(); + POLYVOX_ASSERT(v000 != v100, "Attempting to insert vertex between two voxels with the same value"); const Vector3DFloat n100 = computeCentralDifferenceGradient(m_sampVolume); const float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v000)) / static_cast(m_controller.convertToDensity(v100) - m_controller.convertToDensity(v000)); @@ -466,6 +467,7 @@ namespace PolyVox { m_sampVolume.movePositiveY(); const typename VolumeType::VoxelType v010 = m_sampVolume.getVoxel(); + POLYVOX_ASSERT(v000 != v010, "Attempting to insert vertex between two voxels with the same value"); const Vector3DFloat n010 = computeCentralDifferenceGradient(m_sampVolume); const float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v000)) / static_cast(m_controller.convertToDensity(v010) - m_controller.convertToDensity(v000)); @@ -499,6 +501,7 @@ namespace PolyVox { m_sampVolume.movePositiveZ(); const typename VolumeType::VoxelType v001 = m_sampVolume.getVoxel(); + POLYVOX_ASSERT(v000 != v001, "Attempting to insert vertex between two voxels with the same value"); const Vector3DFloat n001 = computeCentralDifferenceGradient(m_sampVolume); const float fInterp = static_cast(m_tThreshold - m_controller.convertToDensity(v000)) / static_cast(m_controller.convertToDensity(v001) - m_controller.convertToDensity(v000)); From 00fab818cccce28d683565c239ea0684e78d8b3d Mon Sep 17 00:00:00 2001 From: David Williams Date: Sun, 28 Jul 2013 16:45:08 +0200 Subject: [PATCH 26/30] Added define to switch between SimpleVolume and LargeVolume in Cubiquity. This is an abuse of Typedef.h but it's a convenient location and just for temporary testing purposes. It won't get merged back into PolyVox. --- library/PolyVoxCore/include/PolyVoxCore/Impl/TypeDef.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/PolyVoxCore/include/PolyVoxCore/Impl/TypeDef.h b/library/PolyVoxCore/include/PolyVoxCore/Impl/TypeDef.h index 191e34f4..24cb8217 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/Impl/TypeDef.h +++ b/library/PolyVoxCore/include/PolyVoxCore/Impl/TypeDef.h @@ -117,7 +117,7 @@ freely, subject to the following restrictions: #define polyvox_shared_ptr boost::shared_ptr #endif -//#define USE_LARGE_VOLUME +#define USE_LARGE_VOLUME #ifdef USE_LARGE_VOLUME #define POLYVOX_VOLUME LargeVolume #else From fcf5b2b055472488a67ce355b8a0c018d1c28626 Mon Sep 17 00:00:00 2001 From: David Williams Date: Fri, 9 Aug 2013 20:32:20 +0200 Subject: [PATCH 27/30] Making Cubiquity version of PolyVox more closely match develop version. --- .../PolyVoxCore/CubicSurfaceExtractor.h | 1 + .../CubicSurfaceExtractorWithNormals.inl | 12 +- .../include/PolyVoxCore/DefaultIsQuadNeeded.h | 4 +- .../PolyVoxCore/Impl/CompilerCapabilities.h | 2 +- .../include/PolyVoxCore/Impl/Utility.h | 2 - .../MarchingCubesSurfaceExtractor.inl | 5 +- .../PolyVoxCore/include/PolyVoxCore/Region.h | 10 +- .../include/PolyVoxCore/SurfaceMesh.h | 4 +- .../include/PolyVoxCore/SurfaceMesh.inl | 4 +- .../include/PolyVoxCore/VolumeResampler.h | 4 - .../include/PolyVoxCore/VolumeResampler.inl | 145 +----------------- library/PolyVoxCore/source/Impl/Utility.cpp | 5 - library/PolyVoxCore/source/Region.cpp | 10 +- 13 files changed, 28 insertions(+), 180 deletions(-) diff --git a/library/PolyVoxCore/include/PolyVoxCore/CubicSurfaceExtractor.h b/library/PolyVoxCore/include/PolyVoxCore/CubicSurfaceExtractor.h index 73477153..86e04020 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/CubicSurfaceExtractor.h +++ b/library/PolyVoxCore/include/PolyVoxCore/CubicSurfaceExtractor.h @@ -118,6 +118,7 @@ namespace PolyVox CubicSurfaceExtractor(VolumeType* volData, Region region, SurfaceMesh >* result, WrapMode eWrapMode = WrapModes::Border, typename VolumeType::VoxelType tBorderValue = typename VolumeType::VoxelType(), bool bMergeQuads = true, IsQuadNeeded isQuadNeeded = IsQuadNeeded()); #endif + void execute(); private: diff --git a/library/PolyVoxCore/include/PolyVoxCore/CubicSurfaceExtractorWithNormals.inl b/library/PolyVoxCore/include/PolyVoxCore/CubicSurfaceExtractorWithNormals.inl index 11b2ca9b..df347b32 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/CubicSurfaceExtractorWithNormals.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/CubicSurfaceExtractorWithNormals.inl @@ -43,16 +43,16 @@ namespace PolyVox Timer timer; m_meshCurrent->clear(); - for(int32_t z = m_regSizeInVoxels.getLowerCorner().getZ(); z < m_regSizeInVoxels.getUpperCorner().getZ(); z++) + for(int32_t z = m_regSizeInVoxels.getLowerZ(); z < m_regSizeInVoxels.getUpperZ(); z++) { - for(int32_t y = m_regSizeInVoxels.getLowerCorner().getY(); y < m_regSizeInVoxels.getUpperCorner().getY(); y++) + for(int32_t y = m_regSizeInVoxels.getLowerY(); y < m_regSizeInVoxels.getUpperY(); y++) { - for(int32_t x = m_regSizeInVoxels.getLowerCorner().getX(); x < m_regSizeInVoxels.getUpperCorner().getX(); x++) + for(int32_t x = m_regSizeInVoxels.getLowerX(); x < m_regSizeInVoxels.getUpperX(); x++) { // these are always positive anyway - float regX = static_cast(x - m_regSizeInVoxels.getLowerCorner().getX()); - float regY = static_cast(y - m_regSizeInVoxels.getLowerCorner().getY()); - float regZ = static_cast(z - m_regSizeInVoxels.getLowerCorner().getZ()); + float regX = static_cast(x - m_regSizeInVoxels.getLowerX()); + float regY = static_cast(y - m_regSizeInVoxels.getLowerY()); + float regZ = static_cast(z - m_regSizeInVoxels.getLowerZ()); uint32_t material = 0; diff --git a/library/PolyVoxCore/include/PolyVoxCore/DefaultIsQuadNeeded.h b/library/PolyVoxCore/include/PolyVoxCore/DefaultIsQuadNeeded.h index ea6cf673..ce011036 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/DefaultIsQuadNeeded.h +++ b/library/PolyVoxCore/include/PolyVoxCore/DefaultIsQuadNeeded.h @@ -32,11 +32,11 @@ namespace PolyVox class DefaultIsQuadNeeded { public: - bool operator()(VoxelType back, VoxelType front, float& materialToUse) + bool operator()(VoxelType back, VoxelType front, uint32_t& materialToUse) { if((back > 0) && (front == 0)) { - materialToUse = static_cast(back); + materialToUse = static_cast(back); return true; } else diff --git a/library/PolyVoxCore/include/PolyVoxCore/Impl/CompilerCapabilities.h b/library/PolyVoxCore/include/PolyVoxCore/Impl/CompilerCapabilities.h index 1884e19e..074c3555 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/Impl/CompilerCapabilities.h +++ b/library/PolyVoxCore/include/PolyVoxCore/Impl/CompilerCapabilities.h @@ -15,7 +15,7 @@ // is a recent version) then assume support for these. #if !defined(_MSC_VER) || (_MSC_VER >= 1600) #define HAS_CXX11_CONSTEXPR - //#define HAS_CXX11_STATIC_ASSERT //This seems to cause issues on Android. + #define HAS_CXX11_STATIC_ASSERT #define HAS_CXX11_CSTDINT_H #define HAS_CXX11_SHARED_PTR #endif diff --git a/library/PolyVoxCore/include/PolyVoxCore/Impl/Utility.h b/library/PolyVoxCore/include/PolyVoxCore/Impl/Utility.h index ccd35ff1..6fa4795e 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/Impl/Utility.h +++ b/library/PolyVoxCore/include/PolyVoxCore/Impl/Utility.h @@ -52,8 +52,6 @@ namespace PolyVox { return (std::min)(high, (std::max)(low, value)); } - - float triangleFilter(float fInput); } #endif diff --git a/library/PolyVoxCore/include/PolyVoxCore/MarchingCubesSurfaceExtractor.inl b/library/PolyVoxCore/include/PolyVoxCore/MarchingCubesSurfaceExtractor.inl index 00c4bfac..5ef22675 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/MarchingCubesSurfaceExtractor.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/MarchingCubesSurfaceExtractor.inl @@ -461,7 +461,6 @@ namespace PolyVox //volume we get the one which is non-zero. Both materials can be non-zero if our volume has a density component. const typename Controller::MaterialType uMaterial000 = m_controller.convertToMaterial(v000); const typename Controller::MaterialType uMaterial100 = m_controller.convertToMaterial(v100); - //const typename Controller::MaterialType uMaterial = (std::max)(uMaterial000, uMaterial100); const typename Controller::MaterialType uMaterial = m_controller.blendMaterials(uMaterial000, uMaterial100, fInterp); const PositionMaterialNormal surfaceVertex(v3dPosition, v3dNormal, uMaterial); @@ -495,7 +494,6 @@ namespace PolyVox //volume we get the one which is non-zero. Both materials can be non-zero if our volume has a density component. const typename Controller::MaterialType uMaterial000 = m_controller.convertToMaterial(v000); const typename Controller::MaterialType uMaterial010 = m_controller.convertToMaterial(v010); - //const typename Controller::MaterialType uMaterial = (std::max)(uMaterial000, uMaterial010); const typename Controller::MaterialType uMaterial = m_controller.blendMaterials(uMaterial000, uMaterial010, fInterp); PositionMaterialNormal surfaceVertex(v3dPosition, v3dNormal, uMaterial); @@ -528,7 +526,6 @@ namespace PolyVox //volume we get the one which is non-zero. Both materials can be non-zero if our volume has a density component. const typename Controller::MaterialType uMaterial000 = m_controller.convertToMaterial(v000); const typename Controller::MaterialType uMaterial001 = m_controller.convertToMaterial(v001); - //const typename Controller::MaterialType uMaterial = (std::max)(uMaterial000, uMaterial001); const typename Controller::MaterialType uMaterial = m_controller.blendMaterials(uMaterial000, uMaterial001, fInterp); const PositionMaterialNormal surfaceVertex(v3dPosition, v3dNormal, uMaterial); @@ -640,4 +637,4 @@ namespace PolyVox }//For each cell } } -} \ No newline at end of file +} diff --git a/library/PolyVoxCore/include/PolyVoxCore/Region.h b/library/PolyVoxCore/include/PolyVoxCore/Region.h index 3a3383f0..8d654cd0 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/Region.h +++ b/library/PolyVoxCore/include/PolyVoxCore/Region.h @@ -141,21 +141,21 @@ namespace PolyVox /// Tests whether the given point is contained in this Region. bool containsPoint(const Vector3DFloat& pos, float boundary = 0.0f) const; /// Tests whether the given point is contained in this Region. - bool containsPoint(int32_t iX, int32_t iY, int32_t iZ, int8_t boundary = 0) const; + bool containsPoint(int32_t iX, int32_t iY, int32_t iZ, uint8_t boundary = 0) const; /// Tests whether the given point is contained in this Region. - bool containsPoint(const Vector3DInt32& pos, int8_t boundary = 0) const; + bool containsPoint(const Vector3DInt32& pos, uint8_t boundary = 0) const; /// Tests whether the given position is contained in the 'x' range of this Region. bool containsPointInX(float pos, float boundary = 0.0f) const; /// Tests whether the given position is contained in the 'x' range of this Region. - bool containsPointInX(int32_t pos, int8_t boundary = 0) const; + bool containsPointInX(int32_t pos, uint8_t boundary = 0) const; /// Tests whether the given position is contained in the 'y' range of this Region. bool containsPointInY(float pos, float boundary = 0.0f) const; /// Tests whether the given position is contained in the 'y' range of this Region. - bool containsPointInY(int32_t pos, int8_t boundary = 0) const; + bool containsPointInY(int32_t pos, uint8_t boundary = 0) const; /// Tests whether the given position is contained in the 'z' range of this Region. bool containsPointInZ(float pos, float boundary = 0.0f) const; /// Tests whether the given position is contained in the 'z' range of this Region. - bool containsPointInZ(int32_t pos, int8_t boundary = 0) const; + bool containsPointInZ(int32_t pos, uint8_t boundary = 0) const; /// Tests whether the given Region is contained in this Region. bool containsRegion(const Region& reg, uint8_t boundary = 0) const; diff --git a/library/PolyVoxCore/include/PolyVoxCore/SurfaceMesh.h b/library/PolyVoxCore/include/PolyVoxCore/SurfaceMesh.h index ce96c227..9ccc58fb 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/SurfaceMesh.h +++ b/library/PolyVoxCore/include/PolyVoxCore/SurfaceMesh.h @@ -95,8 +95,8 @@ namespace PolyVox std::vector m_vecLodRecords; }; - /*template - polyvox_shared_ptr< SurfaceMesh > extractSubset(SurfaceMesh& inputMesh, std::set setMaterials);*/ + template + polyvox_shared_ptr< SurfaceMesh > extractSubset(SurfaceMesh& inputMesh, std::set setMaterials); } #include "PolyVoxCore/SurfaceMesh.inl" diff --git a/library/PolyVoxCore/include/PolyVoxCore/SurfaceMesh.inl b/library/PolyVoxCore/include/PolyVoxCore/SurfaceMesh.inl index e2dcf694..ae2b5b95 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/SurfaceMesh.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/SurfaceMesh.inl @@ -394,7 +394,7 @@ namespace PolyVox } //Currently a free function - think where this needs to go. - /*template + template polyvox_shared_ptr< SurfaceMesh > extractSubset(SurfaceMesh& inputMesh, std::set setMaterials) { polyvox_shared_ptr< SurfaceMesh > result(new SurfaceMesh); @@ -460,7 +460,7 @@ namespace PolyVox result->m_vecLodRecords.push_back(lodRecord); return result; - }*/ + } template void SurfaceMesh::scaleVertices(float amount) diff --git a/library/PolyVoxCore/include/PolyVoxCore/VolumeResampler.h b/library/PolyVoxCore/include/PolyVoxCore/VolumeResampler.h index 271f9d4d..5074a92c 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/VolumeResampler.h +++ b/library/PolyVoxCore/include/PolyVoxCore/VolumeResampler.h @@ -28,9 +28,6 @@ freely, subject to the following restrictions: namespace PolyVox { - template - typename VolumeType::VoxelType interpolatedSample(VolumeType* pVolume, float fPosX, float fPosY, float fPosZ, WrapMode eWrapMode, typename VolumeType::VoxelType tBorder); - template< typename SrcVolumeType, typename DstVolumeType> class VolumeResampler { @@ -42,7 +39,6 @@ namespace PolyVox private: void resampleSameSize(); void resampleArbitrary(); - void resampleBetter(); //Source data SrcVolumeType* m_pVolSrc; diff --git a/library/PolyVoxCore/include/PolyVoxCore/VolumeResampler.inl b/library/PolyVoxCore/include/PolyVoxCore/VolumeResampler.inl index aa241548..2c6c129d 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/VolumeResampler.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/VolumeResampler.inl @@ -23,43 +23,10 @@ freely, subject to the following restrictions: #include "PolyVoxCore/Interpolation.h" -#include "PolyVoxCore/Impl/Utility.h" - #include namespace PolyVox { - // Takes an interpolated sample of the volume data. - template - typename VolumeType::VoxelType interpolatedSample(VolumeType* pVolume, float fPosX, float fPosY, float fPosZ, WrapMode eWrapMode, typename VolumeType::VoxelType tBorder) - { - float fFloorX = floor(fPosX); - float fFloorY = floor(fPosY); - float fFloorZ = floor(fPosZ); - - float fInterpX = fPosX - fFloorX; - float fInterpY = fPosY - fFloorY; - float fInterpZ = fPosZ - fFloorZ; - - // Conditional logic required to round negative floats correctly - int32_t iX = static_cast(fFloorX > 0.0f ? fFloorX + 0.5f : fFloorX - 0.5f); - int32_t iY = static_cast(fFloorY > 0.0f ? fFloorY + 0.5f : fFloorY - 0.5f); - int32_t iZ = static_cast(fFloorZ > 0.0f ? fFloorZ + 0.5f : fFloorZ - 0.5f); - - const typename VolumeType::VoxelType& voxel000 = pVolume->getVoxelWithWrapping(iX, iY, iZ, eWrapMode, tBorder); - const typename VolumeType::VoxelType& voxel001 = pVolume->getVoxelWithWrapping(iX, iY, iZ + 1, eWrapMode, tBorder); - const typename VolumeType::VoxelType& voxel010 = pVolume->getVoxelWithWrapping(iX, iY + 1, iZ, eWrapMode, tBorder); - const typename VolumeType::VoxelType& voxel011 = pVolume->getVoxelWithWrapping(iX, iY + 1, iZ + 1, eWrapMode, tBorder); - const typename VolumeType::VoxelType& voxel100 = pVolume->getVoxelWithWrapping(iX + 1, iY, iZ, eWrapMode, tBorder); - const typename VolumeType::VoxelType& voxel101 = pVolume->getVoxelWithWrapping(iX + 1, iY, iZ + 1, eWrapMode, tBorder); - const typename VolumeType::VoxelType& voxel110 = pVolume->getVoxelWithWrapping(iX + 1, iY + 1, iZ, eWrapMode, tBorder); - const typename VolumeType::VoxelType& voxel111 = pVolume->getVoxelWithWrapping(iX + 1, iY + 1, iZ + 1, eWrapMode, tBorder); - - typename VolumeType::VoxelType tInterpolatedValue = PolyVox::trilerp(voxel000,voxel100,voxel010,voxel110,voxel001,voxel101,voxel011,voxel111,fInterpX,fInterpY,fInterpZ); - - return tInterpolatedValue; - } - /** * \param pVolSrc * \param regSrc @@ -86,16 +53,14 @@ namespace PolyVox int32_t uDstHeight = m_regDst.getUpperY() - m_regDst.getLowerY() + 1; int32_t uDstDepth = m_regDst.getUpperZ() - m_regDst.getLowerZ() + 1; - /*if((uSrcWidth == uDstWidth) && (uSrcHeight == uDstHeight) && (uSrcDepth == uDstDepth)) + if((uSrcWidth == uDstWidth) && (uSrcHeight == uDstHeight) && (uSrcDepth == uDstDepth)) { resampleSameSize(); } else { resampleArbitrary(); - }*/ - - resampleBetter(); + } } template< typename SrcVolumeType, typename DstVolumeType> @@ -162,7 +127,7 @@ namespace PolyVox sy = modf(sy, &dummy); sz = modf(sz, &dummy); - typename SrcVolumeType::VoxelType tInterpolatedValue = trilerp(voxel000,voxel100,voxel010,voxel110,voxel001,voxel101,voxel011,voxel111,sx,sy,sz); + typename SrcVolumeType::VoxelType tInterpolatedValue = trilerp(voxel000,voxel100,voxel010,voxel110,voxel001,voxel101,voxel011,voxel111,sx,sy,sz); typename DstVolumeType::VoxelType result = static_cast(tInterpolatedValue); m_pVolDst->setVoxelAt(dx,dy,dz,result); @@ -170,108 +135,4 @@ namespace PolyVox } } } - - template< typename SrcVolumeType, typename DstVolumeType> - void VolumeResampler::resampleBetter() - { - float srcWidth = m_regSrc.getWidthInCells(); - float srcHeight = m_regSrc.getHeightInCells(); - float srcDepth = m_regSrc.getDepthInCells(); - - float dstWidth = m_regDst.getWidthInCells(); - float dstHeight = m_regDst.getHeightInCells(); - float dstDepth = m_regDst.getDepthInCells(); - - float fScaleX = srcWidth / dstWidth; - float fScaleY = srcHeight / dstHeight; - float fScaleZ = srcDepth / dstDepth; - - typename SrcVolumeType::Sampler sampler(m_pVolSrc); - - // Should use SrcVolumeType? Or new template parameter? - Region regDownscaledX(0, 0, 0, m_regDst.getWidthInVoxels()-1, m_regSrc.getHeightInVoxels()-1, m_regSrc.getDepthInVoxels()-1); - SrcVolumeType volDownscaledX(regDownscaledX); - - for(int32_t tz = regDownscaledX.getLowerZ(); tz <= regDownscaledX.getUpperZ(); tz++) - { - for(int32_t ty = regDownscaledX.getLowerY(); ty <= regDownscaledX.getUpperY(); ty++) - { - for(int32_t tx = regDownscaledX.getLowerX(); tx <= regDownscaledX.getUpperX(); tx++) - { - float sx = (tx * fScaleX) + m_regSrc.getLowerCorner().getX(); - float sy = (ty ) + m_regSrc.getLowerCorner().getY(); - float sz = (tz ) + m_regSrc.getLowerCorner().getZ(); - - typename SrcVolumeType::VoxelType result = m_pVolSrc->getVoxelWithWrapping(sx, sy, sz, WrapModes::Border); - - //typename SrcVolumeType::VoxelType result = interpolatedSample(m_pVolSrc, sx, sy, sz, WrapModes::Border, SrcVolumeType::VoxelType(0)); - - volDownscaledX.setVoxelAt(tx, ty, tz, result); - } - } - } - - //Now downscale in y - Region regDownscaledXAndY(0, 0, 0, m_regDst.getWidthInVoxels()-1, m_regDst.getHeightInVoxels()-1, m_regSrc.getDepthInVoxels()-1); - SrcVolumeType volDownscaledXAndY(regDownscaledXAndY); - - for(int32_t tz = regDownscaledXAndY.getLowerZ(); tz <= regDownscaledXAndY.getUpperZ(); tz++) - { - for(int32_t ty = regDownscaledXAndY.getLowerY(); ty <= regDownscaledXAndY.getUpperY(); ty++) - { - for(int32_t tx = regDownscaledXAndY.getLowerX(); tx <= regDownscaledXAndY.getUpperX(); tx++) - { - float sx = (tx ); - float sy = (ty * fScaleY); - float sz = (tz ); - - typename SrcVolumeType::VoxelType result = volDownscaledX.getVoxelWithWrapping(sx, sy, sz, WrapModes::Border); - - volDownscaledXAndY.setVoxelAt(tx, ty, tz, result); - } - } - } - - //Now copy and downscale to dst. - //Region regDst = m_pVolDst->getEnclosingRegion(); - - for(int32_t tz = m_regDst.getLowerZ(); tz <= m_regDst.getUpperZ(); tz++) - { - for(int32_t ty = m_regDst.getLowerY(); ty <= m_regDst.getUpperY(); ty++) - { - for(int32_t tx = m_regDst.getLowerX(); tx <= m_regDst.getUpperX(); tx++) - { - float sx = (tx - m_regDst.getLowerX()); - float sy = (ty - m_regDst.getLowerY()); - float sLowerZ = ((tz - 1) - m_regDst.getLowerZ()) * fScaleZ; - float sCentreZ = ((tz ) - m_regDst.getLowerZ()) * fScaleZ; - float sUpperZ = ((tz + 1) - m_regDst.getLowerZ()) * fScaleZ; - - float sumOfWeights = 0.0f; - //typename SrcVolumeType::VoxelType tSum = SrcVolumeType::VoxelType(0); - - //We should be able to use a higher range MultiMaterial rather than needing to use a Vector of floats. - //We shouold also probably support an Accumulation type rather than hard coding. - Vector<4, float> vecSum(0.0, 0.0, 0.0, 0.0); - - for(float sz = sLowerZ; sz <= sUpperZ; sz += 1.0) - { - float weight = triangleFilter(sz - sCentreZ); - sumOfWeights += weight; - - //This is wrong! There's no need to do interpolation. Just multiply the sameple by the correct kernel value. - Vector<4, float> sample = interpolatedSample(&volDownscaledXAndY, sx, sy, sz, WrapModes::Border, SrcVolumeType::VoxelType()); - - vecSum += (sample * weight); - } - - vecSum /= sumOfWeights; //Should divide by 'norm' - - typename SrcVolumeType::VoxelType tResult = vecSum; //Should divide by 'norm' - - m_pVolDst->setVoxelAt(tx, ty, tz, tResult); - } - } - } - } } diff --git a/library/PolyVoxCore/source/Impl/Utility.cpp b/library/PolyVoxCore/source/Impl/Utility.cpp index 555e947c..1c9c152f 100644 --- a/library/PolyVoxCore/source/Impl/Utility.cpp +++ b/library/PolyVoxCore/source/Impl/Utility.cpp @@ -69,9 +69,4 @@ namespace PolyVox v++; return v; } - - float triangleFilter(float fInput) - { - return (std::max)(1.0f - (std::abs)(fInput), 0.0f); - } } diff --git a/library/PolyVoxCore/source/Region.cpp b/library/PolyVoxCore/source/Region.cpp index 5e248dc5..50e837af 100644 --- a/library/PolyVoxCore/source/Region.cpp +++ b/library/PolyVoxCore/source/Region.cpp @@ -201,7 +201,7 @@ namespace PolyVox * \param iZ The 'z' position of the point to test. * \param boundary The desired boundary value. */ - bool Region::containsPoint(int32_t iX, int32_t iY, int32_t iZ, int8_t boundary) const + bool Region::containsPoint(int32_t iX, int32_t iY, int32_t iZ, uint8_t boundary) const { return (iX <= m_iUpperX - boundary) && (iY <= m_iUpperY - boundary) @@ -218,7 +218,7 @@ namespace PolyVox * \param pos The position to test. * \param boundary The desired boundary value. */ - bool Region::containsPoint(const Vector3DInt32& pos, int8_t boundary) const + bool Region::containsPoint(const Vector3DInt32& pos, uint8_t boundary) const { return containsPoint(pos.getX(), pos.getY(), pos.getZ(), boundary); } @@ -243,7 +243,7 @@ namespace PolyVox * \param pos The position to test. * \param boundary The desired boundary value. */ - bool Region::containsPointInX(int32_t pos, int8_t boundary) const + bool Region::containsPointInX(int32_t pos, uint8_t boundary) const { return (pos <= m_iUpperX - boundary) && (pos >= m_iLowerX + boundary); @@ -269,7 +269,7 @@ namespace PolyVox * \param pos The position to test. * \param boundary The desired boundary value. */ - bool Region::containsPointInY(int32_t pos, int8_t boundary) const + bool Region::containsPointInY(int32_t pos, uint8_t boundary) const { return (pos <= m_iUpperY - boundary) && (pos >= m_iLowerY + boundary); @@ -295,7 +295,7 @@ namespace PolyVox * \param pos The position to test. * \param boundary The desired boundary value. */ - bool Region::containsPointInZ(int32_t pos, int8_t boundary) const + bool Region::containsPointInZ(int32_t pos, uint8_t boundary) const { return (pos <= m_iUpperZ - boundary) && (pos >= m_iLowerZ + boundary); From 31b59702bea85d11ca554ddd28c244a60c898ef2 Mon Sep 17 00:00:00 2001 From: Daviw Williams Date: Mon, 18 Nov 2013 16:57:37 +0100 Subject: [PATCH 28/30] We're committed to LargeVolume now, so we don't need the define to switch volume types. --- library/PolyVoxCore/include/PolyVoxCore/Impl/TypeDef.h | 7 ------- 1 file changed, 7 deletions(-) diff --git a/library/PolyVoxCore/include/PolyVoxCore/Impl/TypeDef.h b/library/PolyVoxCore/include/PolyVoxCore/Impl/TypeDef.h index 24cb8217..4500207e 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/Impl/TypeDef.h +++ b/library/PolyVoxCore/include/PolyVoxCore/Impl/TypeDef.h @@ -117,11 +117,4 @@ freely, subject to the following restrictions: #define polyvox_shared_ptr boost::shared_ptr #endif -#define USE_LARGE_VOLUME -#ifdef USE_LARGE_VOLUME - #define POLYVOX_VOLUME LargeVolume -#else - #define POLYVOX_VOLUME SimpleVolume -#endif - #endif From d06650172afa2e3a660046bea77a8fdd79fbff42 Mon Sep 17 00:00:00 2001 From: David Williams Date: Sun, 16 Mar 2014 21:13:15 +0100 Subject: [PATCH 29/30] Added missing header which was causing problems when compiling Cubiquity on Linux. --- library/PolyVoxCore/include/PolyVoxCore/UncompressedBlock.inl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/PolyVoxCore/include/PolyVoxCore/UncompressedBlock.inl b/library/PolyVoxCore/include/PolyVoxCore/UncompressedBlock.inl index 4d506d74..2239b267 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/UncompressedBlock.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/UncompressedBlock.inl @@ -21,6 +21,8 @@ freely, subject to the following restrictions: distribution. *******************************************************************************/ +#include "PolyVoxCore/Impl/Utility.h" + namespace PolyVox { template From a34c1063824e18e5d93bf4b3274b24c570603118 Mon Sep 17 00:00:00 2001 From: David Williams Date: Sun, 11 May 2014 20:34:41 +0200 Subject: [PATCH 30/30] I accidentally merged the 'cubiquity-version' feature back into develop. It seems I can't simply reverse this commit (at least through SourceTree ) because it was a merge, so I'm having to simply revert the contents of the commit (i.e. the files). Bit of a mess! --- .../PolyVoxCore/CubicSurfaceExtractor.h | 10 +- .../PolyVoxCore/CubicSurfaceExtractor.inl | 12 +-- .../MarchingCubesSurfaceExtractor.h | 6 +- .../MarchingCubesSurfaceExtractor.inl | 10 +- .../PolyVoxCore/PolyVoxForwardDeclarations.h | 4 +- .../include/PolyVoxCore/UncompressedBlock.inl | 2 - .../include/PolyVoxCore/VertexTypes.h | 92 ++++--------------- library/PolyVoxCore/source/VertexTypes.cpp | 77 ++++++++++++++++ 8 files changed, 115 insertions(+), 98 deletions(-) diff --git a/library/PolyVoxCore/include/PolyVoxCore/CubicSurfaceExtractor.h b/library/PolyVoxCore/include/PolyVoxCore/CubicSurfaceExtractor.h index 86e04020..a225a3b5 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/CubicSurfaceExtractor.h +++ b/library/PolyVoxCore/include/PolyVoxCore/CubicSurfaceExtractor.h @@ -82,7 +82,7 @@ namespace PolyVox struct IndexAndMaterial { int32_t iIndex; - typename VolumeType::VoxelType uMaterial; + int32_t uMaterial; //Should actually use the material type here, but this is ok for now. }; enum FaceNames @@ -113,16 +113,16 @@ namespace PolyVox // This is a bit ugly - it seems that the C++03 syntax is different from the C++11 syntax? See this thread: http://stackoverflow.com/questions/6076015/typename-outside-of-template // Long term we should probably come back to this and if the #ifdef is still needed then maybe it should check for C++11 mode instead of MSVC? #if defined(_MSC_VER) - CubicSurfaceExtractor(VolumeType* volData, Region region, SurfaceMesh >* result, WrapMode eWrapMode = WrapModes::Border, typename VolumeType::VoxelType tBorderValue = VolumeType::VoxelType(), bool bMergeQuads = true, IsQuadNeeded isQuadNeeded = IsQuadNeeded()); + CubicSurfaceExtractor(VolumeType* volData, Region region, SurfaceMesh* result, WrapMode eWrapMode = WrapModes::Border, typename VolumeType::VoxelType tBorderValue = VolumeType::VoxelType(), bool bMergeQuads = true, IsQuadNeeded isQuadNeeded = IsQuadNeeded()); #else - CubicSurfaceExtractor(VolumeType* volData, Region region, SurfaceMesh >* result, WrapMode eWrapMode = WrapModes::Border, typename VolumeType::VoxelType tBorderValue = typename VolumeType::VoxelType(), bool bMergeQuads = true, IsQuadNeeded isQuadNeeded = IsQuadNeeded()); + CubicSurfaceExtractor(VolumeType* volData, Region region, SurfaceMesh* result, WrapMode eWrapMode = WrapModes::Border, typename VolumeType::VoxelType tBorderValue = typename VolumeType::VoxelType(), bool bMergeQuads = true, IsQuadNeeded isQuadNeeded = IsQuadNeeded()); #endif void execute(); private: - int32_t addVertex(uint32_t uX, uint32_t uY, uint32_t uZ, typename VolumeType::VoxelType uMaterial, Array<3, IndexAndMaterial>& existingVertices); + int32_t addVertex(uint32_t uX, uint32_t uY, uint32_t uZ, uint32_t uMaterial, Array<3, IndexAndMaterial>& existingVertices); bool performQuadMerging(std::list& quads); bool mergeQuads(Quad& q1, Quad& q2); @@ -135,7 +135,7 @@ namespace PolyVox Region m_regSizeInVoxels; //The surface patch we are currently filling. - SurfaceMesh >* m_meshCurrent; + SurfaceMesh* m_meshCurrent; //Used to avoid creating duplicate vertices. Array<3, IndexAndMaterial> m_previousSliceVertices; diff --git a/library/PolyVoxCore/include/PolyVoxCore/CubicSurfaceExtractor.inl b/library/PolyVoxCore/include/PolyVoxCore/CubicSurfaceExtractor.inl index 9f8b4650..3174c63f 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/CubicSurfaceExtractor.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/CubicSurfaceExtractor.inl @@ -36,7 +36,7 @@ namespace PolyVox const uint32_t CubicSurfaceExtractor::MaxVerticesPerPosition = 8; template - CubicSurfaceExtractor::CubicSurfaceExtractor(VolumeType* volData, Region region, SurfaceMesh >* result, WrapMode eWrapMode, typename VolumeType::VoxelType tBorderValue, bool bMergeQuads, IsQuadNeeded isQuadNeeded) + CubicSurfaceExtractor::CubicSurfaceExtractor(VolumeType* volData, Region region, SurfaceMesh* result, WrapMode eWrapMode, typename VolumeType::VoxelType tBorderValue, bool bMergeQuads, IsQuadNeeded isQuadNeeded) :m_volData(volData) ,m_regSizeInVoxels(region) ,m_meshCurrent(result) @@ -88,7 +88,7 @@ namespace PolyVox { uint32_t regX = x - m_regSizeInVoxels.getLowerX(); - typename VolumeType::VoxelType material; //Filled in by callback + uint32_t material; //Filled in by callback typename VolumeType::VoxelType currentVoxel = volumeSampler.getVoxel(); typename VolumeType::VoxelType negXVoxel = volumeSampler.peekVoxel1nx0py0pz(); typename VolumeType::VoxelType negYVoxel = volumeSampler.peekVoxel0px1ny0pz(); @@ -205,7 +205,7 @@ namespace PolyVox } template - int32_t CubicSurfaceExtractor::addVertex(uint32_t uX, uint32_t uY, uint32_t uZ, typename VolumeType::VoxelType uMaterialIn, Array<3, IndexAndMaterial>& existingVertices) + int32_t CubicSurfaceExtractor::addVertex(uint32_t uX, uint32_t uY, uint32_t uZ, uint32_t uMaterialIn, Array<3, IndexAndMaterial>& existingVertices) { for(uint32_t ct = 0; ct < MaxVerticesPerPosition; ct++) { @@ -214,14 +214,14 @@ namespace PolyVox if(rEntry.iIndex == -1) { //No vertices matched and we've now hit an empty space. Fill it by creating a vertex. The 0.5f offset is because vertices set between voxels in order to build cubes around them. - rEntry.iIndex = m_meshCurrent->addVertex(PositionMaterial (Vector3DFloat(static_cast(uX) - 0.5f, static_cast(uY) - 0.5f, static_cast(uZ) - 0.5f), uMaterialIn)); + rEntry.iIndex = m_meshCurrent->addVertex(PositionMaterial(Vector3DFloat(static_cast(uX) - 0.5f, static_cast(uY) - 0.5f, static_cast(uZ) - 0.5f), uMaterialIn)); rEntry.uMaterial = uMaterialIn; return rEntry.iIndex; } //If we have an existing vertex and the material matches then we can return it. - if(rEntry.uMaterial == uMaterialIn) + if(rEntry.uMaterial == static_cast(uMaterialIn)) { return rEntry.iIndex; } @@ -268,7 +268,7 @@ namespace PolyVox { //All four vertices of a given quad have the same material, //so just check that the first pair of vertices match. - if(m_meshCurrent->getVertices()[q1.vertices[0]].getMaterial() == m_meshCurrent->getVertices()[q2.vertices[0]].getMaterial()) + if(std::abs(m_meshCurrent->getVertices()[q1.vertices[0]].getMaterial() - m_meshCurrent->getVertices()[q2.vertices[0]].getMaterial()) < 0.001) { //Now check whether quad 2 is adjacent to quad one by comparing vertices. //Adjacent quads must share two vertices, and the second quad could be to the diff --git a/library/PolyVoxCore/include/PolyVoxCore/MarchingCubesSurfaceExtractor.h b/library/PolyVoxCore/include/PolyVoxCore/MarchingCubesSurfaceExtractor.h index 2e9897f9..31803437 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/MarchingCubesSurfaceExtractor.h +++ b/library/PolyVoxCore/include/PolyVoxCore/MarchingCubesSurfaceExtractor.h @@ -41,9 +41,9 @@ namespace PolyVox // This is a bit ugly - it seems that the C++03 syntax is different from the C++11 syntax? See this thread: http://stackoverflow.com/questions/6076015/typename-outside-of-template // Long term we should probably come back to this and if the #ifdef is still needed then maybe it should check for C++11 mode instead of MSVC? #if defined(_MSC_VER) - MarchingCubesSurfaceExtractor(VolumeType* volData, Region region, SurfaceMesh >* result, WrapMode eWrapMode = WrapModes::Border, typename VolumeType::VoxelType tBorderValue = VolumeType::VoxelType(), Controller controller = Controller()); + MarchingCubesSurfaceExtractor(VolumeType* volData, Region region, SurfaceMesh* result, WrapMode eWrapMode = WrapModes::Border, typename VolumeType::VoxelType tBorderValue = VolumeType::VoxelType(), Controller controller = Controller()); #else - MarchingCubesSurfaceExtractor(VolumeType* volData, Region region, SurfaceMesh >* result, WrapMode eWrapMode = WrapModes::Border, typename VolumeType::VoxelType tBorderValue = typename VolumeType::VoxelType(), Controller controller = Controller()); + MarchingCubesSurfaceExtractor(VolumeType* volData, Region region, SurfaceMesh* result, WrapMode eWrapMode = WrapModes::Border, typename VolumeType::VoxelType tBorderValue = typename VolumeType::VoxelType(), Controller controller = Controller()); #endif void execute(); @@ -193,7 +193,7 @@ namespace PolyVox uint32_t m_uNoOfOccupiedCells; //The surface patch we are currently filling. - SurfaceMesh >* m_meshCurrent; + SurfaceMesh* m_meshCurrent; //Information about the region we are currently processing Region m_regSizeInVoxels; diff --git a/library/PolyVoxCore/include/PolyVoxCore/MarchingCubesSurfaceExtractor.inl b/library/PolyVoxCore/include/PolyVoxCore/MarchingCubesSurfaceExtractor.inl index ac65966b..97b97e79 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/MarchingCubesSurfaceExtractor.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/MarchingCubesSurfaceExtractor.inl @@ -26,7 +26,7 @@ freely, subject to the following restrictions: namespace PolyVox { template - MarchingCubesSurfaceExtractor::MarchingCubesSurfaceExtractor(VolumeType* volData, Region region, SurfaceMesh >* result, WrapMode eWrapMode, typename VolumeType::VoxelType tBorderValue, Controller controller) + MarchingCubesSurfaceExtractor::MarchingCubesSurfaceExtractor(VolumeType* volData, Region region, SurfaceMesh* result, WrapMode eWrapMode, typename VolumeType::VoxelType tBorderValue, Controller controller) :m_volData(volData) ,m_sampVolume(volData) ,m_meshCurrent(result) @@ -459,7 +459,7 @@ namespace PolyVox // Allow the controller to decide how the material should be derived from the voxels. const typename Controller::MaterialType uMaterial = m_controller.blendMaterials(v000, v100, fInterp); - const PositionMaterialNormal surfaceVertex(v3dPosition, v3dNormal, uMaterial); + const PositionMaterialNormal surfaceVertex(v3dPosition, v3dNormal, static_cast(uMaterial)); const uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex); m_pCurrentVertexIndicesX[iXVolSpace - m_regSizeInVoxels.getLowerX()][iYVolSpace - m_regSizeInVoxels.getLowerY()] = uLastVertexIndex; @@ -488,8 +488,8 @@ namespace PolyVox // Allow the controller to decide how the material should be derived from the voxels. const typename Controller::MaterialType uMaterial = m_controller.blendMaterials(v000, v010, fInterp); - PositionMaterialNormal surfaceVertex(v3dPosition, v3dNormal, uMaterial); - uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex); + const PositionMaterialNormal surfaceVertex(v3dPosition, v3dNormal, static_cast(uMaterial)); + const uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex); m_pCurrentVertexIndicesY[iXVolSpace - m_regSizeInVoxels.getLowerX()][iYVolSpace - m_regSizeInVoxels.getLowerY()] = uLastVertexIndex; m_sampVolume.moveNegativeY(); @@ -516,7 +516,7 @@ namespace PolyVox // Allow the controller to decide how the material should be derived from the voxels. const typename Controller::MaterialType uMaterial = m_controller.blendMaterials(v000, v001, fInterp); - const PositionMaterialNormal surfaceVertex(v3dPosition, v3dNormal, uMaterial); + const PositionMaterialNormal surfaceVertex(v3dPosition, v3dNormal, static_cast(uMaterial)); const uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex); m_pCurrentVertexIndicesZ[iXVolSpace - m_regSizeInVoxels.getLowerX()][iYVolSpace - m_regSizeInVoxels.getLowerY()] = uLastVertexIndex; diff --git a/library/PolyVoxCore/include/PolyVoxCore/PolyVoxForwardDeclarations.h b/library/PolyVoxCore/include/PolyVoxCore/PolyVoxForwardDeclarations.h index 051fb93e..702e786a 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/PolyVoxForwardDeclarations.h +++ b/library/PolyVoxCore/include/PolyVoxCore/PolyVoxForwardDeclarations.h @@ -132,12 +132,12 @@ namespace PolyVox //////////////////////////////////////////////////////////////////////////////// // PositionMaterial //////////////////////////////////////////////////////////////////////////////// - template class PositionMaterial; + class PositionMaterial; //////////////////////////////////////////////////////////////////////////////// // PositionMaterialNormal //////////////////////////////////////////////////////////////////////////////// - template class PositionMaterialNormal; + class PositionMaterialNormal; //////////////////////////////////////////////////////////////////////////////// // RawVolume diff --git a/library/PolyVoxCore/include/PolyVoxCore/UncompressedBlock.inl b/library/PolyVoxCore/include/PolyVoxCore/UncompressedBlock.inl index 2239b267..4d506d74 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/UncompressedBlock.inl +++ b/library/PolyVoxCore/include/PolyVoxCore/UncompressedBlock.inl @@ -21,8 +21,6 @@ freely, subject to the following restrictions: distribution. *******************************************************************************/ -#include "PolyVoxCore/Impl/Utility.h" - namespace PolyVox { template diff --git a/library/PolyVoxCore/include/PolyVoxCore/VertexTypes.h b/library/PolyVoxCore/include/PolyVoxCore/VertexTypes.h index 3eb18072..033fad6b 100644 --- a/library/PolyVoxCore/include/PolyVoxCore/VertexTypes.h +++ b/library/PolyVoxCore/include/PolyVoxCore/VertexTypes.h @@ -36,107 +36,49 @@ namespace PolyVox #ifdef SWIG class PositionMaterial #else - template class POLYVOX_API PositionMaterial #endif { public: - PositionMaterial() - { - } + PositionMaterial(); + PositionMaterial(Vector3DFloat positionToSet, float materialToSet); - PositionMaterial(Vector3DFloat positionToSet, MaterialType materialToSet) - :position(positionToSet) - ,material(materialToSet) - { - } + float getMaterial(void) const; + const Vector3DFloat& getPosition(void) const; - MaterialType getMaterial(void) const - { - return material; - } - - const Vector3DFloat& getPosition(void) const - { - return position; - } - - void setMaterial(MaterialType materialToSet) - { - material = materialToSet; - } - - void setPosition(const Vector3DFloat& positionToSet) - { - position = positionToSet; - } + void setMaterial(float materialToSet); + void setPosition(const Vector3DFloat& positionToSet); public: //Nicely fits into four floats. Vector3DFloat position; - MaterialType material; + float material; }; #ifdef SWIG class PositionMaterialNormal #else - template class POLYVOX_API PositionMaterialNormal #endif { public: - PositionMaterialNormal() - { - } + PositionMaterialNormal(); + PositionMaterialNormal(Vector3DFloat positionToSet, float materialToSet); + PositionMaterialNormal(Vector3DFloat positionToSet, Vector3DFloat normalToSet, float materialToSet); - PositionMaterialNormal(Vector3DFloat positionToSet, MaterialType materialToSet) - :position(positionToSet) - ,material(materialToSet) - { - } + float getMaterial(void) const; + const Vector3DFloat& getNormal(void) const; + const Vector3DFloat& getPosition(void) const; - PositionMaterialNormal(Vector3DFloat positionToSet, Vector3DFloat normalToSet, MaterialType materialToSet) - :position(positionToSet) - ,normal(normalToSet) - ,material(materialToSet) - { - } - - MaterialType getMaterial(void) const - { - return material; - } - - const Vector3DFloat& getNormal(void) const - { - return normal; - } - - const Vector3DFloat& getPosition(void) const - { - return position; - } - - void setMaterial(MaterialType materialToSet) - { - material = materialToSet; - } - - void setNormal(const Vector3DFloat& normalToSet) - { - normal = normalToSet; - } - - void setPosition(const Vector3DFloat& positionToSet) - { - position = positionToSet; - } + void setMaterial(float materialToSet); + void setNormal(const Vector3DFloat& normalToSet); + void setPosition(const Vector3DFloat& positionToSet); public: //Nicely fits into seven floats, meaning we //can squeeze in one more for material blending. Vector3DFloat position; Vector3DFloat normal; - MaterialType material; //FIXME: This shouldn't be float on CPU? + float material; //FIXME: This shouldn't be float on CPU? }; } diff --git a/library/PolyVoxCore/source/VertexTypes.cpp b/library/PolyVoxCore/source/VertexTypes.cpp index b4dca237..22a55721 100644 --- a/library/PolyVoxCore/source/VertexTypes.cpp +++ b/library/PolyVoxCore/source/VertexTypes.cpp @@ -25,9 +25,86 @@ freely, subject to the following restrictions: namespace PolyVox { + PositionMaterialNormal::PositionMaterialNormal() + { + } + + PositionMaterialNormal::PositionMaterialNormal(Vector3DFloat positionToSet, float materialToSet) + :position(positionToSet) + ,material(materialToSet) + { + + } + + PositionMaterialNormal::PositionMaterialNormal(Vector3DFloat positionToSet, Vector3DFloat normalToSet, float materialToSet) + :position(positionToSet) + ,normal(normalToSet) + ,material(materialToSet) + { + } + + float PositionMaterialNormal::getMaterial(void) const + { + return material; + } + + const Vector3DFloat& PositionMaterialNormal::getNormal(void) const + { + return normal; + } + + const Vector3DFloat& PositionMaterialNormal::getPosition(void) const + { + return position; + } + + void PositionMaterialNormal::setMaterial(float materialToSet) + { + material = materialToSet; + } + + void PositionMaterialNormal::setNormal(const Vector3DFloat& normalToSet) + { + normal = normalToSet; + } + + void PositionMaterialNormal::setPosition(const Vector3DFloat& positionToSet) + { + position = positionToSet; + } + //////////////////////////////////////////////////////////////////////////////// // PositionMaterial //////////////////////////////////////////////////////////////////////////////// + PositionMaterial::PositionMaterial() + { + } + + PositionMaterial::PositionMaterial(Vector3DFloat positionToSet, float materialToSet) + :position(positionToSet) + ,material(materialToSet) + { + + } + + float PositionMaterial::getMaterial(void) const + { + return material; + } + + const Vector3DFloat& PositionMaterial::getPosition(void) const + { + return position; + } + void PositionMaterial::setMaterial(float materialToSet) + { + material = materialToSet; + } + + void PositionMaterial::setPosition(const Vector3DFloat& positionToSet) + { + position = positionToSet; + } }