OpenVDB: VolumeToSpheres.h Source File

OpenVDB 4.0.2

VolumeToSpheres.h
Go to the documentation of this file.
1 //
3 // Copyright (c) 2012-2017 DreamWorks Animation LLC
4 //
5 // All rights reserved. This software is distributed under the
6 // Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ )
7 //
8 // Redistributions of source code must retain the above copyright
9 // and license notice and the following restrictions and disclaimer.
10 //
11 // * Neither the name of DreamWorks Animation nor the names of
12 // its contributors may be used to endorse or promote products derived
13 // from this software without specific prior written permission.
14 //
15 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL,
20 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 // IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE
27 // LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00.
28 //
30
34
35 #ifndef OPENVDB_TOOLS_VOLUME_TO_SPHERES_HAS_BEEN_INCLUDED
36 #define OPENVDB_TOOLS_VOLUME_TO_SPHERES_HAS_BEEN_INCLUDED
37
38 #include <openvdb/tree/LeafManager.h>
39 #include "Morphology.h" // for erodeVoxels()
40 #include "PointScatter.h"
41 #include "LevelSetUtil.h"
42 #include "VolumeToMesh.h"
43
44 #include <boost/scoped_array.hpp>
45 #include <tbb/blocked_range.h>
46 #include <tbb/parallel_for.h>
47 #include <tbb/parallel_reduce.h>
48
49 #include <limits> // std::numeric_limits
50 #include <vector>
51
52
53 namespace openvdb {
54 OPENVDB_USE_VERSION_NAMESPACE
55 namespace OPENVDB_VERSION_NAME {
56 namespace tools {
57
77 template<typename GridT, typename InterrupterT = util::NullInterrupter>
78 inline void
79 fillWithSpheres(
80 const GridT& grid,
81 std::vector<openvdb::Vec4s>& spheres,
82 int maxSphereCount,
83 bool overlapping = false,
84 float minRadius = 1.0,
85 float maxRadius = std::numeric_limits<float>::max(),
86 float isovalue = 0.0,
87 int instanceCount = 10000,
88 InterrupterT* interrupter = nullptr);
89
90
92
93
97 template<typename GridT>
98 class ClosestSurfacePoint
99 {
100 public:
101 using TreeT = typename GridT::TreeType;
102 using BoolTreeT = typename TreeT::template ValueConverter<bool>::Type;
103 using Index32TreeT = typename TreeT::template ValueConverter<Index32>::Type;
104 using Int16TreeT = typename TreeT::template ValueConverter<Int16>::Type;
105
106 ClosestSurfacePoint();
107
118 template<typename InterrupterT = util::NullInterrupter>
119 bool initialize(const GridT& grid, float isovalue = 0.0, InterrupterT* interrupter = nullptr);
120
124 bool search(const std::vector<Vec3R>& points, std::vector<float>& distances);
125
129 bool searchAndReplace(std::vector<Vec3R>& points, std::vector<float>& distances);
130
132 const Index32TreeT& indexTree() const { return *mIdxTreePt; }
134 const Int16TreeT& signTree() const { return *mSignTreePt; }
135
136 private:
137 using Index32LeafT = typename Index32TreeT::LeafNodeType;
138 using IndexRange = std::pair<size_t, size_t>;
139
140 bool mIsInitialized;
141 std::vector<Vec4R> mLeafBoundingSpheres, mNodeBoundingSpheres;
142 std::vector<IndexRange> mLeafRanges;
143 std::vector<const Index32LeafT*> mLeafNodes;
144 PointList mSurfacePointList;
145 size_t mPointListSize, mMaxNodeLeafs;
146 float mMaxRadiusSqr;
147 typename Index32TreeT::Ptr mIdxTreePt;
148 typename Int16TreeT::Ptr mSignTreePt;
149
150 bool search(std::vector<Vec3R>&, std::vector<float>&, bool transformPoints);
151 };
152
153
155
156
157 // Internal utility methods
158
159 namespace internal {
160
161 struct PointAccessor
162 {
163 PointAccessor(std::vector<Vec3R>& points)
164 : mPoints(points)
165 {
166 }
167
168 void add(const Vec3R &pos)
169 {
170 mPoints.push_back(pos);
171 }
172 private:
173 std::vector<Vec3R>& mPoints;
174 };
175
176
177 template<typename Index32LeafT>
178 class LeafOp
179 {
180 public:
181
182 LeafOp(std::vector<Vec4R>& leafBoundingSpheres,
183 const std::vector<const Index32LeafT*>& leafNodes,
184 const math::Transform& transform,
185 const PointList& surfacePointList);
186
187 void run(bool threaded = true);
188
189
190 void operator()(const tbb::blocked_range<size_t>&) const;
191
192 private:
193 std::vector<Vec4R>& mLeafBoundingSpheres;
194 const std::vector<const Index32LeafT*>& mLeafNodes;
195 const math::Transform& mTransform;
196 const PointList& mSurfacePointList;
197 };
198
199 template<typename Index32LeafT>
200 LeafOp<Index32LeafT>::LeafOp(
201 std::vector<Vec4R>& leafBoundingSpheres,
202 const std::vector<const Index32LeafT*>& leafNodes,
203 const math::Transform& transform,
204 const PointList& surfacePointList)
205 : mLeafBoundingSpheres(leafBoundingSpheres)
206 , mLeafNodes(leafNodes)
207 , mTransform(transform)
208 , mSurfacePointList(surfacePointList)
209 {
210 }
211
212 template<typename Index32LeafT>
213 void
214 LeafOp<Index32LeafT>::run(bool threaded)
215 {
216 if (threaded) {
217 tbb::parallel_for(tbb::blocked_range<size_t>(0, mLeafNodes.size()), *this);
218 } else {
219 (*this)(tbb::blocked_range<size_t>(0, mLeafNodes.size()));
220 }
221 }
222
223 template<typename Index32LeafT>
224 void
225 LeafOp<Index32LeafT>::operator()(const tbb::blocked_range<size_t>& range) const
226 {
227 typename Index32LeafT::ValueOnCIter iter;
228 Vec3s avg;
229
230 for (size_t n = range.begin(); n != range.end(); ++n) {
231
232 avg[0] = 0.0;
233 avg[1] = 0.0;
234 avg[2] = 0.0;
235
236 int count = 0;
237 for (iter = mLeafNodes[n]->cbeginValueOn(); iter; ++iter) {
238 avg += mSurfacePointList[iter.getValue()];
239 ++count;
240 }
241
242 if (count > 1) avg *= float(1.0 / double(count));
243
244 float maxDist = 0.0;
245
246 for (iter = mLeafNodes[n]->cbeginValueOn(); iter; ++iter) {
247 float tmpDist = (mSurfacePointList[iter.getValue()] - avg).lengthSqr();
248 if (tmpDist > maxDist) maxDist = tmpDist;
249 }
250
251 Vec4R& sphere = mLeafBoundingSpheres[n];
252
253 sphere[0] = avg[0];
254 sphere[1] = avg[1];
255 sphere[2] = avg[2];
256 sphere[3] = maxDist * 2.0; // padded radius
257 }
258 }
259
260
261 class NodeOp
262 {
263 public:
264 using IndexRange = std::pair<size_t, size_t>;
265
266 NodeOp(std::vector<Vec4R>& nodeBoundingSpheres,
267 const std::vector<IndexRange>& leafRanges,
268 const std::vector<Vec4R>& leafBoundingSpheres);
269
270 inline void run(bool threaded = true);
271
272 inline void operator()(const tbb::blocked_range<size_t>&) const;
273
274 private:
275 std::vector<Vec4R>& mNodeBoundingSpheres;
276 const std::vector<IndexRange>& mLeafRanges;
277 const std::vector<Vec4R>& mLeafBoundingSpheres;
278 };
279
280 inline
281 NodeOp::NodeOp(std::vector<Vec4R>& nodeBoundingSpheres,
282 const std::vector<IndexRange>& leafRanges,
283 const std::vector<Vec4R>& leafBoundingSpheres)
284 : mNodeBoundingSpheres(nodeBoundingSpheres)
285 , mLeafRanges(leafRanges)
286 , mLeafBoundingSpheres(leafBoundingSpheres)
287 {
288 }
289
290 inline void
291 NodeOp::run(bool threaded)
292 {
293 if (threaded) {
294 tbb::parallel_for(tbb::blocked_range<size_t>(0, mLeafRanges.size()), *this);
295 } else {
296 (*this)(tbb::blocked_range<size_t>(0, mLeafRanges.size()));
297 }
298 }
299
300 inline void
301 NodeOp::operator()(const tbb::blocked_range<size_t>& range) const
302 {
303 Vec3d avg, pos;
304
305 for (size_t n = range.begin(); n != range.end(); ++n) {
306
307 avg[0] = 0.0;
308 avg[1] = 0.0;
309 avg[2] = 0.0;
310
311 int count = int(mLeafRanges[n].second) - int(mLeafRanges[n].first);
312
313 for (size_t i = mLeafRanges[n].first; i < mLeafRanges[n].second; ++i) {
314 avg[0] += mLeafBoundingSpheres[i][0];
315 avg[1] += mLeafBoundingSpheres[i][1];
316 avg[2] += mLeafBoundingSpheres[i][2];
317 }
318
319 if (count > 1) avg *= float(1.0 / double(count));
320
321
322 double maxDist = 0.0;
323
324 for (size_t i = mLeafRanges[n].first; i < mLeafRanges[n].second; ++i) {
325 pos[0] = mLeafBoundingSpheres[i][0];
326 pos[1] = mLeafBoundingSpheres[i][1];
327 pos[2] = mLeafBoundingSpheres[i][2];
328
329 double tmpDist = (pos - avg).lengthSqr() + mLeafBoundingSpheres[i][3];
330 if (tmpDist > maxDist) maxDist = tmpDist;
331 }
332
333 Vec4R& sphere = mNodeBoundingSpheres[n];
334
335 sphere[0] = avg[0];
336 sphere[1] = avg[1];
337 sphere[2] = avg[2];
338 sphere[3] = maxDist * 2.0; // padded radius
339 }
340 }
341
342
344
345
346 template<typename Index32LeafT>
347 class ClosestPointDist
348 {
349 public:
350 using IndexRange = std::pair<size_t, size_t>;
351
352 ClosestPointDist(
353 std::vector<Vec3R>& instancePoints,
354 std::vector<float>& instanceDistances,
355 const PointList& surfacePointList,
356 const std::vector<const Index32LeafT*>& leafNodes,
357 const std::vector<IndexRange>& leafRanges,
358 const std::vector<Vec4R>& leafBoundingSpheres,
359 const std::vector<Vec4R>& nodeBoundingSpheres,
360 size_t maxNodeLeafs,
361 bool transformPoints = false);
362
363
364 void run(bool threaded = true);
365
366
367 void operator()(const tbb::blocked_range<size_t>&) const;
368
369 private:
370
371 void evalLeaf(size_t index, const Index32LeafT& leaf) const;
372 void evalNode(size_t pointIndex, size_t nodeIndex) const;
373
374
375 std::vector<Vec3R>& mInstancePoints;
376 std::vector<float>& mInstanceDistances;
377
378 const PointList& mSurfacePointList;
379
380 const std::vector<const Index32LeafT*>& mLeafNodes;
381 const std::vector<IndexRange>& mLeafRanges;
382 const std::vector<Vec4R>& mLeafBoundingSpheres;
383 const std::vector<Vec4R>& mNodeBoundingSpheres;
384
385 std::vector<float> mLeafDistances, mNodeDistances;
386
387 const bool mTransformPoints;
388 size_t mClosestPointIndex;
389 };// ClosestPointDist
390
391
392 template<typename Index32LeafT>
393 ClosestPointDist<Index32LeafT>::ClosestPointDist(
394 std::vector<Vec3R>& instancePoints,
395 std::vector<float>& instanceDistances,
396 const PointList& surfacePointList,
397 const std::vector<const Index32LeafT*>& leafNodes,
398 const std::vector<IndexRange>& leafRanges,
399 const std::vector<Vec4R>& leafBoundingSpheres,
400 const std::vector<Vec4R>& nodeBoundingSpheres,
401 size_t maxNodeLeafs,
402 bool transformPoints)
403 : mInstancePoints(instancePoints)
404 , mInstanceDistances(instanceDistances)
405 , mSurfacePointList(surfacePointList)
406 , mLeafNodes(leafNodes)
407 , mLeafRanges(leafRanges)
408 , mLeafBoundingSpheres(leafBoundingSpheres)
409 , mNodeBoundingSpheres(nodeBoundingSpheres)
410 , mLeafDistances(maxNodeLeafs, 0.0)
411 , mNodeDistances(leafRanges.size(), 0.0)
412 , mTransformPoints(transformPoints)
413 , mClosestPointIndex(0)
414 {
415 }
416
417
418 template<typename Index32LeafT>
419 void
420 ClosestPointDist<Index32LeafT>::run(bool threaded)
421 {
422 if (threaded) {
423 tbb::parallel_for(tbb::blocked_range<size_t>(0, mInstancePoints.size()), *this);
424 } else {
425 (*this)(tbb::blocked_range<size_t>(0, mInstancePoints.size()));
426 }
427 }
428
429 template<typename Index32LeafT>
430 void
431 ClosestPointDist<Index32LeafT>::evalLeaf(size_t index, const Index32LeafT& leaf) const
432 {
433 typename Index32LeafT::ValueOnCIter iter;
434 const Vec3s center = mInstancePoints[index];
435 size_t& closestPointIndex = const_cast<size_t&>(mClosestPointIndex);
436
437 for (iter = leaf.cbeginValueOn(); iter; ++iter) {
438
439 const Vec3s& point = mSurfacePointList[iter.getValue()];
440 float tmpDist = (point - center).lengthSqr();
441
442 if (tmpDist < mInstanceDistances[index]) {
443 mInstanceDistances[index] = tmpDist;
444 closestPointIndex = iter.getValue();
445 }
446 }
447 }
448
449
450 template<typename Index32LeafT>
451 void
452 ClosestPointDist<Index32LeafT>::evalNode(size_t pointIndex, size_t nodeIndex) const
453 {
454 if (nodeIndex >= mLeafRanges.size()) return;
455
456 const Vec3R& pos = mInstancePoints[pointIndex];
457 float minDist = mInstanceDistances[pointIndex];
458 size_t minDistIdx = 0;
459 Vec3R center;
460 bool updatedDist = false;
461
462 for (size_t i = mLeafRanges[nodeIndex].first, n = 0;
463 i < mLeafRanges[nodeIndex].second; ++i, ++n)
464 {
465 float& distToLeaf = const_cast<float&>(mLeafDistances[n]);
466
467 center[0] = mLeafBoundingSpheres[i][0];
468 center[1] = mLeafBoundingSpheres[i][1];
469 center[2] = mLeafBoundingSpheres[i][2];
470
471 distToLeaf = float((pos - center).lengthSqr() - mLeafBoundingSpheres[i][3]);
472
473 if (distToLeaf < minDist) {
474 minDist = distToLeaf;
475 minDistIdx = i;
476 updatedDist = true;
477 }
478 }
479
480 if (!updatedDist) return;
481
482 evalLeaf(pointIndex, *mLeafNodes[minDistIdx]);
483
484 for (size_t i = mLeafRanges[nodeIndex].first, n = 0;
485 i < mLeafRanges[nodeIndex].second; ++i, ++n)
486 {
487 if (mLeafDistances[n] < mInstanceDistances[pointIndex] && i != minDistIdx) {
488 evalLeaf(pointIndex, *mLeafNodes[i]);
489 }
490 }
491 }
492
493
494 template<typename Index32LeafT>
495 void
496 ClosestPointDist<Index32LeafT>::operator()(const tbb::blocked_range<size_t>& range) const
497 {
498 Vec3R center;
499 for (size_t n = range.begin(); n != range.end(); ++n) {
500
501 const Vec3R& pos = mInstancePoints[n];
502 float minDist = mInstanceDistances[n];
503 size_t minDistIdx = 0;
504
505 for (size_t i = 0, I = mNodeDistances.size(); i < I; ++i) {
506 float& distToNode = const_cast<float&>(mNodeDistances[i]);
507
508 center[0] = mNodeBoundingSpheres[i][0];
509 center[1] = mNodeBoundingSpheres[i][1];
510 center[2] = mNodeBoundingSpheres[i][2];
511
512 distToNode = float((pos - center).lengthSqr() - mNodeBoundingSpheres[i][3]);
513
514 if (distToNode < minDist) {
515 minDist = distToNode;
516 minDistIdx = i;
517 }
518 }
519
520 evalNode(n, minDistIdx);
521
522 for (size_t i = 0, I = mNodeDistances.size(); i < I; ++i) {
523 if (mNodeDistances[i] < mInstanceDistances[n] && i != minDistIdx) {
524 evalNode(n, i);
525 }
526 }
527
528 mInstanceDistances[n] = std::sqrt(mInstanceDistances[n]);
529
530 if (mTransformPoints) mInstancePoints[n] = mSurfacePointList[mClosestPointIndex];
531 }
532 }
533
534
535 class UpdatePoints
536 {
537 public:
538 UpdatePoints(
539 const Vec4s& sphere,
540 const std::vector<Vec3R>& points,
541 std::vector<float>& distances,
542 std::vector<unsigned char>& mask,
543 bool overlapping);
544
545 float radius() const { return mRadius; }
546 int index() const { return mIndex; }
547
548 inline void run(bool threaded = true);
549
550
551 UpdatePoints(UpdatePoints&, tbb::split);
552 inline void operator()(const tbb::blocked_range<size_t>& range);
553 void join(const UpdatePoints& rhs)
554 {
555 if (rhs.mRadius > mRadius) {
556 mRadius = rhs.mRadius;
557 mIndex = rhs.mIndex;
558 }
559 }
560
561 private:
562
563 const Vec4s& mSphere;
564 const std::vector<Vec3R>& mPoints;
565
566 std::vector<float>& mDistances;
567 std::vector<unsigned char>& mMask;
568
569 bool mOverlapping;
570 float mRadius;
571 int mIndex;
572 };
573
574 inline
575 UpdatePoints::UpdatePoints(
576 const Vec4s& sphere,
577 const std::vector<Vec3R>& points,
578 std::vector<float>& distances,
579 std::vector<unsigned char>& mask,
580 bool overlapping)
581 : mSphere(sphere)
582 , mPoints(points)
583 , mDistances(distances)
584 , mMask(mask)
585 , mOverlapping(overlapping)
586 , mRadius(0.0)
587 , mIndex(0)
588 {
589 }
590
591 inline
592 UpdatePoints::UpdatePoints(UpdatePoints& rhs, tbb::split)
593 : mSphere(rhs.mSphere)
594 , mPoints(rhs.mPoints)
595 , mDistances(rhs.mDistances)
596 , mMask(rhs.mMask)
597 , mOverlapping(rhs.mOverlapping)
598 , mRadius(rhs.mRadius)
599 , mIndex(rhs.mIndex)
600 {
601 }
602
603 inline void
604 UpdatePoints::run(bool threaded)
605 {
606 if (threaded) {
607 tbb::parallel_reduce(tbb::blocked_range<size_t>(0, mPoints.size()), *this);
608 } else {
609 (*this)(tbb::blocked_range<size_t>(0, mPoints.size()));
610 }
611 }
612
613 inline void
614 UpdatePoints::operator()(const tbb::blocked_range<size_t>& range)
615 {
616 Vec3s pos;
617 for (size_t n = range.begin(); n != range.end(); ++n) {
618 if (mMask[n]) continue;
619
620 pos.x() = float(mPoints[n].x()) - mSphere[0];
621 pos.y() = float(mPoints[n].y()) - mSphere[1];
622 pos.z() = float(mPoints[n].z()) - mSphere[2];
623
624 float dist = pos.length();
625
626 if (dist < mSphere[3]) {
627 mMask[n] = 1;
628 continue;
629 }
630
631 if (!mOverlapping) {
632 mDistances[n] = std::min(mDistances[n], (dist - mSphere[3]));
633 }
634
635 if (mDistances[n] > mRadius) {
636 mRadius = mDistances[n];
637 mIndex = int(n);
638 }
639 }
640 }
641
642
643 } // namespace internal
644
645
647
648
649 template<typename GridT, typename InterrupterT>
650 inline void
651 fillWithSpheres(
652 const GridT& grid,
653 std::vector<openvdb::Vec4s>& spheres,
654 int maxSphereCount,
655 bool overlapping,
656 float minRadius,
657 float maxRadius,
658 float isovalue,
659 int instanceCount,
660 InterrupterT* interrupter)
661 {
662 spheres.clear();
663 spheres.reserve(maxSphereCount);
664
665 const bool addNBPoints = grid.activeVoxelCount() < 10000;
666 int instances = std::max(instanceCount, maxSphereCount);
667
668 using TreeT = typename GridT::TreeType;
669 using ValueT = typename GridT::ValueType;
670
671 using BoolTreeT = typename TreeT::template ValueConverter<bool>::Type;
672 using Int16TreeT = typename TreeT::template ValueConverter<Int16>::Type;
673
674 using RandGen = std::mersenne_twister_engine<uint32_t, 32, 351, 175, 19,
675 0xccab8ee7, 11, 0xffffffff, 7, 0x31b6ab00, 15, 0xffe50000, 17, 1812433253>; // mt11213b
676 RandGen mtRand(/*seed=*/0);
677
678 const TreeT& tree = grid.tree();
679 const math::Transform& transform = grid.transform();
680
681 std::vector<Vec3R> instancePoints;
682 {
683 // Compute a mask of the voxels enclosed by the isosurface.
684 typename Grid<BoolTreeT>::Ptr interiorMaskPtr;
685 if (grid.getGridClass() == GRID_LEVEL_SET) {
686 // Clamp the isovalue to the level set's background value minus epsilon.
687 // (In a valid narrow-band level set, all voxels, including background voxels,
688 // have values less than or equal to the background value, so an isovalue
689 // greater than or equal to the background value would produce a mask with
690 // effectively infinite extent.)
691 isovalue = std::min(isovalue,
692 static_cast<float>(tree.background() - math::Tolerance<ValueT>::value()));
693 interiorMaskPtr = sdfInteriorMask(grid, ValueT(isovalue));
694 } else {
695 if (grid.getGridClass() == GRID_FOG_VOLUME) {
696 // Clamp the isovalue of a fog volume between epsilon and one,
697 // again to avoid a mask with infinite extent. (Recall that
698 // fog volume voxel values vary from zero outside to one inside.)
699 isovalue = math::Clamp(isovalue, math::Tolerance<float>::value(), 1.f);
700 }
701 // For non-level-set grids, the interior mask comprises the active voxels.
702 interiorMaskPtr = typename Grid<BoolTreeT>::Ptr(Grid<BoolTreeT>::create(false));
703 interiorMaskPtr->setTransform(transform.copy());
704 interiorMaskPtr->tree().topologyUnion(tree);
705 }
706
707 if (interrupter && interrupter->wasInterrupted()) return;
708
709 erodeVoxels(interiorMaskPtr->tree(), 1);
710
711 // Scatter candidate sphere centroids (instancePoints)
712 instancePoints.reserve(instances);
713 internal::PointAccessor ptnAcc(instancePoints);
714
715 UniformPointScatter<internal::PointAccessor, RandGen, InterrupterT> scatter(
716 ptnAcc, Index64(addNBPoints ? (instances / 2) : instances), mtRand, 1.0, interrupter);
717
718 scatter(*interiorMaskPtr);
719 }
720
721 if (interrupter && interrupter->wasInterrupted()) return;
722
723 ClosestSurfacePoint<GridT> csp;
724 if (!csp.initialize(grid, isovalue, interrupter)) return;
725
726 // Add extra instance points in the interior narrow band.
727 if (instancePoints.size() < size_t(instances)) {
728 const Int16TreeT& signTree = csp.signTree();
729 for (auto leafIt = signTree.cbeginLeaf(); leafIt; ++leafIt) {
730 for (auto it = leafIt->cbeginValueOn(); it; ++it) {
731 const int flags = int(it.getValue());
732 if (!(volume_to_mesh_internal::EDGES & flags)
733 && (volume_to_mesh_internal::INSIDE & flags))
734 {
735 instancePoints.push_back(transform.indexToWorld(it.getCoord()));
736 }
737 if (instancePoints.size() == size_t(instances)) break;
738 }
739 if (instancePoints.size() == size_t(instances)) break;
740 }
741 }
742
743 if (interrupter && interrupter->wasInterrupted()) return;
744
745 std::vector<float> instanceRadius;
746 if (!csp.search(instancePoints, instanceRadius)) return;
747
748 std::vector<unsigned char> instanceMask(instancePoints.size(), 0);
749 float largestRadius = 0.0;
750 int largestRadiusIdx = 0;
751
752 for (size_t n = 0, N = instancePoints.size(); n < N; ++n) {
753 if (instanceRadius[n] > largestRadius) {
754 largestRadius = instanceRadius[n];
755 largestRadiusIdx = int(n);
756 }
757 }
758
759 Vec3s pos;
760 Vec4s sphere;
761 minRadius = float(minRadius * transform.voxelSize()[0]);
762 maxRadius = float(maxRadius * transform.voxelSize()[0]);
763
764 for (size_t s = 0, S = std::min(size_t(maxSphereCount), instancePoints.size()); s < S; ++s) {
765
766 if (interrupter && interrupter->wasInterrupted()) return;
767
768 largestRadius = std::min(maxRadius, largestRadius);
769
770 if (s != 0 && largestRadius < minRadius) break;
771
772 sphere[0] = float(instancePoints[largestRadiusIdx].x());
773 sphere[1] = float(instancePoints[largestRadiusIdx].y());
774 sphere[2] = float(instancePoints[largestRadiusIdx].z());
775 sphere[3] = largestRadius;
776
777 spheres.push_back(sphere);
778 instanceMask[largestRadiusIdx] = 1;
779
780 internal::UpdatePoints op(
781 sphere, instancePoints, instanceRadius, instanceMask, overlapping);
782 op.run();
783
784 largestRadius = op.radius();
785 largestRadiusIdx = op.index();
786 }
787 } // fillWithSpheres
788
789
791
792
793 template<typename GridT>
794 ClosestSurfacePoint<GridT>::ClosestSurfacePoint()
795 : mIsInitialized(false)
796 , mPointListSize(0)
797 , mMaxNodeLeafs(0)
798 , mMaxRadiusSqr(0.0)
799 , mIdxTreePt()
800 {
801 }
802
803
804 template<typename GridT>
805 template<typename InterrupterT>
806 bool
807 ClosestSurfacePoint<GridT>::initialize(
808 const GridT& grid, float isovalue, InterrupterT* interrupter)
809 {
810 mIsInitialized = false;
811 using Index32LeafManagerT = tree::LeafManager<Index32TreeT>;
812 using ValueT = typename GridT::ValueType;
813
814 const TreeT& tree = grid.tree();
815 const math::Transform& transform = grid.transform();
816
817 { // Extract surface point cloud
818
819 BoolTreeT mask(false);
820 volume_to_mesh_internal::identifySurfaceIntersectingVoxels(mask, tree, ValueT(isovalue));
821
822 mSignTreePt.reset(new Int16TreeT(0));
823 mIdxTreePt.reset(new Index32TreeT(boost::integer_traits<Index32>::const_max));
824
825
826 volume_to_mesh_internal::computeAuxiliaryData(
827 *mSignTreePt, *mIdxTreePt, mask, tree, ValueT(isovalue));
828
829 if (interrupter && interrupter->wasInterrupted()) return false;
830
831 // count unique points
832
833 using Int16LeafNodeType = typename Int16TreeT::LeafNodeType;
834 using Index32LeafNodeType = typename Index32TreeT::LeafNodeType;
835
836 std::vector<Int16LeafNodeType*> signFlagsLeafNodes;
837 mSignTreePt->getNodes(signFlagsLeafNodes);
838
839 const tbb::blocked_range<size_t> auxiliaryLeafNodeRange(0, signFlagsLeafNodes.size());
840
841 boost::scoped_array<Index32> leafNodeOffsets(new Index32[signFlagsLeafNodes.size()]);
842
843 tbb::parallel_for(auxiliaryLeafNodeRange,
844 volume_to_mesh_internal::LeafNodePointCount<Int16LeafNodeType::LOG2DIM>
845 (signFlagsLeafNodes, leafNodeOffsets));
846
847 {
848 Index32 pointCount = 0;
849 for (size_t n = 0, N = signFlagsLeafNodes.size(); n < N; ++n) {
850 const Index32 tmp = leafNodeOffsets[n];
851 leafNodeOffsets[n] = pointCount;
852 pointCount += tmp;
853 }
854
855 mPointListSize = size_t(pointCount);
856 mSurfacePointList.reset(new Vec3s[mPointListSize]);
857 }
858
859
860 std::vector<Index32LeafNodeType*> pointIndexLeafNodes;
861 mIdxTreePt->getNodes(pointIndexLeafNodes);
862
863 tbb::parallel_for(auxiliaryLeafNodeRange, volume_to_mesh_internal::ComputePoints<TreeT>(
864 mSurfacePointList.get(), tree, pointIndexLeafNodes,
865 signFlagsLeafNodes, leafNodeOffsets, transform, ValueT(isovalue)));
866 }
867
868 if (interrupter && interrupter->wasInterrupted()) return false;
869
870 // estimate max sphere radius (sqr dist)
871 CoordBBox bbox = grid.evalActiveVoxelBoundingBox();
872
873 Vec3s dim = transform.indexToWorld(bbox.min()) -
874 transform.indexToWorld(bbox.max());
875
876 dim[0] = std::abs(dim[0]);
877 dim[1] = std::abs(dim[1]);
878 dim[2] = std::abs(dim[2]);
879
880 mMaxRadiusSqr = std::min(std::min(dim[0], dim[1]), dim[2]);
881 mMaxRadiusSqr *= 0.51f;
882 mMaxRadiusSqr *= mMaxRadiusSqr;
883
884
885 Index32LeafManagerT idxLeafs(*mIdxTreePt);
886
887 using Index32RootNodeT = typename Index32TreeT::RootNodeType;
888 using Index32NodeChainT = typename Index32RootNodeT::NodeChainType;
889 BOOST_STATIC_ASSERT(boost::mpl::size<Index32NodeChainT>::value > 1);
890 using Index32InternalNodeT =
891 typename boost::mpl::at<Index32NodeChainT, boost::mpl::int_<1> >::type;
892
893 typename Index32TreeT::NodeCIter nIt = mIdxTreePt->cbeginNode();
894 nIt.setMinDepth(Index32TreeT::NodeCIter::LEAF_DEPTH - 1);
895 nIt.setMaxDepth(Index32TreeT::NodeCIter::LEAF_DEPTH - 1);
896
897 std::vector<const Index32InternalNodeT*> internalNodes;
898
899 const Index32InternalNodeT* node = nullptr;
900 for (; nIt; ++nIt) {
901 nIt.getNode(node);
902 if (node) internalNodes.push_back(node);
903 }
904
905 std::vector<IndexRange>().swap(mLeafRanges);
906 mLeafRanges.resize(internalNodes.size());
907
908 std::vector<const Index32LeafT*>().swap(mLeafNodes);
909 mLeafNodes.reserve(idxLeafs.leafCount());
910
911 typename Index32InternalNodeT::ChildOnCIter leafIt;
912 mMaxNodeLeafs = 0;
913 for (size_t n = 0, N = internalNodes.size(); n < N; ++n) {
914
915 mLeafRanges[n].first = mLeafNodes.size();
916
917 size_t leafCount = 0;
918 for (leafIt = internalNodes[n]->cbeginChildOn(); leafIt; ++leafIt) {
919 mLeafNodes.push_back(&(*leafIt));
920 ++leafCount;
921 }
922
923 mMaxNodeLeafs = std::max(leafCount, mMaxNodeLeafs);
924
925 mLeafRanges[n].second = mLeafNodes.size();
926 }
927
928 std::vector<Vec4R>().swap(mLeafBoundingSpheres);
929 mLeafBoundingSpheres.resize(mLeafNodes.size());
930
931 internal::LeafOp<Index32LeafT> leafBS(
932 mLeafBoundingSpheres, mLeafNodes, transform, mSurfacePointList);
933 leafBS.run();
934
935
936 std::vector<Vec4R>().swap(mNodeBoundingSpheres);
937 mNodeBoundingSpheres.resize(internalNodes.size());
938
939 internal::NodeOp nodeBS(mNodeBoundingSpheres, mLeafRanges, mLeafBoundingSpheres);
940 nodeBS.run();
941 mIsInitialized = true;
942 return true;
943 } // ClosestSurfacePoint::initialize
944
945
946 template<typename GridT>
947 bool
948 ClosestSurfacePoint<GridT>::search(std::vector<Vec3R>& points,
949 std::vector<float>& distances, bool transformPoints)
950 {
951 if (!mIsInitialized) return false;
952
953 distances.clear();
954 distances.resize(points.size(), mMaxRadiusSqr);
955
956 internal::ClosestPointDist<Index32LeafT> cpd(points, distances, mSurfacePointList,
957 mLeafNodes, mLeafRanges, mLeafBoundingSpheres, mNodeBoundingSpheres,
958 mMaxNodeLeafs, transformPoints);
959
960 cpd.run();
961
962 return true;
963 }
964
965
966 template<typename GridT>
967 bool
968 ClosestSurfacePoint<GridT>::search(const std::vector<Vec3R>& points, std::vector<float>& distances)
969 {
970 return search(const_cast<std::vector<Vec3R>& >(points), distances, false);
971 }
972
973
974 template<typename GridT>
975 bool
976 ClosestSurfacePoint<GridT>::searchAndReplace(std::vector<Vec3R>& points,
977 std::vector<float>& distances)
978 {
979 return search(points, distances, true);
980 }
981
982 } // namespace tools
983 } // namespace OPENVDB_VERSION_NAME
984 } // namespace openvdb
985
986 #endif // OPENVDB_TOOLS_VOLUME_TO_MESH_HAS_BEEN_INCLUDED
987
988 // Copyright (c) 2012-2017 DreamWorks Animation LLC
989 // All rights reserved. This software is distributed under the
990 // Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ )
openvdb::v4_0_2::math::Vec4s
Vec4< float > Vec4s
Definition: Vec4.h:587
openvdb::v4_0_2::math::Tolerance
Tolerance for floating-point comparison.
Definition: Math.h:117
openvdb::v4_0_2::tools::internal::UpdatePoints::index
int index() const
Definition: VolumeToSpheres.h:546
openvdb::v4_0_2::math::Vec4
Definition: Mat4.h:51
openvdb::v4_0_2::Grid::tree
TreeType & tree()
Return a reference to this grid&#39;s tree, which might be shared with other grids.
Definition: Grid.h:797
openvdb::v4_0_2::tools::internal::UpdatePoints::radius
float radius() const
Definition: VolumeToSpheres.h:545
openvdb::v4_0_2::tools::volume_to_mesh_internal::LeafNodePointCount
Definition: VolumeToMesh.h:3915
openvdb::v4_0_2::tools::internal::ClosestPointDist::operator()
void operator()(const tbb::blocked_range< size_t > &) const
Definition: VolumeToSpheres.h:496
openvdb::v4_0_2::tools::internal::NodeOp
Definition: VolumeToSpheres.h:261
openvdb::v4_0_2::tools::internal::UpdatePoints::UpdatePoints
UpdatePoints(const Vec4s &sphere, const std::vector< Vec3R > &points, std::vector< float > &distances, std::vector< unsigned char > &mask, bool overlapping)
Definition: VolumeToSpheres.h:575
openvdb::v4_0_2::tools::ClosestSurfacePoint::signTree
const Int16TreeT & signTree() const
Tree accessor.
Definition: VolumeToSpheres.h:134
openvdb::v4_0_2::Grid::Ptr
SharedPtr< Grid > Ptr
Definition: Grid.h:502
openvdb::v4_0_2::math::Transform::copy
Ptr copy() const
Definition: Transform.h:77
openvdb::v4_0_2::Index32
uint32_t Index32
Definition: Types.h:55
openvdb::v4_0_2::tools::internal::PointAccessor::add
void add(const Vec3R &pos)
Definition: VolumeToSpheres.h:168
i
tbb::atomic< Index32 > i
Definition: LeafBuffer.h:71
openvdb::v4_0_2::tools::ClosestSurfacePoint::BoolTreeT
typename TreeT::template ValueConverter< bool >::Type BoolTreeT
Definition: VolumeToSpheres.h:102
openvdb::v4_0_2::tools::volume_to_mesh_internal::identifySurfaceIntersectingVoxels
void identifySurfaceIntersectingVoxels(typename InputTreeType::template ValueConverter< bool >::Type &intersectionTree, const InputTreeType &inputTree, typename InputTreeType::ValueType isovalue)
Definition: VolumeToMesh.h:3349
openvdb::v4_0_2::tools::ClosestSurfacePoint::Int16TreeT
typename TreeT::template ValueConverter< Int16 >::Type Int16TreeT
Definition: VolumeToSpheres.h:104
openvdb::v4_0_2::math::CoordBBox
Axis-aligned bounding box of signed integer coordinates.
Definition: Coord.h:261
openvdb::v4_0_2::tools::internal::PointAccessor::PointAccessor
PointAccessor(std::vector< Vec3R > &points)
Definition: VolumeToSpheres.h:163
PointScatter.h
We offer three different algorithms (each in its own class) for scattering of points in active voxels...
openvdb::v4_0_2::tools::volume_to_mesh_internal::EDGES
Definition: VolumeToMesh.h:425
openvdb::v4_0_2::math::Vec3< Real >
openvdb::v4_0_2::math::Vec3s
Vec3< float > Vec3s
Definition: Vec3.h:677
openvdb::v4_0_2::tools::volume_to_mesh_internal::INSIDE
Definition: VolumeToMesh.h:425
openvdb::v4_0_2::tools::internal::LeafOp::operator()
void operator()(const tbb::blocked_range< size_t > &) const
Definition: VolumeToSpheres.h:225
openvdb::v4_0_2::tools::UniformPointScatter
The two point scatters UniformPointScatter and NonUniformPointScatter depend on the following two cla...
Definition: PointScatter.h:112
openvdb::v4_0_2::tools::composite::max
const std::enable_if<!VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition: Composite.h:133
openvdb::v4_0_2::tools::volume_to_mesh_internal::computeAuxiliaryData
void computeAuxiliaryData(typename InputTreeType::template ValueConverter< Int16 >::Type &signFlagsTree, typename InputTreeType::template ValueConverter< Index32 >::Type &pointIndexTree, const typename InputTreeType::template ValueConverter< bool >::Type &intersectionTree, const InputTreeType &inputTree, typename InputTreeType::ValueType isovalue)
Definition: VolumeToMesh.h:3891
openvdb::v4_0_2::tools::internal::ClosestPointDist::IndexRange
std::pair< size_t, size_t > IndexRange
Definition: VolumeToSpheres.h:350
openvdb::v4_0_2::tools::composite::min
const std::enable_if<!VecTraits< T >::IsVec, T >::type & min(const T &a, const T &b)
Definition: Composite.h:129
openvdb::v4_0_2::Index64
uint64_t Index64
Definition: Types.h:56
openvdb::v4_0_2::math::Transform
Calculate an axis-aligned bounding box in index space from a bounding sphere in world space...
Definition: Transform.h:66
VolumeToMesh.h
Extract polygonal surfaces from scalar volumes.
OPENVDB_VERSION_NAME
#define OPENVDB_VERSION_NAME
Definition: version.h:43
openvdb::v4_0_2::tools::internal::ClosestPointDist
Definition: VolumeToSpheres.h:347
openvdb::v4_0_2::tools::fillWithSpheres
void fillWithSpheres(const GridT &grid, std::vector< openvdb::Vec4s > &spheres, int maxSphereCount, bool overlapping=false, float minRadius=1.0, float maxRadius=std::numeric_limits< float >::max(), float isovalue=0.0, int instanceCount=10000, InterrupterT *interrupter=nullptr)
Fill a closed level set or fog volume with adaptively-sized spheres.
Definition: VolumeToSpheres.h:651
openvdb::v4_0_2::tools::internal::UpdatePoints::operator()
void operator()(const tbb::blocked_range< size_t > &range)
Definition: VolumeToSpheres.h:614
openvdb::v4_0_2::tools::internal::ClosestPointDist::run
void run(bool threaded=true)
Definition: VolumeToSpheres.h:420
openvdb::v4_0_2::tools::internal::NodeOp::run
void run(bool threaded=true)
Definition: VolumeToSpheres.h:291
openvdb::v4_0_2::tools::sdfInteriorMask
GridOrTreeType::template ValueConverter< bool >::Type::Ptr sdfInteriorMask(const GridOrTreeType &volume, typename GridOrTreeType::ValueType isovalue=lsutilGridZero< GridOrTreeType >())
Threaded method to construct a boolean mask that represents interior regions in a signed distance fie...
Definition: LevelSetUtil.h:2291
openvdb::v4_0_2::tree::LeafManager::tree
const TreeType & tree() const
Return a const reference to tree associated with this manager.
Definition: LeafManager.h:343
openvdb::v4_0_2::tools::internal::NodeOp::operator()
void operator()(const tbb::blocked_range< size_t > &) const
Definition: VolumeToSpheres.h:301
Morphology.h
Implementation of morphological dilation and erosion.
openvdb::v4_0_2::tools::internal::UpdatePoints
Definition: VolumeToSpheres.h:535
openvdb
Definition: Exceptions.h:39
openvdb::v4_0_2::tools::internal::NodeOp::IndexRange
std::pair< size_t, size_t > IndexRange
Definition: VolumeToSpheres.h:264
openvdb::v4_0_2::math::CoordBBox::max
const Coord & max() const
Definition: Coord.h:335
openvdb::v4_0_2::tools::internal::UpdatePoints::join
void join(const UpdatePoints &rhs)
Definition: VolumeToSpheres.h:553
openvdb::v4_0_2::math::Vec3::x
T & x()
Reference to the component, e.g. v.x() = 4.5f;.
Definition: Vec3.h:109
openvdb::v4_0_2::math::Vec3d
Vec3< double > Vec3d
Definition: Vec3.h:678
openvdb::v4_0_2::initialize
OPENVDB_IMPORT void initialize()
Global registration of basic types.
openvdb::v4_0_2::tools::internal::LeafOp
Definition: VolumeToSpheres.h:178
openvdb::v4_0_2::tools::ClosestSurfacePoint::indexTree
const Index32TreeT & indexTree() const
Tree accessor.
Definition: VolumeToSpheres.h:132
openvdb::v4_0_2::math::Clamp
Type Clamp(Type x, Type min, Type max)
Return x clamped to [min, max].
Definition: Math.h:230
openvdb::v4_0_2::tools::ClosestSurfacePoint::TreeT
typename GridT::TreeType TreeT
Definition: VolumeToSpheres.h:101
openvdb::v4_0_2::tools::internal::NodeOp::NodeOp
NodeOp(std::vector< Vec4R > &nodeBoundingSpheres, const std::vector< IndexRange > &leafRanges, const std::vector< Vec4R > &leafBoundingSpheres)
Definition: VolumeToSpheres.h:281
openvdb::v4_0_2::tools::volume_to_mesh_internal::ComputePoints
Definition: VolumeToMesh.h:1475
openvdb::v4_0_2::tree::LeafManager
This class manages a linear array of pointers to a given tree&#39;s leaf nodes, as well as optional auxil...
Definition: LeafManager.h:110
openvdb::v4_0_2::tools::ClosestSurfacePoint::ClosestSurfacePoint
ClosestSurfacePoint()
Definition: VolumeToSpheres.h:794
openvdb::v4_0_2::math::Transform::indexToWorld
Vec3d indexToWorld(const Vec3d &xyz) const
Apply this transformation to the given coordinates.
Definition: Transform.h:135
openvdb::v4_0_2::tools::ClosestSurfacePoint::searchAndReplace
bool searchAndReplace(std::vector< Vec3R > &points, std::vector< float > &distances)
Overwrite each input point with its closest surface point.
Definition: VolumeToSpheres.h:976
LevelSetUtil.h
Miscellaneous utility methods that operate primarily or exclusively on level set grids.
openvdb::v4_0_2::tools::PointList
boost::scoped_array< openvdb::Vec3s > PointList
Point and primitive list types.
Definition: VolumeToMesh.h:180
openvdb::v4_0_2::tools::ClosestSurfacePoint::Index32TreeT
typename TreeT::template ValueConverter< Index32 >::Type Index32TreeT
Definition: VolumeToSpheres.h:103
openvdb::v4_0_2::GridBase::setTransform
void setTransform(math::Transform::Ptr)
Associate the given transform with this grid, in place of its existing transform. ...
Definition: Grid.h:1112
openvdb::v4_0_2::Grid
Container class that associates a tree with a transform and metadata.
Definition: Grid.h:55
OPENVDB_USE_VERSION_NAMESPACE
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:71
openvdb::v4_0_2::tools::internal::LeafOp::run
void run(bool threaded=true)
Definition: VolumeToSpheres.h:214
LeafManager.h
A LeafManager manages a linear array of pointers to a given tree&#39;s leaf nodes, as well as optional au...
openvdb::v4_0_2::tools::erodeVoxels
void erodeVoxels(TreeType &tree, int iterations=1, NearestNeighbors nn=NN_FACE)
Topologically erode all leaf-level active voxels in the given tree.
Definition: Morphology.h:877
openvdb::v4_0_2::tools::internal::UpdatePoints::run
void run(bool threaded=true)
Definition: VolumeToSpheres.h:604
openvdb::v4_0_2::math::Tolerance::value
static T value()
Definition: Math.h:117
openvdb::v4_0_2::math::CoordBBox::min
const Coord & min() const
Definition: Coord.h:334
openvdb::v4_0_2::tools::ClosestSurfacePoint::initialize
bool initialize(const GridT &grid, float isovalue=0.0, InterrupterT *interrupter=nullptr)
Extract surface points and construct a spatial acceleration structure.
Definition: VolumeToSpheres.h:807
openvdb::v4_0_2::math::Transform::voxelSize
Vec3d voxelSize() const
Return the size of a voxel using the linear component of the map.
Definition: Transform.h:120
openvdb::v4_0_2::tools::internal::PointAccessor
Definition: VolumeToSpheres.h:161
size
static constexpr size_t size
The size of a LeafBuffer when LeafBuffer::mOutOfCore is atomic.
Definition: LeafBuffer.h:85
openvdb::v4_0_2::points::pointCount
Index64 pointCount(const PointDataTreeT &tree, const bool inCoreOnly=false)
Total points in the PointDataTree.
Definition: PointCount.h:198
openvdb::v4_0_2::GRID_LEVEL_SET
Definition: Types.h:264
openvdb::v4_0_2::GRID_FOG_VOLUME
Definition: Types.h:265
openvdb::v4_0_2::tools::ClosestSurfacePoint::search
bool search(const std::vector< Vec3R > &points, std::vector< float > &distances)
Compute the distance from each input point to its closest surface point.
Definition: VolumeToSpheres.h:968
openvdb::v4_0_2::tools::internal::ClosestPointDist::ClosestPointDist
ClosestPointDist(std::vector< Vec3R > &instancePoints, std::vector< float > &instanceDistances, const PointList &surfacePointList, const std::vector< const Index32LeafT *> &leafNodes, const std::vector< IndexRange > &leafRanges, const std::vector< Vec4R > &leafBoundingSpheres, const std::vector< Vec4R > &nodeBoundingSpheres, size_t maxNodeLeafs, bool transformPoints=false)
Definition: VolumeToSpheres.h:393
openvdb::v4_0_2::tools::ClosestSurfacePoint
Accelerated closest surface point queries for narrow band level sets.
Definition: VolumeToSpheres.h:98