PolyVox  0.3.0-dev
Open source voxel management library
MarchingCubesSurfaceExtractor.h
Go to the documentation of this file.
1 /*******************************************************************************
2 Copyright (c) 2005-2009 David Williams
3 
4 This software is provided 'as-is', without any express or implied
5 warranty. In no event will the authors be held liable for any damages
6 arising from the use of this software.
7 
8 Permission is granted to anyone to use this software for any purpose,
9 including commercial applications, and to alter it and redistribute it
10 freely, subject to the following restrictions:
11 
12  1. The origin of this software must not be misrepresented; you must not
13  claim that you wrote the original software. If you use this software
14  in a product, an acknowledgment in the product documentation would be
15  appreciated but is not required.
16 
17  2. Altered source versions must be plainly marked as such, and must not be
18  misrepresented as being the original software.
19 
20  3. This notice may not be removed or altered from any source
21  distribution.
22 *******************************************************************************/
23 
24 #ifndef __PolyVox_SurfaceExtractor_H__
25 #define __PolyVox_SurfaceExtractor_H__
26 
28 #include "Impl/TypeDef.h"
29 
30 #include "PolyVoxCore/Array.h"
31 #include "PolyVoxCore/BaseVolume.h" //For wrap modes... should move these?
34 
35 namespace PolyVox
36 {
37  template< typename VolumeType, typename Controller = DefaultMarchingCubesController<typename VolumeType::VoxelType> >
39  {
40  public:
41  // 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
42  // 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?
43 #if defined(_MSC_VER)
44  MarchingCubesSurfaceExtractor(VolumeType* volData, Region region, SurfaceMesh<PositionMaterialNormal>* result, WrapMode eWrapMode = WrapModes::Border, typename VolumeType::VoxelType tBorderValue = VolumeType::VoxelType(), Controller controller = Controller());
45 #else
46  MarchingCubesSurfaceExtractor(VolumeType* volData, Region region, SurfaceMesh<PositionMaterialNormal>* result, WrapMode eWrapMode = WrapModes::Border, typename VolumeType::VoxelType tBorderValue = typename VolumeType::VoxelType(), Controller controller = Controller());
47 #endif
48 
49  void execute();
50 
51  private:
52  //Compute the cell bitmask for a particular slice in z.
53  template<bool isPrevZAvail>
54  uint32_t computeBitmaskForSlice(const Array2DUint8& pPreviousBitmask, Array2DUint8& pCurrentBitmask);
55 
56  //Compute the cell bitmask for a given cell.
57  template<bool isPrevXAvail, bool isPrevYAvail, bool isPrevZAvail>
58  void computeBitmaskForCell(const Array2DUint8& pPreviousBitmask, Array2DUint8& pCurrentBitmask, uint32_t uXRegSpace, uint32_t uYRegSpace);
59 
60  //Use the cell bitmasks to generate all the vertices needed for that slice
61  void generateVerticesForSlice(const Array2DUint8& pCurrentBitmask,
62  Array2DInt32& m_pCurrentVertexIndicesX,
63  Array2DInt32& m_pCurrentVertexIndicesY,
64  Array2DInt32& m_pCurrentVertexIndicesZ);
65 
67  // NOTE: These two functions are in the .h file rather than the .inl due to an apparent bug in VC2010.
68  //See http://stackoverflow.com/questions/1484885/strange-vc-compile-error-c2244 for details.
70  Vector3DFloat computeCentralDifferenceGradient(const typename VolumeType::Sampler& volIter)
71  {
72  //FIXME - Should actually use DensityType here, both in principle and because the maths may be
73  //faster (and to reduce casts). So it would be good to add a way to get DensityType from a voxel.
74  //But watch out for when the DensityType is unsigned and the difference could be negative.
75  float voxel1nx = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel1nx0py0pz()));
76  float voxel1px = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel1px0py0pz()));
77 
78  float voxel1ny = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel0px1ny0pz()));
79  float voxel1py = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel0px1py0pz()));
80 
81  float voxel1nz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel0px0py1nz()));
82  float voxel1pz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel0px0py1pz()));
83 
84  return Vector3DFloat
85  (
86  voxel1nx - voxel1px,
87  voxel1ny - voxel1py,
88  voxel1nz - voxel1pz
89  );
90  }
91 
92  Vector3DFloat computeSobelGradient(const typename VolumeType::Sampler& volIter)
93  {
94  static const int weights[3][3][3] = { { {2,3,2}, {3,6,3}, {2,3,2} }, {
95  {3,6,3}, {6,0,6}, {3,6,3} }, { {2,3,2}, {3,6,3}, {2,3,2} } };
96 
97  //FIXME - Should actually use DensityType here, both in principle and because the maths may be
98  //faster (and to reduce casts). So it would be good to add a way to get DensityType from a voxel.
99  //But watch out for when the DensityType is unsigned and the difference could be negative.
100  const float pVoxel1nx1ny1nz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel1nx1ny1nz()));
101  const float pVoxel1nx1ny0pz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel1nx1ny0pz()));
102  const float pVoxel1nx1ny1pz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel1nx1ny1pz()));
103  const float pVoxel1nx0py1nz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel1nx0py1nz()));
104  const float pVoxel1nx0py0pz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel1nx0py0pz()));
105  const float pVoxel1nx0py1pz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel1nx0py1pz()));
106  const float pVoxel1nx1py1nz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel1nx1py1nz()));
107  const float pVoxel1nx1py0pz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel1nx1py0pz()));
108  const float pVoxel1nx1py1pz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel1nx1py1pz()));
109 
110  const float pVoxel0px1ny1nz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel0px1ny1nz()));
111  const float pVoxel0px1ny0pz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel0px1ny0pz()));
112  const float pVoxel0px1ny1pz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel0px1ny1pz()));
113  const float pVoxel0px0py1nz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel0px0py1nz()));
114  //const float pVoxel0px0py0pz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel0px0py0pz()));
115  const float pVoxel0px0py1pz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel0px0py1pz()));
116  const float pVoxel0px1py1nz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel0px1py1nz()));
117  const float pVoxel0px1py0pz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel0px1py0pz()));
118  const float pVoxel0px1py1pz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel0px1py1pz()));
119 
120  const float pVoxel1px1ny1nz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel1px1ny1nz()));
121  const float pVoxel1px1ny0pz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel1px1ny0pz()));
122  const float pVoxel1px1ny1pz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel1px1ny1pz()));
123  const float pVoxel1px0py1nz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel1px0py1nz()));
124  const float pVoxel1px0py0pz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel1px0py0pz()));
125  const float pVoxel1px0py1pz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel1px0py1pz()));
126  const float pVoxel1px1py1nz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel1px1py1nz()));
127  const float pVoxel1px1py0pz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel1px1py0pz()));
128  const float pVoxel1px1py1pz = static_cast<float>(m_controller.convertToDensity(volIter.peekVoxel1px1py1pz()));
129 
130  const float xGrad(- weights[0][0][0] * pVoxel1nx1ny1nz -
131  weights[1][0][0] * pVoxel1nx1ny0pz - weights[2][0][0] *
132  pVoxel1nx1ny1pz - weights[0][1][0] * pVoxel1nx0py1nz -
133  weights[1][1][0] * pVoxel1nx0py0pz - weights[2][1][0] *
134  pVoxel1nx0py1pz - weights[0][2][0] * pVoxel1nx1py1nz -
135  weights[1][2][0] * pVoxel1nx1py0pz - weights[2][2][0] *
136  pVoxel1nx1py1pz + weights[0][0][2] * pVoxel1px1ny1nz +
137  weights[1][0][2] * pVoxel1px1ny0pz + weights[2][0][2] *
138  pVoxel1px1ny1pz + weights[0][1][2] * pVoxel1px0py1nz +
139  weights[1][1][2] * pVoxel1px0py0pz + weights[2][1][2] *
140  pVoxel1px0py1pz + weights[0][2][2] * pVoxel1px1py1nz +
141  weights[1][2][2] * pVoxel1px1py0pz + weights[2][2][2] *
142  pVoxel1px1py1pz);
143 
144  const float yGrad(- weights[0][0][0] * pVoxel1nx1ny1nz -
145  weights[1][0][0] * pVoxel1nx1ny0pz - weights[2][0][0] *
146  pVoxel1nx1ny1pz + weights[0][2][0] * pVoxel1nx1py1nz +
147  weights[1][2][0] * pVoxel1nx1py0pz + weights[2][2][0] *
148  pVoxel1nx1py1pz - weights[0][0][1] * pVoxel0px1ny1nz -
149  weights[1][0][1] * pVoxel0px1ny0pz - weights[2][0][1] *
150  pVoxel0px1ny1pz + weights[0][2][1] * pVoxel0px1py1nz +
151  weights[1][2][1] * pVoxel0px1py0pz + weights[2][2][1] *
152  pVoxel0px1py1pz - weights[0][0][2] * pVoxel1px1ny1nz -
153  weights[1][0][2] * pVoxel1px1ny0pz - weights[2][0][2] *
154  pVoxel1px1ny1pz + weights[0][2][2] * pVoxel1px1py1nz +
155  weights[1][2][2] * pVoxel1px1py0pz + weights[2][2][2] *
156  pVoxel1px1py1pz);
157 
158  const float zGrad(- weights[0][0][0] * pVoxel1nx1ny1nz +
159  weights[2][0][0] * pVoxel1nx1ny1pz - weights[0][1][0] *
160  pVoxel1nx0py1nz + weights[2][1][0] * pVoxel1nx0py1pz -
161  weights[0][2][0] * pVoxel1nx1py1nz + weights[2][2][0] *
162  pVoxel1nx1py1pz - weights[0][0][1] * pVoxel0px1ny1nz +
163  weights[2][0][1] * pVoxel0px1ny1pz - weights[0][1][1] *
164  pVoxel0px0py1nz + weights[2][1][1] * pVoxel0px0py1pz -
165  weights[0][2][1] * pVoxel0px1py1nz + weights[2][2][1] *
166  pVoxel0px1py1pz - weights[0][0][2] * pVoxel1px1ny1nz +
167  weights[2][0][2] * pVoxel1px1ny1pz - weights[0][1][2] *
168  pVoxel1px0py1nz + weights[2][1][2] * pVoxel1px0py1pz -
169  weights[0][2][2] * pVoxel1px1py1nz + weights[2][2][2] *
170  pVoxel1px1py1pz);
171 
172  //Note: The above actually give gradients going from low density to high density.
173  //For our normals we want the the other way around, so we switch the components as we return them.
174  return Vector3DFloat(-xGrad,-yGrad,-zGrad);
175  }
177  // End of compiler bug workaroumd.
179 
180  //Use the cell bitmasks to generate all the indices needed for that slice
181  void generateIndicesForSlice(const Array2DUint8& pPreviousBitmask,
182  const Array2DInt32& m_pPreviousVertexIndicesX,
183  const Array2DInt32& m_pPreviousVertexIndicesY,
184  const Array2DInt32& m_pPreviousVertexIndicesZ,
185  const Array2DInt32& m_pCurrentVertexIndicesX,
186  const Array2DInt32& m_pCurrentVertexIndicesY);
187 
188  //The volume data and a sampler to access it.
189  VolumeType* m_volData;
190  typename VolumeType::Sampler m_sampVolume;
191 
192  //Used to return the number of cells in a slice which contain triangles.
193  uint32_t m_uNoOfOccupiedCells;
194 
195  //The surface patch we are currently filling.
197 
198  //Information about the region we are currently processing
199  Region m_regSizeInVoxels;
200  Region m_regSizeInCells;
201  /*Region m_regSizeInVoxelsCropped;
202  Region m_regSizeInVoxelsUncropped;
203  Region m_regVolumeCropped;*/
204  Region m_regSlicePrevious;
205  Region m_regSliceCurrent;
206 
207  //Used to convert arbitrary voxel types in densities and materials.
208  Controller m_controller;
209 
210  //Our threshold value
211  typename Controller::DensityType m_tThreshold;
212  };
213 }
214 
216 
217 #endif