26 template<
typename VolumeType,
typename Controller>
29 ,m_sampVolume(volData)
30 ,m_meshCurrent(result)
31 ,m_regSizeInVoxels(region)
32 ,m_controller(controller)
33 ,m_tThreshold(m_controller.getThreshold())
36 m_regSizeInCells = m_regSizeInVoxels;
39 m_sampVolume.setWrapMode(eWrapMode, tBorderValue);
42 template<
typename VolumeType,
typename Controller>
45 m_meshCurrent->clear();
47 const uint32_t uArrayWidth = m_regSizeInVoxels.getUpperX() - m_regSizeInVoxels.getLowerX() + 1;
48 const uint32_t uArrayHeight = m_regSizeInVoxels.getUpperY() - m_regSizeInVoxels.getLowerY() + 1;
49 const uint32_t arraySizes[2]= {uArrayWidth, uArrayHeight};
63 m_regSlicePrevious = m_regSizeInVoxels;
64 Vector3DInt32 v3dUpperCorner = m_regSlicePrevious.getUpperCorner();
65 v3dUpperCorner.
setZ(m_regSlicePrevious.getLowerZ());
66 m_regSlicePrevious.setUpperCorner(v3dUpperCorner);
67 m_regSliceCurrent = m_regSlicePrevious;
69 uint32_t uNoOfNonEmptyCellsForSlice0 = 0;
70 uint32_t uNoOfNonEmptyCellsForSlice1 = 0;
73 computeBitmaskForSlice<false>(pPreviousBitmask, pCurrentBitmask);
74 uNoOfNonEmptyCellsForSlice1 = m_uNoOfOccupiedCells;
76 if(uNoOfNonEmptyCellsForSlice1 != 0)
81 generateVerticesForSlice(pCurrentBitmask, m_pCurrentVertexIndicesX, m_pCurrentVertexIndicesY, m_pCurrentVertexIndicesZ);
84 std::swap(uNoOfNonEmptyCellsForSlice0, uNoOfNonEmptyCellsForSlice1);
85 pPreviousBitmask.swap(pCurrentBitmask);
86 m_pPreviousVertexIndicesX.
swap(m_pCurrentVertexIndicesX);
87 m_pPreviousVertexIndicesY.
swap(m_pCurrentVertexIndicesY);
88 m_pPreviousVertexIndicesZ.
swap(m_pCurrentVertexIndicesZ);
90 m_regSlicePrevious = m_regSliceCurrent;
94 for(
int32_t uSlice = 1; uSlice <= m_regSizeInVoxels.getUpperZ() - m_regSizeInVoxels.getLowerZ(); uSlice++)
96 computeBitmaskForSlice<true>(pPreviousBitmask, pCurrentBitmask);
97 uNoOfNonEmptyCellsForSlice1 = m_uNoOfOccupiedCells;
99 if(uNoOfNonEmptyCellsForSlice1 != 0)
104 generateVerticesForSlice(pCurrentBitmask, m_pCurrentVertexIndicesX, m_pCurrentVertexIndicesY, m_pCurrentVertexIndicesZ);
107 if((uNoOfNonEmptyCellsForSlice0 != 0) || (uNoOfNonEmptyCellsForSlice1 != 0))
109 generateIndicesForSlice(pPreviousBitmask, m_pPreviousVertexIndicesX, m_pPreviousVertexIndicesY, m_pPreviousVertexIndicesZ, m_pCurrentVertexIndicesX, m_pCurrentVertexIndicesY);
112 std::swap(uNoOfNonEmptyCellsForSlice0, uNoOfNonEmptyCellsForSlice1);
113 pPreviousBitmask.swap(pCurrentBitmask);
114 m_pPreviousVertexIndicesX.
swap(m_pCurrentVertexIndicesX);
115 m_pPreviousVertexIndicesY.
swap(m_pCurrentVertexIndicesY);
116 m_pPreviousVertexIndicesZ.
swap(m_pCurrentVertexIndicesZ);
118 m_regSlicePrevious = m_regSliceCurrent;
122 m_meshCurrent->m_Region = m_regSizeInVoxels;
124 m_meshCurrent->m_vecLodRecords.clear();
127 lodRecord.
endIndex = m_meshCurrent->getNoOfIndices();
128 m_meshCurrent->m_vecLodRecords.push_back(lodRecord);
131 template<
typename VolumeType,
typename Controller>
132 template<
bool isPrevZAvail>
135 m_uNoOfOccupiedCells = 0;
137 const int32_t iMaxXVolSpace = m_regSliceCurrent.getUpperX();
138 const int32_t iMaxYVolSpace = m_regSliceCurrent.getUpperY();
140 const int32_t iZVolSpace = m_regSliceCurrent.getLowerZ();
143 int32_t iYVolSpace = m_regSliceCurrent.getLowerY();
144 int32_t iXVolSpace = m_regSliceCurrent.getLowerX();
146 uint32_t uXRegSpace = iXVolSpace - m_regSizeInVoxels.getLowerX();
147 uint32_t uYRegSpace = iYVolSpace - m_regSizeInVoxels.getLowerY();
150 m_sampVolume.setPosition(iXVolSpace,iYVolSpace,iZVolSpace);
151 computeBitmaskForCell<false, false, isPrevZAvail>(pPreviousBitmask, pCurrentBitmask, uXRegSpace, uYRegSpace);
154 iXVolSpace = m_regSliceCurrent.getLowerX();
155 m_sampVolume.setPosition(iXVolSpace, m_regSliceCurrent.getLowerY(), iZVolSpace);
156 for(iYVolSpace = m_regSliceCurrent.getLowerY() + 1; iYVolSpace <= iMaxYVolSpace; iYVolSpace++)
158 uXRegSpace = iXVolSpace - m_regSizeInVoxels.getLowerX();
159 uYRegSpace = iYVolSpace - m_regSizeInVoxels.getLowerY();
161 m_sampVolume.movePositiveY();
163 computeBitmaskForCell<false, true, isPrevZAvail>(pPreviousBitmask, pCurrentBitmask, uXRegSpace, uYRegSpace);
167 iYVolSpace = m_regSliceCurrent.getLowerY();
168 m_sampVolume.setPosition(m_regSliceCurrent.getLowerX(), iYVolSpace, iZVolSpace);
169 for(iXVolSpace = m_regSliceCurrent.getLowerX() + 1; iXVolSpace <= iMaxXVolSpace; iXVolSpace++)
171 uXRegSpace = iXVolSpace - m_regSizeInVoxels.getLowerX();
172 uYRegSpace = iYVolSpace - m_regSizeInVoxels.getLowerY();
174 m_sampVolume.movePositiveX();
176 computeBitmaskForCell<true, false, isPrevZAvail>(pPreviousBitmask, pCurrentBitmask, uXRegSpace, uYRegSpace);
180 for(iYVolSpace = m_regSliceCurrent.getLowerY() + 1; iYVolSpace <= iMaxYVolSpace; iYVolSpace++)
182 m_sampVolume.setPosition(m_regSliceCurrent.getLowerX(), iYVolSpace, iZVolSpace);
183 for(iXVolSpace = m_regSliceCurrent.getLowerX() + 1; iXVolSpace <= iMaxXVolSpace; iXVolSpace++)
185 uXRegSpace = iXVolSpace - m_regSizeInVoxels.getLowerX();
186 uYRegSpace = iYVolSpace - m_regSizeInVoxels.getLowerY();
188 m_sampVolume.movePositiveX();
190 computeBitmaskForCell<true, true, isPrevZAvail>(pPreviousBitmask, pCurrentBitmask, uXRegSpace, uYRegSpace);
194 return m_uNoOfOccupiedCells;
197 template<
typename VolumeType,
typename Controller>
198 template<
bool isPrevXAvail,
bool isPrevYAvail,
bool isPrevZAvail>
203 typename VolumeType::VoxelType v000;
204 typename VolumeType::VoxelType v100;
205 typename VolumeType::VoxelType v010;
206 typename VolumeType::VoxelType v110;
207 typename VolumeType::VoxelType v001;
208 typename VolumeType::VoxelType v101;
209 typename VolumeType::VoxelType v011;
210 typename VolumeType::VoxelType v111;
218 v111 = m_sampVolume.peekVoxel1px1py1pz();
221 uint8_t iPreviousCubeIndexZ = pPreviousBitmask[uXRegSpace][uYRegSpace];
222 iPreviousCubeIndexZ >>= 4;
225 uint8_t iPreviousCubeIndexY = pCurrentBitmask[uXRegSpace][uYRegSpace-1];
226 iPreviousCubeIndexY &= 192;
227 iPreviousCubeIndexY >>= 2;
230 uint8_t iPreviousCubeIndexX = pCurrentBitmask[uXRegSpace-1][uYRegSpace];
231 iPreviousCubeIndexX &= 128;
232 iPreviousCubeIndexX >>= 1;
234 iCubeIndex = iPreviousCubeIndexX | iPreviousCubeIndexY | iPreviousCubeIndexZ;
236 if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128;
240 v011 = m_sampVolume.peekVoxel0px1py1pz();
241 v111 = m_sampVolume.peekVoxel1px1py1pz();
244 uint8_t iPreviousCubeIndexZ = pPreviousBitmask[uXRegSpace][uYRegSpace];
245 iPreviousCubeIndexZ >>= 4;
248 uint8_t iPreviousCubeIndexY = pCurrentBitmask[uXRegSpace][uYRegSpace-1];
249 iPreviousCubeIndexY &= 192;
250 iPreviousCubeIndexY >>= 2;
252 iCubeIndex = iPreviousCubeIndexY | iPreviousCubeIndexZ;
254 if (m_controller.convertToDensity(v011) < m_tThreshold) iCubeIndex |= 64;
255 if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128;
262 v101 = m_sampVolume.peekVoxel1px0py1pz();
263 v111 = m_sampVolume.peekVoxel1px1py1pz();
266 uint8_t iPreviousCubeIndexZ = pPreviousBitmask[uXRegSpace][uYRegSpace];
267 iPreviousCubeIndexZ >>= 4;
270 uint8_t iPreviousCubeIndexX = pCurrentBitmask[uXRegSpace-1][uYRegSpace];
271 iPreviousCubeIndexX &= 160;
272 iPreviousCubeIndexX >>= 1;
274 iCubeIndex = iPreviousCubeIndexX | iPreviousCubeIndexZ;
276 if (m_controller.convertToDensity(v101) < m_tThreshold) iCubeIndex |= 32;
277 if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128;
281 v001 = m_sampVolume.peekVoxel0px0py1pz();
282 v101 = m_sampVolume.peekVoxel1px0py1pz();
283 v011 = m_sampVolume.peekVoxel0px1py1pz();
284 v111 = m_sampVolume.peekVoxel1px1py1pz();
287 uint8_t iPreviousCubeIndexZ = pPreviousBitmask[uXRegSpace][uYRegSpace];
288 iCubeIndex = iPreviousCubeIndexZ >> 4;
290 if (m_controller.convertToDensity(v001) < m_tThreshold) iCubeIndex |= 16;
291 if (m_controller.convertToDensity(v101) < m_tThreshold) iCubeIndex |= 32;
292 if (m_controller.convertToDensity(v011) < m_tThreshold) iCubeIndex |= 64;
293 if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128;
303 v110 = m_sampVolume.peekVoxel1px1py0pz();
304 v111 = m_sampVolume.peekVoxel1px1py1pz();
307 uint8_t iPreviousCubeIndexY = pCurrentBitmask[uXRegSpace][uYRegSpace-1];
308 iPreviousCubeIndexY &= 204;
309 iPreviousCubeIndexY >>= 2;
312 uint8_t iPreviousCubeIndexX = pCurrentBitmask[uXRegSpace-1][uYRegSpace];
313 iPreviousCubeIndexX &= 170;
314 iPreviousCubeIndexX >>= 1;
316 iCubeIndex = iPreviousCubeIndexX | iPreviousCubeIndexY;
318 if (m_controller.convertToDensity(v110) < m_tThreshold) iCubeIndex |= 8;
319 if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128;
323 v010 = m_sampVolume.peekVoxel0px1py0pz();
324 v110 = m_sampVolume.peekVoxel1px1py0pz();
326 v011 = m_sampVolume.peekVoxel0px1py1pz();
327 v111 = m_sampVolume.peekVoxel1px1py1pz();
330 uint8_t iPreviousCubeIndexY = pCurrentBitmask[uXRegSpace][uYRegSpace-1];
331 iPreviousCubeIndexY &= 204;
332 iPreviousCubeIndexY >>= 2;
334 iCubeIndex = iPreviousCubeIndexY;
336 if (m_controller.convertToDensity(v010) < m_tThreshold) iCubeIndex |= 4;
337 if (m_controller.convertToDensity(v110) < m_tThreshold) iCubeIndex |= 8;
338 if (m_controller.convertToDensity(v011) < m_tThreshold) iCubeIndex |= 64;
339 if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128;
346 v100 = m_sampVolume.peekVoxel1px0py0pz();
347 v110 = m_sampVolume.peekVoxel1px1py0pz();
349 v101 = m_sampVolume.peekVoxel1px0py1pz();
350 v111 = m_sampVolume.peekVoxel1px1py1pz();
353 uint8_t iPreviousCubeIndexX = pCurrentBitmask[uXRegSpace-1][uYRegSpace];
354 iPreviousCubeIndexX &= 170;
355 iPreviousCubeIndexX >>= 1;
357 iCubeIndex = iPreviousCubeIndexX;
359 if (m_controller.convertToDensity(v100) < m_tThreshold) iCubeIndex |= 2;
360 if (m_controller.convertToDensity(v110) < m_tThreshold) iCubeIndex |= 8;
361 if (m_controller.convertToDensity(v101) < m_tThreshold) iCubeIndex |= 32;
362 if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128;
366 v000 = m_sampVolume.getVoxel();
367 v100 = m_sampVolume.peekVoxel1px0py0pz();
368 v010 = m_sampVolume.peekVoxel0px1py0pz();
369 v110 = m_sampVolume.peekVoxel1px1py0pz();
371 v001 = m_sampVolume.peekVoxel0px0py1pz();
372 v101 = m_sampVolume.peekVoxel1px0py1pz();
373 v011 = m_sampVolume.peekVoxel0px1py1pz();
374 v111 = m_sampVolume.peekVoxel1px1py1pz();
376 if (m_controller.convertToDensity(v000) < m_tThreshold) iCubeIndex |= 1;
377 if (m_controller.convertToDensity(v100) < m_tThreshold) iCubeIndex |= 2;
378 if (m_controller.convertToDensity(v010) < m_tThreshold) iCubeIndex |= 4;
379 if (m_controller.convertToDensity(v110) < m_tThreshold) iCubeIndex |= 8;
380 if (m_controller.convertToDensity(v001) < m_tThreshold) iCubeIndex |= 16;
381 if (m_controller.convertToDensity(v101) < m_tThreshold) iCubeIndex |= 32;
382 if (m_controller.convertToDensity(v011) < m_tThreshold) iCubeIndex |= 64;
383 if (m_controller.convertToDensity(v111) < m_tThreshold) iCubeIndex |= 128;
389 pCurrentBitmask[uXRegSpace][uYRegSpace] = iCubeIndex;
393 ++m_uNoOfOccupiedCells;
397 template<
typename VolumeType,
typename Controller>
398 void MarchingCubesSurfaceExtractor<VolumeType, Controller>::generateVerticesForSlice(
const Array2DUint8& pCurrentBitmask,
403 const int32_t iZVolSpace = m_regSliceCurrent.getLowerZ();
406 for(
int32_t iYVolSpace = m_regSliceCurrent.getLowerY(); iYVolSpace <= m_regSliceCurrent.getUpperY(); iYVolSpace++)
408 const uint32_t uYRegSpace = iYVolSpace - m_regSizeInVoxels.getLowerY();
410 for(
int32_t iXVolSpace = m_regSliceCurrent.getLowerX(); iXVolSpace <= m_regSliceCurrent.getUpperX(); iXVolSpace++)
413 const uint32_t uXRegSpace = iXVolSpace - m_regSizeInVoxels.getLowerX();
416 const uint8_t iCubeIndex = pCurrentBitmask[uXRegSpace][uYRegSpace];
427 m_sampVolume.setPosition(iXVolSpace,iYVolSpace,iZVolSpace);
428 const typename VolumeType::VoxelType v000 = m_sampVolume.getVoxel();
434 m_sampVolume.movePositiveX();
435 const typename VolumeType::VoxelType v100 = m_sampVolume.getVoxel();
438 const float fInterp =
static_cast<float>(m_tThreshold - m_controller.convertToDensity(v000)) / static_cast<float>(m_controller.convertToDensity(v100) - m_controller.convertToDensity(v000));
440 const Vector3DFloat v3dPosition(static_cast<float>(iXVolSpace - m_regSizeInVoxels.getLowerX()) + fInterp, static_cast<float>(iYVolSpace - m_regSizeInVoxels.getLowerY()), static_cast<float>(iZVolSpace - m_regSizeInCells.getLowerZ()));
442 Vector3DFloat v3dNormal = (n100*fInterp) + (n000*(1-fInterp));
448 const typename Controller::MaterialType uMaterial000 = m_controller.convertToMaterial(v000);
449 const typename Controller::MaterialType uMaterial100 = m_controller.convertToMaterial(v100);
450 const typename Controller::MaterialType uMaterial = (std::max)(uMaterial000, uMaterial100);
452 const PositionMaterialNormal surfaceVertex(v3dPosition, v3dNormal, static_cast<float>(uMaterial));
453 const uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex);
454 m_pCurrentVertexIndicesX[iXVolSpace - m_regSizeInVoxels.getLowerX()][iYVolSpace - m_regSizeInVoxels.getLowerY()] = uLastVertexIndex;
456 m_sampVolume.moveNegativeX();
460 m_sampVolume.movePositiveY();
461 const typename VolumeType::VoxelType v010 = m_sampVolume.getVoxel();
464 const float fInterp =
static_cast<float>(m_tThreshold - m_controller.convertToDensity(v000)) / static_cast<float>(m_controller.convertToDensity(v010) - m_controller.convertToDensity(v000));
466 const Vector3DFloat v3dPosition(static_cast<float>(iXVolSpace - m_regSizeInVoxels.getLowerX()), static_cast<float>(iYVolSpace - m_regSizeInVoxels.getLowerY()) + fInterp, static_cast<float>(iZVolSpace - m_regSizeInVoxels.getLowerZ()));
468 Vector3DFloat v3dNormal = (n010*fInterp) + (n000*(1-fInterp));
474 const typename Controller::MaterialType uMaterial000 = m_controller.convertToMaterial(v000);
475 const typename Controller::MaterialType uMaterial010 = m_controller.convertToMaterial(v010);
476 const typename Controller::MaterialType uMaterial = (std::max)(uMaterial000, uMaterial010);
478 const PositionMaterialNormal surfaceVertex(v3dPosition, v3dNormal, static_cast<float>(uMaterial));
479 const uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex);
480 m_pCurrentVertexIndicesY[iXVolSpace - m_regSizeInVoxels.getLowerX()][iYVolSpace - m_regSizeInVoxels.getLowerY()] = uLastVertexIndex;
482 m_sampVolume.moveNegativeY();
486 m_sampVolume.movePositiveZ();
487 const typename VolumeType::VoxelType v001 = m_sampVolume.getVoxel();
490 const float fInterp =
static_cast<float>(m_tThreshold - m_controller.convertToDensity(v000)) / static_cast<float>(m_controller.convertToDensity(v001) - m_controller.convertToDensity(v000));
492 const Vector3DFloat v3dPosition(static_cast<float>(iXVolSpace - m_regSizeInVoxels.getLowerX()), static_cast<float>(iYVolSpace - m_regSizeInVoxels.getLowerY()), static_cast<float>(iZVolSpace - m_regSizeInVoxels.getLowerZ()) + fInterp);
494 Vector3DFloat v3dNormal = (n001*fInterp) + (n000*(1-fInterp));
500 const typename Controller::MaterialType uMaterial000 = m_controller.convertToMaterial(v000);
501 const typename Controller::MaterialType uMaterial001 = m_controller.convertToMaterial(v001);
502 const typename Controller::MaterialType uMaterial = (std::max)(uMaterial000, uMaterial001);
504 const PositionMaterialNormal surfaceVertex(v3dPosition, v3dNormal, static_cast<float>(uMaterial));
505 const uint32_t uLastVertexIndex = m_meshCurrent->addVertex(surfaceVertex);
506 m_pCurrentVertexIndicesZ[iXVolSpace - m_regSizeInVoxels.getLowerX()][iYVolSpace - m_regSizeInVoxels.getLowerY()] = uLastVertexIndex;
508 m_sampVolume.moveNegativeZ();
514 template<
typename VolumeType,
typename Controller>
515 void MarchingCubesSurfaceExtractor<VolumeType, Controller>::generateIndicesForSlice(
const Array2DUint8& pPreviousBitmask,
523 for(
int i = 0; i < 12; i++)
528 const int32_t iZVolSpace = m_regSlicePrevious.getLowerZ();
530 for(
int32_t iYVolSpace = m_regSlicePrevious.getLowerY(); iYVolSpace <= m_regSizeInCells.getUpperY(); iYVolSpace++)
532 for(
int32_t iXVolSpace = m_regSlicePrevious.getLowerX(); iXVolSpace <= m_regSizeInCells.getUpperX(); iXVolSpace++)
534 m_sampVolume.setPosition(iXVolSpace,iYVolSpace,iZVolSpace);
537 const uint32_t uXRegSpace = m_sampVolume.getPosition().getX() - m_regSizeInVoxels.getLowerX();
538 const uint32_t uYRegSpace = m_sampVolume.getPosition().getY() - m_regSizeInVoxels.getLowerY();
541 const uint8_t iCubeIndex = pPreviousBitmask[uXRegSpace][uYRegSpace];
552 indlist[0] = m_pPreviousVertexIndicesX[uXRegSpace][uYRegSpace];
556 indlist[1] = m_pPreviousVertexIndicesY[uXRegSpace+1][uYRegSpace];
560 indlist[2] = m_pPreviousVertexIndicesX[uXRegSpace][uYRegSpace+1];
564 indlist[3] = m_pPreviousVertexIndicesY[uXRegSpace][uYRegSpace];
568 indlist[4] = m_pCurrentVertexIndicesX[uXRegSpace][uYRegSpace];
572 indlist[5] = m_pCurrentVertexIndicesY[uXRegSpace+1][uYRegSpace];
576 indlist[6] = m_pCurrentVertexIndicesX[uXRegSpace][uYRegSpace+1];
580 indlist[7] = m_pCurrentVertexIndicesY[uXRegSpace][uYRegSpace];
584 indlist[8] = m_pPreviousVertexIndicesZ[uXRegSpace][uYRegSpace];
588 indlist[9] = m_pPreviousVertexIndicesZ[uXRegSpace+1][uYRegSpace];
592 indlist[10] = m_pPreviousVertexIndicesZ[uXRegSpace+1][uYRegSpace+1];
596 indlist[11] = m_pPreviousVertexIndicesZ[uXRegSpace][uYRegSpace+1];
599 for (
int i=0;
triTable[iCubeIndex][i]!=-1;i+=3)
602 const int32_t ind1 = indlist[triTable[iCubeIndex][i+1]];
603 const int32_t ind2 = indlist[triTable[iCubeIndex][i+2]];
605 if((ind0 != -1) && (ind1 != -1) && (ind2 != -1))
607 m_meshCurrent->addTriangle(ind0, ind1, ind2);