OpenVDB 5.1.0

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