• Main Page
  • Related Pages
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

PolyVoxCore/include/PolyVoxCore/SurfaceExtractor.h

Go to the documentation of this file.
00001 /*******************************************************************************
00002 Copyright (c) 2005-2009 David Williams
00003 
00004 This software is provided 'as-is', without any express or implied
00005 warranty. In no event will the authors be held liable for any damages
00006 arising from the use of this software.
00007 
00008 Permission is granted to anyone to use this software for any purpose,
00009 including commercial applications, and to alter it and redistribute it
00010 freely, subject to the following restrictions:
00011 
00012     1. The origin of this software must not be misrepresented; you must not
00013     claim that you wrote the original software. If you use this software
00014     in a product, an acknowledgment in the product documentation would be
00015     appreciated but is not required.
00016 
00017     2. Altered source versions must be plainly marked as such, and must not be
00018     misrepresented as being the original software.
00019 
00020     3. This notice may not be removed or altered from any source
00021     distribution.   
00022 *******************************************************************************/
00023 
00024 #ifndef __PolyVox_SurfaceExtractor_H__
00025 #define __PolyVox_SurfaceExtractor_H__
00026 
00027 #include "PolyVoxImpl/MarchingCubesTables.h"
00028 #include "PolyVoxImpl/TypeDef.h"
00029 
00030 #include "PolyVoxCore/Array.h"
00031 #include "PolyVoxCore/SurfaceMesh.h"
00032 
00033 namespace PolyVox
00034 {
00035     template< template<typename> class VolumeType, typename VoxelType>
00036     class SurfaceExtractor
00037     {
00038     public:
00039         SurfaceExtractor(VolumeType<VoxelType>* volData, Region region, SurfaceMesh<PositionMaterialNormal>* result);
00040 
00041         void execute();
00042 
00043     private:
00044         //Compute the cell bitmask for a particular slice in z.
00045         template<bool isPrevZAvail>
00046         uint32_t computeBitmaskForSlice(const Array2DUint8& pPreviousBitmask, Array2DUint8& pCurrentBitmask);
00047 
00048         //Compute the cell bitmask for a given cell.
00049         template<bool isPrevXAvail, bool isPrevYAvail, bool isPrevZAvail>
00050         void computeBitmaskForCell(const Array2DUint8& pPreviousBitmask, Array2DUint8& pCurrentBitmask);
00051 
00052         //Use the cell bitmasks to generate all the vertices needed for that slice
00053         void generateVerticesForSlice(const Array2DUint8& pCurrentBitmask,
00054             Array2DInt32& m_pCurrentVertexIndicesX,
00055             Array2DInt32& m_pCurrentVertexIndicesY,
00056             Array2DInt32& m_pCurrentVertexIndicesZ);
00057 
00059         // NOTE: These two functions are in the .h file rather than the .inl due to an apparent bug in VC2010.
00060         //See http://stackoverflow.com/questions/1484885/strange-vc-compile-error-c2244 for details.
00062         Vector3DFloat computeCentralDifferenceGradient(const typename VolumeType<VoxelType>::Sampler& volIter)
00063         {
00064             //FIXME - Should actually use DensityType here, both in principle and because the maths may be
00065             //faster (and to reduce casts). So it would be good to add a way to get DensityType from a voxel.
00066             //But watch out for when the DensityType is unsigned and the difference could be negative.
00067             float voxel1nx = static_cast<float>(volIter.peekVoxel1nx0py0pz().getDensity());
00068             float voxel1px = static_cast<float>(volIter.peekVoxel1px0py0pz().getDensity());
00069 
00070             float voxel1ny = static_cast<float>(volIter.peekVoxel0px1ny0pz().getDensity());
00071             float voxel1py = static_cast<float>(volIter.peekVoxel0px1py0pz().getDensity());
00072 
00073             float voxel1nz = static_cast<float>(volIter.peekVoxel0px0py1nz().getDensity());
00074             float voxel1pz = static_cast<float>(volIter.peekVoxel0px0py1pz().getDensity());
00075 
00076             return Vector3DFloat
00077             (
00078                 voxel1nx - voxel1px,
00079                 voxel1ny - voxel1py,
00080                 voxel1nz - voxel1pz
00081             );
00082         }
00083 
00084         Vector3DFloat computeSobelGradient(const typename VolumeType<VoxelType>::Sampler& volIter)
00085         {
00086             static const int weights[3][3][3] = {  {  {2,3,2}, {3,6,3}, {2,3,2}  },  {
00087                 {3,6,3},  {6,0,6},  {3,6,3} },  { {2,3,2},  {3,6,3},  {2,3,2} } };
00088 
00089                 //FIXME - Should actually use DensityType here, both in principle and because the maths may be
00090                 //faster (and to reduce casts). So it would be good to add a way to get DensityType from a voxel.
00091                 //But watch out for when the DensityType is unsigned and the difference could be negative.
00092                 const float pVoxel1nx1ny1nz = static_cast<float>(volIter.peekVoxel1nx1ny1nz().getDensity());
00093                 const float pVoxel1nx1ny0pz = static_cast<float>(volIter.peekVoxel1nx1ny0pz().getDensity());
00094                 const float pVoxel1nx1ny1pz = static_cast<float>(volIter.peekVoxel1nx1ny1pz().getDensity());
00095                 const float pVoxel1nx0py1nz = static_cast<float>(volIter.peekVoxel1nx0py1nz().getDensity());
00096                 const float pVoxel1nx0py0pz = static_cast<float>(volIter.peekVoxel1nx0py0pz().getDensity());
00097                 const float pVoxel1nx0py1pz = static_cast<float>(volIter.peekVoxel1nx0py1pz().getDensity());
00098                 const float pVoxel1nx1py1nz = static_cast<float>(volIter.peekVoxel1nx1py1nz().getDensity());
00099                 const float pVoxel1nx1py0pz = static_cast<float>(volIter.peekVoxel1nx1py0pz().getDensity());
00100                 const float pVoxel1nx1py1pz = static_cast<float>(volIter.peekVoxel1nx1py1pz().getDensity());
00101 
00102                 const float pVoxel0px1ny1nz = static_cast<float>(volIter.peekVoxel0px1ny1nz().getDensity());
00103                 const float pVoxel0px1ny0pz = static_cast<float>(volIter.peekVoxel0px1ny0pz().getDensity());
00104                 const float pVoxel0px1ny1pz = static_cast<float>(volIter.peekVoxel0px1ny1pz().getDensity());
00105                 const float pVoxel0px0py1nz = static_cast<float>(volIter.peekVoxel0px0py1nz().getDensity());
00106                 //const float pVoxel0px0py0pz = static_cast<float>(volIter.peekVoxel0px0py0pz().getDensity());
00107                 const float pVoxel0px0py1pz = static_cast<float>(volIter.peekVoxel0px0py1pz().getDensity());
00108                 const float pVoxel0px1py1nz = static_cast<float>(volIter.peekVoxel0px1py1nz().getDensity());
00109                 const float pVoxel0px1py0pz = static_cast<float>(volIter.peekVoxel0px1py0pz().getDensity());
00110                 const float pVoxel0px1py1pz = static_cast<float>(volIter.peekVoxel0px1py1pz().getDensity());
00111 
00112                 const float pVoxel1px1ny1nz = static_cast<float>(volIter.peekVoxel1px1ny1nz().getDensity());
00113                 const float pVoxel1px1ny0pz = static_cast<float>(volIter.peekVoxel1px1ny0pz().getDensity());
00114                 const float pVoxel1px1ny1pz = static_cast<float>(volIter.peekVoxel1px1ny1pz().getDensity());
00115                 const float pVoxel1px0py1nz = static_cast<float>(volIter.peekVoxel1px0py1nz().getDensity());
00116                 const float pVoxel1px0py0pz = static_cast<float>(volIter.peekVoxel1px0py0pz().getDensity());
00117                 const float pVoxel1px0py1pz = static_cast<float>(volIter.peekVoxel1px0py1pz().getDensity());
00118                 const float pVoxel1px1py1nz = static_cast<float>(volIter.peekVoxel1px1py1nz().getDensity());
00119                 const float pVoxel1px1py0pz = static_cast<float>(volIter.peekVoxel1px1py0pz().getDensity());
00120                 const float pVoxel1px1py1pz = static_cast<float>(volIter.peekVoxel1px1py1pz().getDensity());
00121 
00122                 const float xGrad(- weights[0][0][0] * pVoxel1nx1ny1nz -
00123                     weights[1][0][0] * pVoxel1nx1ny0pz - weights[2][0][0] *
00124                     pVoxel1nx1ny1pz - weights[0][1][0] * pVoxel1nx0py1nz -
00125                     weights[1][1][0] * pVoxel1nx0py0pz - weights[2][1][0] *
00126                     pVoxel1nx0py1pz - weights[0][2][0] * pVoxel1nx1py1nz -
00127                     weights[1][2][0] * pVoxel1nx1py0pz - weights[2][2][0] *
00128                     pVoxel1nx1py1pz + weights[0][0][2] * pVoxel1px1ny1nz +
00129                     weights[1][0][2] * pVoxel1px1ny0pz + weights[2][0][2] *
00130                     pVoxel1px1ny1pz + weights[0][1][2] * pVoxel1px0py1nz +
00131                     weights[1][1][2] * pVoxel1px0py0pz + weights[2][1][2] *
00132                     pVoxel1px0py1pz + weights[0][2][2] * pVoxel1px1py1nz +
00133                     weights[1][2][2] * pVoxel1px1py0pz + weights[2][2][2] *
00134                     pVoxel1px1py1pz);
00135 
00136                 const float yGrad(- weights[0][0][0] * pVoxel1nx1ny1nz -
00137                     weights[1][0][0] * pVoxel1nx1ny0pz - weights[2][0][0] *
00138                     pVoxel1nx1ny1pz + weights[0][2][0] * pVoxel1nx1py1nz +
00139                     weights[1][2][0] * pVoxel1nx1py0pz + weights[2][2][0] *
00140                     pVoxel1nx1py1pz - weights[0][0][1] * pVoxel0px1ny1nz -
00141                     weights[1][0][1] * pVoxel0px1ny0pz - weights[2][0][1] *
00142                     pVoxel0px1ny1pz + weights[0][2][1] * pVoxel0px1py1nz +
00143                     weights[1][2][1] * pVoxel0px1py0pz + weights[2][2][1] *
00144                     pVoxel0px1py1pz - weights[0][0][2] * pVoxel1px1ny1nz -
00145                     weights[1][0][2] * pVoxel1px1ny0pz - weights[2][0][2] *
00146                     pVoxel1px1ny1pz + weights[0][2][2] * pVoxel1px1py1nz +
00147                     weights[1][2][2] * pVoxel1px1py0pz + weights[2][2][2] *
00148                     pVoxel1px1py1pz);
00149 
00150                 const float zGrad(- weights[0][0][0] * pVoxel1nx1ny1nz +
00151                     weights[2][0][0] * pVoxel1nx1ny1pz - weights[0][1][0] *
00152                     pVoxel1nx0py1nz + weights[2][1][0] * pVoxel1nx0py1pz -
00153                     weights[0][2][0] * pVoxel1nx1py1nz + weights[2][2][0] *
00154                     pVoxel1nx1py1pz - weights[0][0][1] * pVoxel0px1ny1nz +
00155                     weights[2][0][1] * pVoxel0px1ny1pz - weights[0][1][1] *
00156                     pVoxel0px0py1nz + weights[2][1][1] * pVoxel0px0py1pz -
00157                     weights[0][2][1] * pVoxel0px1py1nz + weights[2][2][1] *
00158                     pVoxel0px1py1pz - weights[0][0][2] * pVoxel1px1ny1nz +
00159                     weights[2][0][2] * pVoxel1px1ny1pz - weights[0][1][2] *
00160                     pVoxel1px0py1nz + weights[2][1][2] * pVoxel1px0py1pz -
00161                     weights[0][2][2] * pVoxel1px1py1nz + weights[2][2][2] *
00162                     pVoxel1px1py1pz);
00163 
00164                 //Note: The above actually give gradients going from low density to high density.
00165                 //For our normals we want the the other way around, so we switch the components as we return them.
00166                 return Vector3DFloat(-xGrad,-yGrad,-zGrad);
00167         }
00169         // End of compiler bug workaroumd.
00171 
00172         //Use the cell bitmasks to generate all the indices needed for that slice
00173         void generateIndicesForSlice(const Array2DUint8& pPreviousBitmask,
00174             const Array2DInt32& m_pPreviousVertexIndicesX,
00175             const Array2DInt32& m_pPreviousVertexIndicesY,
00176             const Array2DInt32& m_pPreviousVertexIndicesZ,
00177             const Array2DInt32& m_pCurrentVertexIndicesX,
00178             const Array2DInt32& m_pCurrentVertexIndicesY);
00179 
00180         //The volume data and a sampler to access it.
00181         VolumeType<VoxelType>* m_volData;
00182         typename VolumeType<VoxelType>::Sampler m_sampVolume;
00183 
00184         //Holds a position in volume space.
00185         int32_t iXVolSpace;
00186         int32_t iYVolSpace;
00187         int32_t iZVolSpace;
00188 
00189         //Holds a position in region space.
00190         uint32_t uXRegSpace;
00191         uint32_t uYRegSpace;
00192         uint32_t uZRegSpace;
00193 
00194         //Used to return the number of cells in a slice which contain triangles.
00195         uint32_t m_uNoOfOccupiedCells;
00196 
00197         //The surface patch we are currently filling.
00198         SurfaceMesh<PositionMaterialNormal>* m_meshCurrent;
00199 
00200         //Information about the region we are currently processing
00201         Region m_regSizeInVoxels;
00202         Region m_regSizeInCells;
00203         /*Region m_regSizeInVoxelsCropped;
00204         Region m_regSizeInVoxelsUncropped;
00205         Region m_regVolumeCropped;*/
00206         Region m_regSlicePrevious;
00207         Region m_regSliceCurrent;
00208     };
00209 }
00210 
00211 #include "PolyVoxCore/SurfaceExtractor.inl"
00212 
00213 #endif

Generated on Sat Nov 19 2011 00:27:31 for PolyVox by  doxygen 1.7.1