OpenVDB 12.1.0

Loading...
Searching...
No Matches
ParticlesToLevelSet.h
Go to the documentation of this file.
1// Copyright Contributors to the OpenVDB Project
2// SPDX-License-Identifier: Apache-2.0
3
4/// @author Ken Museth
5///
6/// @file tools/ParticlesToLevelSet.h
7///
8/// @brief Rasterize particles with position, radius and velocity
9/// into either a boolean mask grid or a narrow-band level set grid.
10///
11/// @details Optionally, arbitrary attributes on the particles can be transferred,
12/// resulting in additional output grids with the same topology as the main grid.
13///
14/// @note Particle to level set conversion is intended to be combined with
15/// some kind of surface postprocessing, using
16/// @vdblink::tools::LevelSetFilter LevelSetFilter@endlink, for example.
17/// Without such postprocessing the generated surface is typically too noisy and blobby.
18/// However, it serves as a great and fast starting point for subsequent
19/// level set surface processing and convolution.
20///
21/// @details For particle access, any class with the following interface may be used
22/// (see the unit test or the From Particles Houdini SOP for practical examples):
23/// @code
24/// struct ParticleList
25/// {
26/// // Return the total number of particles in the list.
27/// // Always required!
28/// size_t size() const;
29///
30/// // Get the world-space position of the nth particle.
31/// // Required by rasterizeSpheres().
32/// void getPos(size_t n, Vec3R& xyz) const;
33///
34/// // Get the world-space position and radius of the nth particle.
35/// // Required by rasterizeSpheres().
36/// void getPosRad(size_t n, Vec3R& xyz, Real& radius) const;
37///
38/// // Get the world-space position, radius and velocity of the nth particle.
39/// // Required by rasterizeTrails().
40/// void getPosRadVel(size_t n, Vec3R& xyz, Real& radius, Vec3R& velocity) const;
41///
42/// // Get the value of the nth particle's user-defined attribute (of type @c AttributeType).
43/// // Required only if attribute transfer is enabled in ParticlesToLevelSet.
44/// void getAtt(size_t n, AttributeType& att) const;
45/// };
46/// @endcode
47///
48/// Some functions accept an interrupter argument. This refers to any class
49/// with the following interface:
50/// @code
51/// struct Interrupter
52/// {
53/// void start(const char* name = nullptr) // called when computations begin
54/// void end() // called when computations end
55/// bool wasInterrupted(int percent=-1) // return true to abort computation
56/// };
57/// @endcode
58///
59/// The default interrupter is @vdblink::util::NullInterrupter NullInterrupter@endlink,
60/// for which all calls are no-ops that incur no computational overhead.
61
62#ifndef OPENVDB_TOOLS_PARTICLES_TO_LEVELSET_HAS_BEEN_INCLUDED
63#define OPENVDB_TOOLS_PARTICLES_TO_LEVELSET_HAS_BEEN_INCLUDED
64
65#include <openvdb/Types.h>
66#include <openvdb/Grid.h>
67#include <openvdb/math/Math.h>
68#include <openvdb/math/Transform.h>
69#include <openvdb/tree/LeafManager.h>
70#include <openvdb/util/logging.h>
71#include <openvdb/util/NullInterrupter.h>
72#include <openvdb/util/Assert.h>
73#include <openvdb/thread/Threading.h>
74
75#include "Composite.h" // for csgUnion()
76#include "PointPartitioner.h"
77#include "Prune.h"
78#include "SignedFloodFill.h"
79
80#include <tbb/parallel_reduce.h>
81#include <tbb/blocked_range.h>
82
83#include <functional>
84#include <iostream>
85#include <type_traits>
86#include <vector>
87
88
89 namespace openvdb {
90 OPENVDB_USE_VERSION_NAMESPACE
91 namespace OPENVDB_VERSION_NAME {
92 namespace tools {
93
94/// @brief Populate a scalar, floating-point grid with CSG-unioned level set spheres
95/// described by the given particle positions and radii.
96/// @details For more control over the output, including attribute transfer,
97/// use the ParticlesToLevelSet class directly.
98 template<typename GridT, typename ParticleListT, typename InterrupterT = util::NullInterrupter>
99 inline void particlesToSdf(const ParticleListT&, GridT&, InterrupterT* = nullptr);
100
101/// @brief Populate a scalar, floating-point grid with fixed-size, CSG-unioned
102/// level set spheres described by the given particle positions and the specified radius.
103/// @details For more control over the output, including attribute transfer,
104/// use the ParticlesToLevelSet class directly.
105 template<typename GridT, typename ParticleListT, typename InterrupterT = util::NullInterrupter>
106 inline void particlesToSdf(const ParticleListT&, GridT&, Real radius, InterrupterT* = nullptr);
107
108/// @brief Populate a scalar, floating-point grid with CSG-unioned trails
109/// of level set spheres with decreasing radius, where the starting position and radius
110/// and the direction of each trail is given by particle attributes.
111/// @details For more control over the output, including attribute transfer,
112/// use the ParticlesToLevelSet class directly.
113/// @note The @a delta parameter controls the distance between spheres in a trail.
114/// Be careful not to use too small a value.
115 template<typename GridT, typename ParticleListT, typename InterrupterT = util::NullInterrupter>
116 inline void particleTrailsToSdf(const ParticleListT&, GridT&, Real delta=1, InterrupterT* =nullptr);
117
118/// @brief Activate a boolean grid wherever it intersects the spheres
119/// described by the given particle positions and radii.
120/// @details For more control over the output, including attribute transfer,
121/// use the ParticlesToLevelSet class directly.
122 template<typename GridT, typename ParticleListT, typename InterrupterT = util::NullInterrupter>
123 inline void particlesToMask(const ParticleListT&, GridT&, InterrupterT* = nullptr);
124
125/// @brief Activate a boolean grid wherever it intersects the fixed-size spheres
126/// described by the given particle positions and the specified radius.
127/// @details For more control over the output, including attribute transfer,
128/// use the ParticlesToLevelSet class directly.
129 template<typename GridT, typename ParticleListT, typename InterrupterT = util::NullInterrupter>
130 inline void particlesToMask(const ParticleListT&, GridT&, Real radius, InterrupterT* = nullptr);
131
132/// @brief Activate a boolean grid wherever it intersects trails of spheres
133/// with decreasing radius, where the starting position and radius and the direction
134/// of each trail is given by particle attributes.
135/// @details For more control over the output, including attribute transfer,
136/// use the ParticlesToLevelSet class directly.
137/// @note The @a delta parameter controls the distance between spheres in a trail.
138/// Be careful not to use too small a value.
139 template<typename GridT, typename ParticleListT, typename InterrupterT = util::NullInterrupter>
140 inline void particleTrailsToMask(const ParticleListT&, GridT&,Real delta=1,InterrupterT* =nullptr);
141
142
143////////////////////////////////////////
144
145/// @cond OPENVDB_DOCS_INTERNAL
146
147 namespace p2ls_internal {
148// This is a simple type that combines a distance value and a particle
149// attribute. It's required for attribute transfer which is performed
150// in the ParticlesToLevelSet::Raster member class defined below.
151/// @private
152 template<typename VisibleT, typename BlindT> class BlindData;
153}
154
155/// @endcond
156
157 template<typename SdfGridT,
158 typename AttributeT = void,
159 typename InterrupterT = util::NullInterrupter>
160 class ParticlesToLevelSet
161{
162 public:
163 using DisableT = typename std::is_void<AttributeT>::type;
164 using InterrupterType = InterrupterT;
165
166 using SdfGridType = SdfGridT;
167 using SdfType = typename SdfGridT::ValueType;
168
169 using AttType = typename std::conditional<DisableT::value, size_t, AttributeT>::type;
170 using AttGridType = typename SdfGridT::template ValueConverter<AttType>::Type;
171
172 static const bool OutputIsMask = std::is_same<SdfType, bool>::value;
173
174 /// @brief Constructor using an existing boolean or narrow-band level set grid
175 ///
176 /// @param grid grid into which particles are rasterized
177 /// @param interrupt callback to interrupt a long-running process
178 ///
179 /// @details If the input grid is already populated with signed distances,
180 /// particles are unioned onto the existing level set surface.
181 ///
182 /// @details The width in voxel units of the generated narrow band level set
183 /// is given by 2&times;<I>background</I>/<I>dx</I>, where @a background
184 /// is the background value stored in the grid and @a dx is the voxel size
185 /// derived from the transform associated with the grid.
186 /// Also note that &minus;<I>background</I> corresponds to the constant value
187 /// inside the generated narrow-band level set.
188 ///
189 /// @note If attribute transfer is enabled, i.e., if @c AttributeT is not @c void,
190 /// attributes are generated only for voxels that overlap with particles,
191 /// not for any other preexisting voxels (for which no attributes exist!).
192 explicit ParticlesToLevelSet(SdfGridT& grid, InterrupterT* interrupt = nullptr);
193
194 ~ParticlesToLevelSet() { delete mBlindGrid; }
195
196 /// @brief This method syncs up the level set and attribute grids
197 /// and therefore needs to be called before any of those grids are
198 /// used and after the last call to any of the rasterizer methods.
199 /// @details It has no effect or overhead if attribute transfer is disabled
200 /// (i.e., if @c AttributeT is @c void) and @a prune is @c false.
201 ///
202 /// @note Avoid calling this method more than once, and call it only after
203 /// all the particles have been rasterized.
204 void finalize(bool prune = false);
205
206 /// @brief Return a pointer to the grid containing the optional user-defined attribute.
207 /// @warning If attribute transfer is disabled (i.e., if @c AttributeT is @c void)
208 /// or if @link finalize() finalize@endlink is not called, the pointer will be null.
209 typename AttGridType::Ptr attributeGrid() { return mAttGrid; }
210
211 /// @brief Return the size of a voxel in world units.
212 Real getVoxelSize() const { return mDx; }
213
214 /// @brief Return the half-width of the narrow band in voxel units.
215 Real getHalfWidth() const { return mHalfWidth; }
216
217 /// @brief Return the smallest radius allowed in voxel units.
218 Real getRmin() const { return mRmin; }
219 /// @brief Set the smallest radius allowed in voxel units.
220 void setRmin(Real Rmin) { mRmin = math::Max(Real(0),Rmin); }
221
222 /// @brief Return the largest radius allowed in voxel units.
223 Real getRmax() const { return mRmax; }
224 /// @brief Set the largest radius allowed in voxel units.
225 void setRmax(Real Rmax) { mRmax = math::Max(mRmin,Rmax); }
226
227 /// @brief Return @c true if any particles were ignored due to their size.
228 bool ignoredParticles() const { return mMinCount>0 || mMaxCount>0; }
229 /// @brief Return the number of particles that were ignored because they were
230 /// smaller than the minimum radius.
231 size_t getMinCount() const { return mMinCount; }
232 /// @brief Return the number of particles that were ignored because they were
233 /// larger than the maximum radius.
234 size_t getMaxCount() const { return mMaxCount; }
235
236 /// @brief Return the grain size used for threading
237 int getGrainSize() const { return mGrainSize; }
238 /// @brief Set the grain size used for threading.
239 /// @note A grain size of zero or less disables threading.
240 void setGrainSize(int grainSize) { mGrainSize = grainSize; }
241
242 /// @brief Rasterize each particle as a sphere with the particle's position and radius.
243 /// @details For level set output, all spheres are CSG-unioned.
244 template<typename ParticleListT>
245 void rasterizeSpheres(const ParticleListT& pa);
246
247 /// @brief Rasterize each particle as a sphere with the particle's position
248 /// and a fixed radius.
249 /// @details For level set output, all spheres are CSG-unioned.
250 ///
251 /// @param pa particles with positions
252 /// @param radius fixed sphere radius in world units.
253 template<typename ParticleListT>
254 void rasterizeSpheres(const ParticleListT& pa, Real radius);
255
256 /// @brief Rasterize each particle as a trail comprising the CSG union
257 /// of spheres of decreasing radius.
258 ///
259 /// @param pa particles with position, radius and velocity.
260 /// @param delta controls the distance between sphere instances
261 ///
262 /// @warning Be careful not to use too small values for @a delta,
263 /// since this can lead to excessive computation per trail (which the
264 /// interrupter can't stop).
265 ///
266 /// @note The direction of a trail is opposite to that of the velocity vector,
267 /// and its length is given by the magnitude of the velocity.
268 /// The radius at the head of the trail is given by the radius of the particle,
269 /// and the radius at the tail is @a Rmin voxel units, which has
270 /// a default value of 1.5 corresponding to the Nyquist frequency!
271 template<typename ParticleListT>
272 void rasterizeTrails(const ParticleListT& pa, Real delta=1.0);
273
274 private:
275 using BlindType = p2ls_internal::BlindData<SdfType, AttType>;
276 using BlindGridType = typename SdfGridT::template ValueConverter<BlindType>::Type;
277
278 /// Class with multi-threaded implementation of particle rasterization
279 template<typename ParticleListT, typename GridT> struct Raster;
280
281 SdfGridType* mSdfGrid;
282 typename AttGridType::Ptr mAttGrid;
283 BlindGridType* mBlindGrid;
284 InterrupterT* mInterrupter;
285 Real mDx, mHalfWidth;
286 Real mRmin, mRmax; // ignore particles outside this range of radii in voxel
287 size_t mMinCount, mMaxCount; // counters for ignored particles
288 int mGrainSize;
289}; // class ParticlesToLevelSet
290
291
292 template<typename SdfGridT, typename AttributeT, typename InterrupterT>
293 inline ParticlesToLevelSet<SdfGridT, AttributeT, InterrupterT>::
294 ParticlesToLevelSet(SdfGridT& grid, InterrupterT* interrupter) :
295 mSdfGrid(&grid),
296 mBlindGrid(nullptr),
297 mInterrupter(interrupter),
298 mDx(grid.voxelSize()[0]),
299 mHalfWidth(grid.background()/mDx),
300 mRmin(1.5),// corresponds to the Nyquist grid sampling frequency
301 mRmax(100.0),// corresponds to a huge particle (probably too large!)
302 mMinCount(0),
303 mMaxCount(0),
304 mGrainSize(1)
305{
306 if (!mSdfGrid->hasUniformVoxels()) {
307 OPENVDB_THROW(RuntimeError, "ParticlesToLevelSet only supports uniform voxels!");
308 }
309 if (!DisableT::value) {
310 mBlindGrid = new BlindGridType(BlindType(grid.background()));
311 mBlindGrid->setTransform(mSdfGrid->transform().copy());
312 }
313}
314
315 template<typename SdfGridT, typename AttributeT, typename InterrupterT>
316 template<typename ParticleListT>
317 inline void ParticlesToLevelSet<SdfGridT, AttributeT, InterrupterT>::
318 rasterizeSpheres(const ParticleListT& pa)
319{
320 if (DisableT::value) {
321 Raster<ParticleListT, SdfGridT> r(*this, mSdfGrid, pa);
322 r.rasterizeSpheres();
323 } else {
324 Raster<ParticleListT, BlindGridType> r(*this, mBlindGrid, pa);
325 r.rasterizeSpheres();
326 }
327}
328
329 template<typename SdfGridT, typename AttributeT, typename InterrupterT>
330 template<typename ParticleListT>
331 inline void ParticlesToLevelSet<SdfGridT, AttributeT, InterrupterT>::
332 rasterizeSpheres(const ParticleListT& pa, Real radius)
333{
334 if (DisableT::value) {
335 Raster<ParticleListT, SdfGridT> r(*this, mSdfGrid, pa);
336 r.rasterizeSpheres(radius/mDx);
337 } else {
338 Raster<ParticleListT, BlindGridType> r(*this, mBlindGrid, pa);
339 r.rasterizeSpheres(radius/mDx);
340 }
341}
342
343 template<typename SdfGridT, typename AttributeT, typename InterrupterT>
344 template<typename ParticleListT>
345 inline void ParticlesToLevelSet<SdfGridT, AttributeT, InterrupterT>::
346 rasterizeTrails(const ParticleListT& pa, Real delta)
347{
348 if (DisableT::value) {
349 Raster<ParticleListT, SdfGridT> r(*this, mSdfGrid, pa);
350 r.rasterizeTrails(delta);
351 } else {
352 Raster<ParticleListT, BlindGridType> r(*this, mBlindGrid, pa);
353 r.rasterizeTrails(delta);
354 }
355}
356
357
358 template<typename SdfGridT, typename AttributeT, typename InterrupterT>
359 inline void
360 ParticlesToLevelSet<SdfGridT, AttributeT, InterrupterT>::finalize(bool prune)
361{
362 OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
363
364 if (!mBlindGrid) {
365 if (prune) {
366 if (OutputIsMask) {
367 tools::prune(mSdfGrid->tree());
368 } else {
369 tools::pruneLevelSet(mSdfGrid->tree());
370 }
371 }
372 return;
373 }
374
375 if (prune) tools::prune(mBlindGrid->tree());
376
377 using AttTreeT = typename AttGridType::TreeType;
378 using AttLeafT = typename AttTreeT::LeafNodeType;
379 using BlindTreeT = typename BlindGridType::TreeType;
380 using BlindLeafIterT = typename BlindTreeT::LeafCIter;
381 using BlindLeafT = typename BlindTreeT::LeafNodeType;
382 using SdfTreeT = typename SdfGridType::TreeType;
383 using SdfLeafT = typename SdfTreeT::LeafNodeType;
384
385 // Use topology copy constructors since output grids have the same topology as mBlindDataGrid
386 const BlindTreeT& blindTree = mBlindGrid->tree();
387
388 // Create the output attribute grid.
389 typename AttTreeT::Ptr attTree(new AttTreeT(
390 blindTree, blindTree.background().blind(), openvdb::TopologyCopy()));
391 // Note this overwrites any existing attribute grids!
392 mAttGrid = typename AttGridType::Ptr(new AttGridType(attTree));
393 mAttGrid->setTransform(mBlindGrid->transform().copy());
394
395 typename SdfTreeT::Ptr sdfTree; // the output mask or level set tree
396
397 // Extract the attribute grid and the mask or level set grid from mBlindDataGrid.
398 if (OutputIsMask) {
399 sdfTree.reset(new SdfTreeT(blindTree,
400 /*off=*/SdfType(0), /*on=*/SdfType(1), TopologyCopy()));
401
402 // Copy leaf voxels in parallel.
403 tree::LeafManager<AttTreeT> leafNodes(*attTree);
404 leafNodes.foreach([&](AttLeafT& attLeaf, size_t /*leafIndex*/) {
405 if (const auto* blindLeaf = blindTree.probeConstLeaf(attLeaf.origin())) {
406 for (auto iter = attLeaf.beginValueOn(); iter; ++iter) {
407 const auto pos = iter.pos();
408 attLeaf.setValueOnly(pos, blindLeaf->getValue(pos).blind());
409 }
410 }
411 });
412 // Copy tiles serially.
413 const auto blindAcc = mBlindGrid->getConstAccessor();
414 auto iter = attTree->beginValueOn();
415 iter.setMaxDepth(AttTreeT::ValueOnIter::LEAF_DEPTH - 1);
416 for ( ; iter; ++iter) {
417 iter.modifyValue([&](AttType& v) { v = blindAcc.getValue(iter.getCoord()).blind(); });
418 }
419 } else {
420 // Here we exploit the fact that by design level sets have no active tiles.
421 // Only leaf voxels can be active.
422 sdfTree.reset(new SdfTreeT(blindTree, blindTree.background().visible(), TopologyCopy()));
423 for (BlindLeafIterT n = blindTree.cbeginLeaf(); n; ++n) {
424 const BlindLeafT& leaf = *n;
425 const openvdb::Coord xyz = leaf.origin();
426 // Get leafnodes that were allocated during topology construction!
427 SdfLeafT* sdfLeaf = sdfTree->probeLeaf(xyz);
428 AttLeafT* attLeaf = attTree->probeLeaf(xyz);
429 // Use linear offset (vs coordinate) access for better performance!
430 typename BlindLeafT::ValueOnCIter m=leaf.cbeginValueOn();
431 if (!m) {//no active values in leaf node so copy everything
432 for (openvdb::Index k = 0; k!=BlindLeafT::SIZE; ++k) {
433 const BlindType& v = leaf.getValue(k);
434 sdfLeaf->setValueOnly(k, v.visible());
435 attLeaf->setValueOnly(k, v.blind());
436 }
437 } else {//only copy active values (using flood fill for the inactive values)
438 for(; m; ++m) {
439 const openvdb::Index k = m.pos();
440 const BlindType& v = *m;
441 sdfLeaf->setValueOnly(k, v.visible());
442 attLeaf->setValueOnly(k, v.blind());
443 }
444 }
445 }
446 tools::signedFloodFill(*sdfTree);//required since we only transferred active voxels!
447 }
448
449 if (mSdfGrid->empty()) {
450 mSdfGrid->setTree(sdfTree);
451 } else {
452 if (OutputIsMask) {
453 mSdfGrid->tree().topologyUnion(*sdfTree);
454 tools::prune(mSdfGrid->tree());
455 } else {
456 tools::csgUnion(mSdfGrid->tree(), *sdfTree, /*prune=*/true);
457 }
458 }
459
460 OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
461}
462
463
464///////////////////////////////////////////////////////////
465
466
467 template<typename SdfGridT, typename AttributeT, typename InterrupterT>
468 template<typename ParticleListT, typename GridT>
469 struct ParticlesToLevelSet<SdfGridT, AttributeT, InterrupterT>::Raster
470{
471 using DisableT = typename std::is_void<AttributeT>::type;
472 using ParticlesToLevelSetT = ParticlesToLevelSet<SdfGridT, AttributeT, InterrupterT>;
473 using SdfT = typename ParticlesToLevelSetT::SdfType; // type of signed distance values
474 using AttT = typename ParticlesToLevelSetT::AttType; // type of particle attribute
475 using ValueT = typename GridT::ValueType;
476 using AccessorT = typename GridT::Accessor;
477 using TreeT = typename GridT::TreeType;
478 using LeafNodeT = typename TreeT::LeafNodeType;
479 using PointPartitionerT = PointPartitioner<Index32, LeafNodeT::LOG2DIM>;
480
481 static const bool
482 OutputIsMask = std::is_same<SdfT, bool>::value,
483 DoAttrXfer = !DisableT::value;
484
485 /// @brief Main constructor
486 Raster(ParticlesToLevelSetT& parent, GridT* grid, const ParticleListT& particles)
487 : mParent(parent)
488 , mParticles(particles)
489 , mGrid(grid)
490 , mMap(*(mGrid->transform().baseMap()))
491 , mMinCount(0)
492 , mMaxCount(0)
493 , mIsCopy(false)
494 {
495 mPointPartitioner = new PointPartitionerT;
496 mPointPartitioner->construct(particles, mGrid->transform());
497 }
498
499 /// @brief Copy constructor called by tbb threads
500 Raster(Raster& other, tbb::split)
501 : mParent(other.mParent)
502 , mParticles(other.mParticles)
503 , mGrid(new GridT(*other.mGrid, openvdb::ShallowCopy()))
504 , mMap(other.mMap)
505 , mMinCount(0)
506 , mMaxCount(0)
507 , mTask(other.mTask)
508 , mIsCopy(true)
509 , mPointPartitioner(other.mPointPartitioner)
510 {
511 mGrid->newTree();
512 }
513
514 virtual ~Raster()
515 {
516 // Copy-constructed Rasters own temporary grids that have to be deleted,
517 // while the original has ownership of the bucket array.
518 if (mIsCopy) {
519 delete mGrid;
520 } else {
521 delete mPointPartitioner;
522 }
523 }
524
525 void rasterizeSpheres()
526 {
527 mMinCount = mMaxCount = 0;
528 if (mParent.mInterrupter) {
529 mParent.mInterrupter->start("Rasterizing particles to level set using spheres");
530 }
531 mTask = std::bind(&Raster::rasterSpheres, std::placeholders::_1, std::placeholders::_2);
532 this->cook();
533 if (mParent.mInterrupter) mParent.mInterrupter->end();
534 }
535
536 void rasterizeSpheres(Real radius)
537 {
538 mMinCount = radius < mParent.mRmin ? mParticles.size() : 0;
539 mMaxCount = radius > mParent.mRmax ? mParticles.size() : 0;
540 if (mMinCount>0 || mMaxCount>0) {//skipping all particles!
541 mParent.mMinCount = mMinCount;
542 mParent.mMaxCount = mMaxCount;
543 } else {
544 if (mParent.mInterrupter) {
545 mParent.mInterrupter->start(
546 "Rasterizing particles to level set using const spheres");
547 }
548 mTask = std::bind(&Raster::rasterFixedSpheres,
549 std::placeholders::_1, std::placeholders::_2, radius);
550 this->cook();
551 if (mParent.mInterrupter) mParent.mInterrupter->end();
552 }
553 }
554
555 void rasterizeTrails(Real delta=1.0)
556 {
557 mMinCount = mMaxCount = 0;
558 if (mParent.mInterrupter) {
559 mParent.mInterrupter->start("Rasterizing particles to level set using trails");
560 }
561 mTask = std::bind(&Raster::rasterTrails,
562 std::placeholders::_1, std::placeholders::_2, delta);
563 this->cook();
564 if (mParent.mInterrupter) mParent.mInterrupter->end();
565 }
566
567 /// @brief Kick off the optionally multithreaded computation.
568 void operator()(const tbb::blocked_range<size_t>& r)
569 {
570 OPENVDB_ASSERT(mTask);
571 mTask(this, r);
572 mParent.mMinCount = mMinCount;
573 mParent.mMaxCount = mMaxCount;
574 }
575
576 /// @brief Required by tbb::parallel_reduce
577 void join(Raster& other)
578 {
579 OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
580 if (OutputIsMask) {
581 if (DoAttrXfer) {
582 tools::compMax(*mGrid, *other.mGrid);
583 } else {
584 mGrid->topologyUnion(*other.mGrid);
585 }
586 } else {
587 tools::csgUnion(*mGrid, *other.mGrid, /*prune=*/true);
588 }
589 OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
590 mMinCount += other.mMinCount;
591 mMaxCount += other.mMaxCount;
592 }
593
594 private:
595 /// Disallow assignment since some of the members are references
596 Raster& operator=(const Raster&) { return *this; }
597
598 /// @return true if the particle is too small or too large
599 bool ignoreParticle(Real R)
600 {
601 if (R < mParent.mRmin) {// below the cutoff radius
602 ++mMinCount;
603 return true;
604 }
605 if (R > mParent.mRmax) {// above the cutoff radius
606 ++mMaxCount;
607 return true;
608 }
609 return false;
610 }
611
612 /// @brief Threaded rasterization of particles as spheres with variable radius
613 /// @param r range of indices into the list of particles
614 void rasterSpheres(const tbb::blocked_range<size_t>& r)
615 {
616 AccessorT acc = mGrid->getAccessor(); // local accessor
617 bool run = true;
618 const Real invDx = 1 / mParent.mDx;
619 AttT att;
620 Vec3R pos;
621 Real rad;
622
623 // Loop over buckets
624 for (size_t n = r.begin(), N = r.end(); n < N; ++n) {
625 // Loop over particles in bucket n.
626 typename PointPartitionerT::IndexIterator iter = mPointPartitioner->indices(n);
627 for ( ; run && iter; ++iter) {
628 const Index32& id = *iter;
629 mParticles.getPosRad(id, pos, rad);
630 const Real R = invDx * rad;// in voxel units
631 if (this->ignoreParticle(R)) continue;
632 const Vec3R P = mMap.applyInverseMap(pos);
633 this->getAtt<DisableT>(id, att);
634 run = this->makeSphere(P, R, att, acc);
635 }//end loop over particles
636 }//end loop over buckets
637 }
638
639 /// @brief Threaded rasterization of particles as spheres with a fixed radius
640 /// @param r range of indices into the list of particles
641 /// @param R radius of fixed-size spheres
642 void rasterFixedSpheres(const tbb::blocked_range<size_t>& r, Real R)
643 {
644 AccessorT acc = mGrid->getAccessor(); // local accessor
645 AttT att;
646 Vec3R pos;
647
648 // Loop over buckets
649 for (size_t n = r.begin(), N = r.end(); n < N; ++n) {
650 // Loop over particles in bucket n.
651 for (auto iter = mPointPartitioner->indices(n); iter; ++iter) {
652 const Index32& id = *iter;
653 this->getAtt<DisableT>(id, att);
654 mParticles.getPos(id, pos);
655 const Vec3R P = mMap.applyInverseMap(pos);
656 this->makeSphere(P, R, att, acc);
657 }
658 }
659 }
660
661 /// @brief Threaded rasterization of particles as spheres with velocity trails
662 /// @param r range of indices into the list of particles
663 /// @param delta inter-sphere spacing
664 void rasterTrails(const tbb::blocked_range<size_t>& r, Real delta)
665 {
666 AccessorT acc = mGrid->getAccessor(); // local accessor
667 bool run = true;
668 AttT att;
669 Vec3R pos, vel;
670 Real rad;
671 const Vec3R origin = mMap.applyInverseMap(Vec3R(0,0,0));
672 const Real Rmin = mParent.mRmin, invDx = 1 / mParent.mDx;
673
674 // Loop over buckets
675 for (size_t n = r.begin(), N = r.end(); n < N; ++n) {
676 // Loop over particles in bucket n.
677 typename PointPartitionerT::IndexIterator iter = mPointPartitioner->indices(n);
678 for ( ; run && iter; ++iter) {
679 const Index32& id = *iter;
680 mParticles.getPosRadVel(id, pos, rad, vel);
681 const Real R0 = invDx * rad;
682 if (this->ignoreParticle(R0)) continue;
683 this->getAtt<DisableT>(id, att);
684 const Vec3R P0 = mMap.applyInverseMap(pos);
685 const Vec3R V = mMap.applyInverseMap(vel) - origin; // exclude translation
686 const Real speed = V.length(), invSpeed = 1.0 / speed;
687 const Vec3R Nrml = -V * invSpeed; // inverse normalized direction
688 Vec3R P = P0; // local position of instance
689 Real R = R0, d = 0; // local radius and length of trail
690 while (run && d <= speed) {
691 run = this->makeSphere(P, R, att, acc);
692 P += 0.5 * delta * R * Nrml; // adaptive offset along inverse velocity direction
693 d = (P - P0).length(); // current length of trail
694 R = R0 - (R0 - Rmin) * d * invSpeed; // R = R0 -> mRmin(e.g. 1.5)
695 }//end loop over sphere instances
696 }//end loop over particles
697 }//end loop over buckets
698 }
699
700 void cook()
701 {
702 // parallelize over the point buckets
703 const Index32 bucketCount = Index32(mPointPartitioner->size());
704
705 if (mParent.mGrainSize>0) {
706 tbb::parallel_reduce(
707 tbb::blocked_range<size_t>(0, bucketCount, mParent.mGrainSize), *this);
708 } else {
709 (*this)(tbb::blocked_range<size_t>(0, bucketCount));
710 }
711 }
712
713 /// @brief Rasterize sphere at position P and radius R into
714 /// a narrow-band level set with half-width, mHalfWidth.
715 /// @return @c false if rasterization was interrupted
716 ///
717 /// @param P coordinates of the particle position in voxel units
718 /// @param R radius of particle in voxel units
719 /// @param att an optional user-defined attribute value to be associated with voxels
720 /// @param acc grid accessor with a private copy of the grid
721 ///
722 /// @note For best performance all computations are performed in voxel space,
723 /// with the important exception of the final level set value that is converted
724 /// to world units (the grid stores the closest Euclidean signed distances
725 /// measured in world units). Also note we use the convention of positive distances
726 /// outside the surface and negative distances inside the surface.
727 template <bool IsMaskT = OutputIsMask>
728 typename std::enable_if<!IsMaskT, bool>::type
729 makeSphere(const Vec3R& P, Real R, const AttT& att, AccessorT& acc)
730 {
731 const Real
732 dx = mParent.mDx,
733 w = mParent.mHalfWidth,
734 max = R + w, // maximum distance in voxel units
735 max2 = math::Pow2(max), // square of maximum distance in voxel units
736 min2 = math::Pow2(math::Max(Real(0), R - w)); // square of minimum distance
737 // Bounding box of the sphere
738 const Coord
739 lo(math::Floor(P[0]-max),math::Floor(P[1]-max),math::Floor(P[2]-max)),
740 hi(math::Ceil( P[0]+max),math::Ceil( P[1]+max),math::Ceil( P[2]+max));
741 const ValueT inside = -mGrid->background();
742
743 ValueT v;
744 size_t count = 0;
745 for (Coord c = lo; c.x() <= hi.x(); ++c.x()) {
746 //only check interrupter every 32'th scan in x
747 if (!(count++ & ((1<<5)-1)) && util::wasInterrupted(mParent.mInterrupter)) {
748 thread::cancelGroupExecution();
749 return false;
750 }
751 const Real x2 = math::Pow2(c.x() - P[0]);
752 for (c.y() = lo.y(); c.y() <= hi.y(); ++c.y()) {
753 const Real x2y2 = x2 + math::Pow2(c.y() - P[1]);
754 for (c.z() = lo.z(); c.z() <= hi.z(); ++c.z()) {
755 const Real x2y2z2 = x2y2 + math::Pow2(c.z()-P[2]); // squared dist from c to P
756#if defined __INTEL_COMPILER
757 _Pragma("warning (push)")
758 _Pragma("warning (disable:186)") // "pointless comparison of unsigned integer with zero"
759#endif
760 if (x2y2z2 >= max2 || (!acc.probeValue(c, v) && (v < ValueT(0))))
761 continue;//outside narrow band of the particle or inside existing level set
762#if defined __INTEL_COMPILER
763 _Pragma("warning (pop)")
764#endif
765 if (x2y2z2 <= min2) {//inside narrow band of the particle.
766 acc.setValueOff(c, inside);
767 continue;
768 }
769 // convert signed distance from voxel units to world units
770 //const ValueT d=dx*(math::Sqrt(x2y2z2) - R);
771 const ValueT d = Merge(static_cast<SdfT>(dx*(math::Sqrt(x2y2z2)-R)), att);
772 if (d < v) acc.setValue(c, d);//CSG union
773 }//end loop over z
774 }//end loop over y
775 }//end loop over x
776 return true;
777 }
778
779 /// @brief Rasterize a sphere of radius @a r at position @a p into a boolean mask grid.
780 /// @return @c false if rasterization was interrupted
781 template <bool IsMaskT = OutputIsMask>
782 typename std::enable_if<IsMaskT, bool>::type
783 makeSphere(const Vec3R& p, Real r, const AttT& att, AccessorT& acc)
784 {
785 const Real
786 rSquared = r * r, // sphere radius squared, in voxel units
787 inW = r / math::Sqrt(6.0); // half the width in voxel units of an inscribed cube
788 const Coord
789 // Bounding box of the sphere
790 outLo(math::Floor(p[0] - r), math::Floor(p[1] - r), math::Floor(p[2] - r)),
791 outHi(math::Ceil(p[0] + r), math::Ceil(p[1] + r), math::Ceil(p[2] + r)),
792 // Bounds of the inscribed cube
793 inLo(math::Ceil(p[0] - inW), math::Ceil(p[1] - inW), math::Ceil(p[2] - inW)),
794 inHi(math::Floor(p[0] + inW), math::Floor(p[1] + inW), math::Floor(p[2] + inW));
795 // Bounding boxes of regions comprising out - in
796 /// @todo These could be divided further into sparsely- and densely-filled subregions.
797 const std::vector<CoordBBox> padding{
798 CoordBBox(outLo.x(), outLo.y(), outLo.z(), inLo.x()-1, outHi.y(), outHi.z()),
799 CoordBBox(inHi.x()+1, outLo.y(), outLo.z(), outHi.x(), outHi.y(), outHi.z()),
800 CoordBBox(outLo.x(), outLo.y(), outLo.z(), outHi.x(), inLo.y()-1, outHi.z()),
801 CoordBBox(outLo.x(), inHi.y()+1, outLo.z(), outHi.x(), outHi.y(), outHi.z()),
802 CoordBBox(outLo.x(), outLo.y(), outLo.z(), outHi.x(), outHi.y(), inLo.z()-1),
803 CoordBBox(outLo.x(), outLo.y(), inHi.z()+1, outHi.x(), outHi.y(), outHi.z()),
804 };
805 const ValueT onValue = Merge(SdfT(1), att);
806
807 // Sparsely fill the inscribed cube.
808 /// @todo Use sparse fill only if 2r > leaf width?
809 acc.tree().sparseFill(CoordBBox(inLo, inHi), onValue);
810
811 // Densely fill the remaining regions.
812 for (const auto& bbox: padding) {
813 if (util::wasInterrupted(mParent.mInterrupter)) {
814 thread::cancelGroupExecution();
815 return false;
816 }
817 const Coord &bmin = bbox.min(), &bmax = bbox.max();
818 Coord c;
819 Real cx, cy, cz;
820 for (c = bmin, cx = c.x(); c.x() <= bmax.x(); ++c.x(), cx += 1) {
821 const Real x2 = math::Pow2(cx - p[0]);
822 for (c.y() = bmin.y(), cy = c.y(); c.y() <= bmax.y(); ++c.y(), cy += 1) {
823 const Real x2y2 = x2 + math::Pow2(cy - p[1]);
824 for (c.z() = bmin.z(), cz = c.z(); c.z() <= bmax.z(); ++c.z(), cz += 1) {
825 const Real x2y2z2 = x2y2 + math::Pow2(cz - p[2]);
826 if (x2y2z2 < rSquared) {
827 acc.setValue(c, onValue);
828 }
829 }
830 }
831 }
832 }
833 return true;
834 }
835
836 using FuncType = typename std::function<void (Raster*, const tbb::blocked_range<size_t>&)>;
837
838 template<typename DisableType>
839 typename std::enable_if<DisableType::value>::type
840 getAtt(size_t, AttT&) const {}
841
842 template<typename DisableType>
843 typename std::enable_if<!DisableType::value>::type
844 getAtt(size_t n, AttT& a) const { mParticles.getAtt(n, a); }
845
846 template<typename T>
847 typename std::enable_if<std::is_same<T, ValueT>::value, ValueT>::type
848 Merge(T s, const AttT&) const { return s; }
849
850 template<typename T>
851 typename std::enable_if<!std::is_same<T, ValueT>::value, ValueT>::type
852 Merge(T s, const AttT& a) const { return ValueT(s,a); }
853
854 ParticlesToLevelSetT& mParent;
855 const ParticleListT& mParticles;//list of particles
856 GridT* mGrid;
857 const math::MapBase& mMap;
858 size_t mMinCount, mMaxCount;//counters for ignored particles!
859 FuncType mTask;
860 const bool mIsCopy;
861 PointPartitionerT* mPointPartitioner;
862}; // struct ParticlesToLevelSet::Raster
863
864
865///////////////////// YOU CAN SAFELY IGNORE THIS SECTION /////////////////////
866
867/// @cond OPENVDB_DOCS_INTERNAL
868
869 namespace p2ls_internal {
870
871// This is a simple type that combines a distance value and a particle
872// attribute. It's required for attribute transfer which is defined in the
873// Raster class above.
874/// @private
875 template<typename VisibleT, typename BlindT>
876 class BlindData
877{
878 public:
879 using type = VisibleT;
880 using VisibleType = VisibleT;
881 using BlindType = BlindT;
882
883 BlindData() {}
884 explicit BlindData(VisibleT v) : mVisible(v), mBlind(zeroVal<BlindType>()) {}
885 BlindData(VisibleT v, BlindT b) : mVisible(v), mBlind(b) {}
886 BlindData(const BlindData&) = default;
887 BlindData& operator=(const BlindData&) = default;
888 const VisibleT& visible() const { return mVisible; }
889 const BlindT& blind() const { return mBlind; }
890 OPENVDB_NO_FP_EQUALITY_WARNING_BEGIN
891 bool operator==(const BlindData& rhs) const { return mVisible == rhs.mVisible; }
892 OPENVDB_NO_FP_EQUALITY_WARNING_END
893 bool operator< (const BlindData& rhs) const { return mVisible < rhs.mVisible; }
894 bool operator> (const BlindData& rhs) const { return mVisible > rhs.mVisible; }
895 BlindData operator+(const BlindData& rhs) const { return BlindData(mVisible + rhs.mVisible); }
896 BlindData operator-(const BlindData& rhs) const { return BlindData(mVisible - rhs.mVisible); }
897 BlindData operator-() const { return BlindData(-mVisible, mBlind); }
898
899 protected:
900 VisibleT mVisible;
901 BlindT mBlind;
902};
903
904/// @private
905// Required by several of the tree nodes
906 template<typename VisibleT, typename BlindT>
907 inline std::ostream& operator<<(std::ostream& ostr, const BlindData<VisibleT, BlindT>& rhs)
908{
909 ostr << rhs.visible();
910 return ostr;
911}
912
913/// @private
914// Required by math::Abs
915 template<typename VisibleT, typename BlindT>
916 inline BlindData<VisibleT, BlindT> Abs(const BlindData<VisibleT, BlindT>& x)
917{
918 return BlindData<VisibleT, BlindT>(math::Abs(x.visible()), x.blind());
919}
920
921/// @private
922// Required to support the (zeroVal<BlindData>() + val) idiom.
923 template<typename VisibleT, typename BlindT, typename T>
924 inline BlindData<VisibleT, BlindT>
925 operator+(const BlindData<VisibleT, BlindT>& x, const T& rhs)
926{
927 return BlindData<VisibleT, BlindT>(x.visible() + static_cast<VisibleT>(rhs), x.blind());
928}
929
930} // namespace p2ls_internal
931
932/// @endcond
933
934//////////////////////////////////////////////////////////////////////////////
935
936
937// The following are convenience functions for common use cases.
938
939 template<typename GridT, typename ParticleListT, typename InterrupterT>
940 inline void
941 particlesToSdf(const ParticleListT& plist, GridT& grid, InterrupterT* interrupt)
942{
943 static_assert(std::is_floating_point<typename GridT::ValueType>::value,
944 "particlesToSdf requires an SDF grid with floating-point values");
945
946 if (grid.getGridClass() != GRID_LEVEL_SET) {
947 OPENVDB_LOG_WARN("particlesToSdf requires a level set grid;"
948 " try Grid::setGridClass(openvdb::GRID_LEVEL_SET)");
949 }
950
951 ParticlesToLevelSet<GridT> p2ls(grid, interrupt);
952 p2ls.rasterizeSpheres(plist);
953 tools::pruneLevelSet(grid.tree());
954}
955
956 template<typename GridT, typename ParticleListT, typename InterrupterT>
957 inline void
958 particlesToSdf(const ParticleListT& plist, GridT& grid, Real radius, InterrupterT* interrupt)
959{
960 static_assert(std::is_floating_point<typename GridT::ValueType>::value,
961 "particlesToSdf requires an SDF grid with floating-point values");
962
963 if (grid.getGridClass() != GRID_LEVEL_SET) {
964 OPENVDB_LOG_WARN("particlesToSdf requires a level set grid;"
965 " try Grid::setGridClass(openvdb::GRID_LEVEL_SET)");
966 }
967
968 ParticlesToLevelSet<GridT> p2ls(grid, interrupt);
969 p2ls.rasterizeSpheres(plist, radius);
970 tools::pruneLevelSet(grid.tree());
971}
972
973 template<typename GridT, typename ParticleListT, typename InterrupterT>
974 inline void
975 particleTrailsToSdf(const ParticleListT& plist, GridT& grid, Real delta, InterrupterT* interrupt)
976{
977 static_assert(std::is_floating_point<typename GridT::ValueType>::value,
978 "particleTrailsToSdf requires an SDF grid with floating-point values");
979
980 if (grid.getGridClass() != GRID_LEVEL_SET) {
981 OPENVDB_LOG_WARN("particlesToSdf requires a level set grid;"
982 " try Grid::setGridClass(openvdb::GRID_LEVEL_SET)");
983 }
984
985 ParticlesToLevelSet<GridT> p2ls(grid, interrupt);
986 p2ls.rasterizeTrails(plist, delta);
987 tools::pruneLevelSet(grid.tree());
988}
989
990 template<typename GridT, typename ParticleListT, typename InterrupterT>
991 inline void
992 particlesToMask(const ParticleListT& plist, GridT& grid, InterrupterT* interrupt)
993{
994 static_assert(std::is_same<bool, typename GridT::ValueType>::value,
995 "particlesToMask requires a boolean-valued grid");
996 ParticlesToLevelSet<GridT> p2ls(grid, interrupt);
997 p2ls.rasterizeSpheres(plist);
998 tools::prune(grid.tree());
999}
1000
1001 template<typename GridT, typename ParticleListT, typename InterrupterT>
1002 inline void
1003 particlesToMask(const ParticleListT& plist, GridT& grid, Real radius, InterrupterT* interrupt)
1004{
1005 static_assert(std::is_same<bool, typename GridT::ValueType>::value,
1006 "particlesToMask requires a boolean-valued grid");
1007 ParticlesToLevelSet<GridT> p2ls(grid, interrupt);
1008 p2ls.rasterizeSpheres(plist, radius);
1009 tools::prune(grid.tree());
1010}
1011
1012 template<typename GridT, typename ParticleListT, typename InterrupterT>
1013 inline void
1014 particleTrailsToMask(const ParticleListT& plist, GridT& grid, Real delta, InterrupterT* interrupt)
1015{
1016 static_assert(std::is_same<bool, typename GridT::ValueType>::value,
1017 "particleTrailsToMask requires a boolean-valued grid");
1018 ParticlesToLevelSet<GridT> p2ls(grid, interrupt);
1019 p2ls.rasterizeTrails(plist, delta);
1020 tools::prune(grid.tree());
1021}
1022
1023} // namespace tools
1024} // namespace OPENVDB_VERSION_NAME
1025} // namespace openvdb
1026
1027#endif // OPENVDB_TOOLS_PARTICLES_TO_LEVELSET_HAS_BEEN_INCLUDED
Assert.h
OPENVDB_ASSERT
#define OPENVDB_ASSERT(X)
Definition Assert.h:41
Composite.h
Functions to efficiently perform various compositing operations on grids.
Grid.h
operator<<
OPENVDB_API std::ostream & operator<<(std::ostream &os, half h)
Output h to os, formatted as a float.
LeafManager.h
A LeafManager manages a linear array of pointers to a given tree's leaf nodes, as well as optional au...
Math.h
General-purpose arithmetic and comparison routines, most of which accept arbitrary value types (or at...
OPENVDB_NO_FP_EQUALITY_WARNING_END
#define OPENVDB_NO_FP_EQUALITY_WARNING_END
Definition Math.h:49
OPENVDB_NO_FP_EQUALITY_WARNING_BEGIN
#define OPENVDB_NO_FP_EQUALITY_WARNING_BEGIN
Definition Math.h:48
NullInterrupter.h
OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
#define OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
Definition Platform.h:164
OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
#define OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
Definition Platform.h:163
PointPartitioner.h
Spatially partitions points using a parallel radix-based sorting algorithm.
Prune.h
Defined various multi-threaded utility functions for trees.
SignedFloodFill.h
Propagate the signs of distance values from the active voxels in the narrow band to the inactive valu...
Transform.h
openvdb::v12_1::ShallowCopy
Tag dispatch class that distinguishes shallow copy constructors from deep copy constructors.
Definition Types.h:751
openvdb::v12_1::TopologyCopy
Tag dispatch class that distinguishes topology copy constructors from deep copy constructors.
Definition Types.h:754
openvdb::v12_1::math::Coord
Signed (x, y, z) 32-bit integer coordinates.
Definition Coord.h:26
openvdb::v12_1::math::Vec3::length
T length() const
Length of the vector.
Definition Vec3.h:201
openvdb::v12_1::tools::ParticlesToLevelSet
Definition ParticlesToLevelSet.h:161
openvdb::v12_1::tools::ParticlesToLevelSet::InterrupterType
InterrupterT InterrupterType
Definition ParticlesToLevelSet.h:164
openvdb::v12_1::tools::ParticlesToLevelSet::rasterizeTrails
void rasterizeTrails(const ParticleListT &pa, Real delta=1.0)
Rasterize each particle as a trail comprising the CSG union of spheres of decreasing radius.
Definition ParticlesToLevelSet.h:346
openvdb::v12_1::tools::ParticlesToLevelSet::setRmax
void setRmax(Real Rmax)
Set the largest radius allowed in voxel units.
Definition ParticlesToLevelSet.h:225
openvdb::v12_1::tools::ParticlesToLevelSet::ParticlesToLevelSet
ParticlesToLevelSet(SdfGridT &grid, InterrupterT *interrupt=nullptr)
Constructor using an existing boolean or narrow-band level set grid.
Definition ParticlesToLevelSet.h:294
openvdb::v12_1::tools::ParticlesToLevelSet::getRmin
Real getRmin() const
Return the smallest radius allowed in voxel units.
Definition ParticlesToLevelSet.h:218
openvdb::v12_1::tools::ParticlesToLevelSet::finalize
void finalize(bool prune=false)
This method syncs up the level set and attribute grids and therefore needs to be called before any of...
Definition ParticlesToLevelSet.h:360
openvdb::v12_1::tools::ParticlesToLevelSet::rasterizeSpheres
void rasterizeSpheres(const ParticleListT &pa, Real radius)
Rasterize each particle as a sphere with the particle's position and a fixed radius.
Definition ParticlesToLevelSet.h:332
openvdb::v12_1::tools::ParticlesToLevelSet::setGrainSize
void setGrainSize(int grainSize)
Set the grain size used for threading.
Definition ParticlesToLevelSet.h:240
openvdb::v12_1::tools::ParticlesToLevelSet::getRmax
Real getRmax() const
Return the largest radius allowed in voxel units.
Definition ParticlesToLevelSet.h:223
openvdb::v12_1::tools::ParticlesToLevelSet::getVoxelSize
Real getVoxelSize() const
Return the size of a voxel in world units.
Definition ParticlesToLevelSet.h:212
openvdb::v12_1::tools::ParticlesToLevelSet::~ParticlesToLevelSet
~ParticlesToLevelSet()
Definition ParticlesToLevelSet.h:194
openvdb::v12_1::tools::ParticlesToLevelSet::getHalfWidth
Real getHalfWidth() const
Return the half-width of the narrow band in voxel units.
Definition ParticlesToLevelSet.h:215
openvdb::v12_1::tools::ParticlesToLevelSet::getMinCount
size_t getMinCount() const
Return the number of particles that were ignored because they were smaller than the minimum radius.
Definition ParticlesToLevelSet.h:231
openvdb::v12_1::tools::ParticlesToLevelSet::SdfType
typename SdfGridT::ValueType SdfType
Definition ParticlesToLevelSet.h:167
openvdb::v12_1::tools::ParticlesToLevelSet::rasterizeSpheres
void rasterizeSpheres(const ParticleListT &pa)
Rasterize each particle as a sphere with the particle's position and radius.
Definition ParticlesToLevelSet.h:318
openvdb::v12_1::tools::ParticlesToLevelSet::getGrainSize
int getGrainSize() const
Return the grain size used for threading.
Definition ParticlesToLevelSet.h:237
openvdb::v12_1::tools::ParticlesToLevelSet::attributeGrid
AttGridType::Ptr attributeGrid()
Return a pointer to the grid containing the optional user-defined attribute.
Definition ParticlesToLevelSet.h:209
openvdb::v12_1::tools::ParticlesToLevelSet::ignoredParticles
bool ignoredParticles() const
Return true if any particles were ignored due to their size.
Definition ParticlesToLevelSet.h:228
openvdb::v12_1::tools::ParticlesToLevelSet::DisableT
typename std::is_void< AttributeT >::type DisableT
Definition ParticlesToLevelSet.h:163
openvdb::v12_1::tools::ParticlesToLevelSet< SdfGridT, AttributeT, InterrupterT >::OutputIsMask
static const bool OutputIsMask
Definition ParticlesToLevelSet.h:172
openvdb::v12_1::tools::ParticlesToLevelSet::AttType
typename std::conditional< DisableT::value, size_t, AttributeT >::type AttType
Definition ParticlesToLevelSet.h:169
openvdb::v12_1::tools::ParticlesToLevelSet::AttGridType
typename SdfGridT::template ValueConverter< AttType >::Type AttGridType
Definition ParticlesToLevelSet.h:170
openvdb::v12_1::tools::ParticlesToLevelSet::setRmin
void setRmin(Real Rmin)
Set the smallest radius allowed in voxel units.
Definition ParticlesToLevelSet.h:220
openvdb::v12_1::tools::ParticlesToLevelSet::getMaxCount
size_t getMaxCount() const
Return the number of particles that were ignored because they were larger than the maximum radius.
Definition ParticlesToLevelSet.h:234
openvdb::v12_1::tools::ParticlesToLevelSet::SdfGridType
SdfGridT SdfGridType
Definition ParticlesToLevelSet.h:166
openvdb::v12_1::tools::PointPartitioner
Definition PointPartitioner.h:78
openvdb::v12_1::tree::LeafManager
This class manages a linear array of pointers to a given tree's leaf nodes, as well as optional auxil...
Definition LeafManager.h:86
openvdb::v12_1::tree::LeafManager::foreach
void foreach(const LeafOp &op, bool threaded=true, size_t grainSize=1)
Threaded method that applies a user-supplied functor to each leaf node in the LeafManager.
Definition LeafManager.h:484
logging.h
OPENVDB_LOG_WARN
#define OPENVDB_LOG_WARN(message)
Log a warning message of the form 'someVar << "some text" << ...'.
Definition logging.h:256
openvdb::v12_1::ax::run
OPENVDB_AX_API void run(const char *ax, openvdb::GridBase &grid, const AttributeBindings &bindings={})
Run a full AX pipeline (parse, compile and execute) on a single OpenVDB Grid.
openvdb::v12_1::math::operator==
bool operator==(const Vec3< T0 > &v0, const Vec3< T1 > &v1)
Equality operator, does exact floating point comparisons.
Definition Vec3.h:474
openvdb::v12_1::math::Ceil
int Ceil(float x)
Return the ceiling of x.
Definition Math.h:856
openvdb::v12_1::math::Sqrt
float Sqrt(float x)
Return the square root of a floating-point value.
Definition Math.h:761
openvdb::v12_1::math::Max
const Type & Max(const Type &a, const Type &b)
Return the maximum of two values.
Definition Math.h:595
openvdb::v12_1::math::operator-
Vec3< typename promote< T, Coord::ValueType >::type > operator-(const Vec3< T > &v0, const Coord &v1)
Allow a Coord to be subtracted from a Vec3.
Definition Coord.h:554
openvdb::v12_1::math::operator+
Vec3< typename promote< T, typename Coord::ValueType >::type > operator+(const Vec3< T > &v0, const Coord &v1)
Allow a Coord to be added to or subtracted from a Vec3.
Definition Coord.h:528
openvdb::v12_1::math::Abs
Coord Abs(const Coord &xyz)
Definition Coord.h:518
openvdb::v12_1::math::Pow2
Type Pow2(Type x)
Return x2.
Definition Math.h:548
openvdb::v12_1::math::Floor
int Floor(float x)
Return the floor of x.
Definition Math.h:848
openvdb::v12_1::tools::composite::max
const std::enable_if<!VecTraits< T >::IsVec, T >::type & max(const T &a, const T &b)
Definition Composite.h:110
openvdb::v12_1::tools::pruneLevelSet
void pruneLevelSet(TreeT &tree, bool threaded=true, size_t grainSize=1)
Reduce the memory footprint of a tree by replacing nodes whose values are all inactive with inactive ...
Definition Prune.h:390
openvdb::v12_1::tools::if
if(shared)
Definition ValueTransformer.h:596
openvdb::v12_1::tools::prune
void prune(TreeT &tree, typename TreeT::ValueType tolerance=zeroVal< typename TreeT::ValueType >(), bool threaded=true, size_t grainSize=1)
Reduce the memory footprint of a tree by replacing with tiles any nodes whose values are all the same...
Definition Prune.h:335
openvdb::v12_1::tools::particlesToMask
void particlesToMask(const ParticleListT &, GridT &, InterrupterT *=nullptr)
Activate a boolean grid wherever it intersects the spheres described by the given particle positions ...
Definition ParticlesToLevelSet.h:992
openvdb::v12_1::tools::compMax
void compMax(GridOrTreeT &a, GridOrTreeT &b)
Given grids A and B, compute max(a, b) per voxel (using sparse traversal). Store the result in the A ...
Definition Composite.h:748
openvdb::v12_1::tools::signedFloodFill
void signedFloodFill(TreeOrLeafManagerT &tree, bool threaded=true, size_t grainSize=1, Index minLevel=0)
Set the values of all inactive voxels and tiles of a narrow-band level set from the signs of the acti...
Definition SignedFloodFill.h:267
openvdb::v12_1::tools::particleTrailsToSdf
void particleTrailsToSdf(const ParticleListT &, GridT &, Real delta=1, InterrupterT *=nullptr)
Populate a scalar, floating-point grid with CSG-unioned trails of level set spheres with decreasing r...
Definition ParticlesToLevelSet.h:975
openvdb::v12_1::tools::particlesToSdf
void particlesToSdf(const ParticleListT &, GridT &, InterrupterT *=nullptr)
Populate a scalar, floating-point grid with CSG-unioned level set spheres described by the given part...
Definition ParticlesToLevelSet.h:941
openvdb::v12_1::tools::csgUnion
void csgUnion(GridOrTreeT &a, GridOrTreeT &b, bool prune=true, bool pruneCancelledTiles=false)
Given two level set grids, replace the A grid with the union of A and B.
Definition Composite.h:886
openvdb::v12_1::tools::particleTrailsToMask
void particleTrailsToMask(const ParticleListT &, GridT &, Real delta=1, InterrupterT *=nullptr)
Activate a boolean grid wherever it intersects trails of spheres with decreasing radius,...
Definition ParticlesToLevelSet.h:1014
openvdb::v12_1::util::wasInterrupted
bool wasInterrupted(T *i, int percent=-1)
Definition NullInterrupter.h:49
openvdb::v12_1::Index
Index32 Index
Definition Types.h:54
openvdb::v12_1::Real
double Real
Definition Types.h:60
openvdb::v12_1::GRID_LEVEL_SET
@ GRID_LEVEL_SET
Definition Types.h:526
openvdb::v12_1::zeroVal
constexpr T zeroVal()
Return the value of type T that corresponds to zero.
Definition Math.h:70
openvdb::v12_1::Index32
uint32_t Index32
Definition Types.h:52
openvdb::v12_1::Vec3R
math::Vec3< Real > Vec3R
Definition Types.h:72
openvdb
Definition Exceptions.h:13
Types.h
OPENVDB_VERSION_NAME
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition version.h.in:121
OPENVDB_USE_VERSION_NAMESPACE
#define OPENVDB_USE_VERSION_NAMESPACE
Definition version.h.in:218