41 #ifndef OPENVDB_POINTS_POINT_SCATTER_HAS_BEEN_INCLUDED 42 #define OPENVDB_POINTS_POINT_SCATTER_HAS_BEEN_INCLUDED 44 #include <type_traits> 49 #include <openvdb/openvdb.h> 50 #include <openvdb/Types.h> 51 #include <openvdb/tree/LeafManager.h> 52 #include <openvdb/tools/Prune.h> 53 #include <openvdb/util/NullInterrupter.h> 59 #include <tbb/parallel_sort.h> 60 #include <tbb/parallel_for.h> 100 typename RandGenT = std::mt19937,
101 typename PositionArrayT = TypedAttributeArray<Vec3f, NullCodec>,
102 typename PointDataGridT = Grid<
103 typename points::TreeConverter<typename GridT::TreeType>::Type>,
104 typename InterrupterT = util::NullInterrupter>
105 inline typename PointDataGridT::Ptr
108 const unsigned int seed = 0,
109 const float spread = 1.0f,
110 InterrupterT* interrupter =
nullptr);
129 typename RandGenT = std::mt19937,
130 typename PositionArrayT = TypedAttributeArray<Vec3f, NullCodec>,
131 typename PointDataGridT = Grid<
132 typename points::TreeConverter<typename GridT::TreeType>::Type>,
133 typename InterrupterT = util::NullInterrupter>
134 inline typename PointDataGridT::Ptr
136 const float pointsPerVoxel,
137 const unsigned int seed = 0,
138 const float spread = 1.0f,
139 InterrupterT* interrupter =
nullptr);
161 typename RandGenT = std::mt19937,
162 typename PositionArrayT = TypedAttributeArray<Vec3f, NullCodec>,
163 typename PointDataGridT = Grid<
164 typename points::TreeConverter<typename GridT::TreeType>::Type>,
165 typename InterrupterT = util::NullInterrupter>
166 inline typename PointDataGridT::Ptr
168 const float pointsPerVoxel,
169 const unsigned int seed = 0,
170 const float spread = 1.0f,
171 InterrupterT* interrupter =
nullptr);
177 namespace point_scatter_internal
183 template<
typename Po
intDataGr
idT,
typename Gr
idT>
184 inline typename PointDataGridT::Ptr
187 typename PointDataGridT::Ptr points(
new PointDataGridT);
188 points->setTransform(grid.transform().copy());
189 points->topologyUnion(grid);
190 if (points->tree().hasActiveTiles()) {
191 points->tree().voxelizeActiveTiles();
204 template<
typename PositionType,
210 const AttributeSet::Descriptor::Ptr& descriptor,
216 using ValueType =
typename PositionTraits::ElementType;
219 leaf.initializeAttributes(descriptor, static_cast<Index>(count));
223 auto& array = leaf.attributeArray(0);
226 PositionWriteHandle pHandle(array,
false);
228 for (
Index64 index = 0; index < count; ++index) {
229 P[0] = (spread * (rand01() - ValueType(0.5)));
230 P[1] = (spread * (rand01() - ValueType(0.5)));
231 P[2] = (spread * (rand01() - ValueType(0.5)));
232 pHandle.set(static_cast<Index>(index), P);
245 typename PositionArrayT,
246 typename PointDataGridT,
247 typename InterrupterT>
248 inline typename PointDataGridT::Ptr
251 const unsigned int seed,
253 InterrupterT* interrupter)
255 using PositionType =
typename PositionArrayT::ValueType;
257 using ValueType =
typename PositionTraits::ElementType;
258 using CodecType =
typename PositionArrayT::Codec;
262 using TreeType =
typename PointDataGridT::TreeType;
263 using LeafNodeType =
typename TreeType::LeafNodeType;
271 static void getPrefixSum(LeafManagerT& leafManager,
272 std::vector<Index64>& offsets)
275 offsets.reserve(leafManager.leafCount() + 1);
276 offsets.push_back(0);
277 const auto leafRange = leafManager.
leafRange();
278 for (
auto leaf = leafRange.begin(); leaf; ++leaf) {
279 offset += leaf->onVoxelCount();
280 offsets.push_back(offset);
285 static_assert(PositionTraits::IsVec && PositionTraits::Size == 3,
286 "Invalid Position Array type.");
288 if (spread < 0.0f || spread > 1.0f) {
292 if (interrupter) interrupter->start(
"Uniform scattering with fixed point count");
294 typename PointDataGridT::Ptr points =
295 point_scatter_internal::initialisePointTopology<PointDataGridT>(grid);
296 TreeType& tree = points->tree();
297 if (!tree.cbeginLeaf())
return points;
299 LeafManagerT leafManager(tree);
300 const Index64 voxelCount = leafManager.activeLeafVoxelCount();
301 assert(voxelCount != 0);
303 const double pointsPerVolume = double(count) / double(voxelCount);
305 const Index64 remainder = count - (pointsPerVoxel * voxelCount);
307 if (remainder == 0) {
309 GridT, RandGenT, PositionArrayT, PointDataGridT, InterrupterT>(
310 grid, float(pointsPerVoxel), seed, spread, interrupter);
313 std::vector<Index64> voxelOffsets, values;
314 std::thread worker(&Local::getPrefixSum, std::ref(leafManager), std::ref(voxelOffsets));
318 values.reserve(remainder);
319 for (
Index64 i = 0; i < remainder; ++i) values.emplace_back(gen());
324 if (util::wasInterrupted<InterrupterT>(interrupter)) {
329 tbb::parallel_sort(values.begin(), values.end());
330 const bool fractionalOnly(pointsPerVoxel == 0);
332 leafManager.foreach([&voxelOffsets, &values, fractionalOnly]
333 (LeafNodeType& leaf,
const size_t idx)
335 const Index64 lowerOffset = voxelOffsets[idx];
336 const Index64 upperOffset = voxelOffsets[idx + 1];
337 assert(upperOffset > lowerOffset);
339 const auto valuesEnd = values.end();
340 auto lower = std::lower_bound(values.begin(), valuesEnd, lowerOffset);
342 auto*
const data = leaf.buffer().data();
343 auto iter = leaf.beginValueOn();
346 bool addedPoints(!fractionalOnly);
347 while (lower != valuesEnd) {
349 if (vId >= upperOffset)
break;
352 iter.increment(nextOffset - currentOffset);
353 currentOffset = nextOffset;
356 auto& value = data[iter.pos()];
364 if (!addedPoints) leaf.setValuesOff();
367 voxelOffsets.clear();
370 if (fractionalOnly) {
372 leafManager.rebuild();
375 const AttributeSet::Descriptor::Ptr descriptor =
376 AttributeSet::Descriptor::create(PositionArrayT::attributeType());
377 RandomGenerator rand01(seed);
379 const auto leafRange = leafManager.leafRange();
380 auto leaf = leafRange.begin();
381 for (; leaf; ++leaf) {
382 if (util::wasInterrupted<InterrupterT>(interrupter))
break;
384 for (
auto iter = leaf->beginValueAll(); iter; ++iter) {
385 if (iter.isValueOn()) {
387 if (value == 0) leaf->setValueOff(iter.pos());
388 else offset += value;
391 leaf->setOffsetOnly(iter.pos(), offset);
396 point_scatter_internal::generatePositions<PositionType, CodecType>
397 (*leaf, descriptor, offset, spread, rand01);
402 for (; leaf; ++leaf) leaf->setValuesOff();
406 if (interrupter) interrupter->end();
417 typename PositionArrayT,
418 typename PointDataGridT,
419 typename InterrupterT>
420 inline typename PointDataGridT::Ptr
422 const float pointsPerVoxel,
423 const unsigned int seed,
425 InterrupterT* interrupter)
427 using PositionType =
typename PositionArrayT::ValueType;
429 using ValueType =
typename PositionTraits::ElementType;
430 using CodecType =
typename PositionArrayT::Codec;
434 using TreeType =
typename PointDataGridT::TreeType;
436 static_assert(PositionTraits::IsVec && PositionTraits::Size == 3,
437 "Invalid Position Array type.");
439 if (pointsPerVoxel < 0.0f) {
443 if (spread < 0.0f || spread > 1.0f) {
447 if (interrupter) interrupter->start(
"Dense uniform scattering with fixed point count");
449 typename PointDataGridT::Ptr points =
450 point_scatter_internal::initialisePointTopology<PointDataGridT>(grid);
451 TreeType& tree = points->tree();
452 auto leafIter = tree.beginLeaf();
453 if (!leafIter)
return points;
456 const double delta = pointsPerVoxel - float(pointsPerVoxelInt);
458 const bool fractionalOnly = pointsPerVoxelInt == 0;
460 const AttributeSet::Descriptor::Ptr descriptor =
461 AttributeSet::Descriptor::create(PositionArrayT::attributeType());
462 RandomGenerator rand01(seed);
464 for (; leafIter; ++leafIter) {
465 if (util::wasInterrupted<InterrupterT>(interrupter))
break;
467 for (
auto iter = leafIter->beginValueAll(); iter; ++iter) {
468 if (iter.isValueOn()) {
469 offset += pointsPerVoxelInt;
470 if (fractional && rand01() < delta) ++offset;
471 else if (fractionalOnly) leafIter->setValueOff(iter.pos());
474 leafIter->setOffsetOnly(iter.pos(), offset);
478 point_scatter_internal::generatePositions<PositionType, CodecType>
479 (*leafIter, descriptor, offset, spread, rand01);
484 const bool prune(leafIter || fractionalOnly);
485 for (; leafIter; ++leafIter) leafIter->setValuesOff();
488 if (interrupter) interrupter->end();
499 typename PositionArrayT,
500 typename PointDataGridT,
501 typename InterrupterT>
502 inline typename PointDataGridT::Ptr
504 const float pointsPerVoxel,
505 const unsigned int seed,
507 InterrupterT* interrupter)
509 using PositionType =
typename PositionArrayT::ValueType;
511 using ValueType =
typename PositionTraits::ElementType;
512 using CodecType =
typename PositionArrayT::Codec;
516 using TreeType =
typename PointDataGridT::TreeType;
518 static_assert(PositionTraits::IsVec && PositionTraits::Size == 3,
519 "Invalid Position Array type.");
520 static_assert(std::is_arithmetic<typename GridT::ValueType>::value,
521 "Scalar grid type required for weighted voxel scattering.");
523 if (pointsPerVoxel < 0.0f) {
527 if (spread < 0.0f || spread > 1.0f) {
531 if (interrupter) interrupter->start(
"Non-uniform scattering with local point density");
533 typename PointDataGridT::Ptr points =
534 point_scatter_internal::initialisePointTopology<PointDataGridT>(grid);
535 TreeType& tree = points->tree();
536 auto leafIter = tree.beginLeaf();
537 if (!leafIter)
return points;
539 const AttributeSet::Descriptor::Ptr descriptor =
540 AttributeSet::Descriptor::create(PositionArrayT::attributeType());
541 RandomGenerator rand01(seed);
542 const auto accessor = grid.getConstAccessor();
544 for (; leafIter; ++leafIter) {
545 if (util::wasInterrupted<InterrupterT>(interrupter))
break;
547 for (
auto iter = leafIter->beginValueAll(); iter; ++iter) {
548 if (iter.isValueOn()) {
550 double(accessor.getValue(iter.getCoord())) * pointsPerVoxel;
551 fractional =
std::max(0.0, fractional);
552 int count = int(fractional);
553 if (rand01() < (fractional -
double(count))) ++count;
554 else if (count == 0) leafIter->setValueOff(iter.pos());
558 leafIter->setOffsetOnly(iter.pos(), offset);
562 point_scatter_internal::generatePositions<PositionType, CodecType>
563 (*leafIter, descriptor, offset, spread, rand01);
568 for (; leafIter; ++leafIter) leafIter->setValuesOff();
571 if (interrupter) interrupter->end();
581 #endif // OPENVDB_POINTS_POINT_SCATTER_HAS_BEEN_INCLUDED bool isApproxZero(const Type &x)
Return true if x is equal to zero to within the default floating-point comparison tolerance...
Definition: Math.h:320
void expand(bool fill=true)
If this array is uniform, replace it with an array of length size().
Definition: AttributeArray.h:2025
Write-able version of AttributeHandle.
Definition: AttributeArray.h:715
void generatePositions(LeafNodeT &leaf, const AttributeSet::Descriptor::Ptr &descriptor, const Index64 &count, const float spread, RandGenT &rand01)
Generate random point positions for a leaf node.
Definition: points/PointScatter.h:209
LeafRange leafRange(size_t grainsize=1) const
Return a TBB-compatible LeafRange.
Definition: LeafManager.h:386
PointDataGridT::Ptr denseUniformPointScatter(const GridT &grid, const float pointsPerVoxel, const unsigned int seed=0, const float spread=1.0f, InterrupterT *interrupter=nullptr)
Uniformly scatter a fixed number of points per active voxel. If the pointsPerVoxel value provided is ...
Definition: points/PointScatter.h:421
PointDataGridT::Ptr initialisePointTopology(const GridT &grid)
initialise the topology of a PointDataGrid and ensure everything is voxelized
Definition: points/PointScatter.h:185
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:109
Attribute Array storage templated on type and compression codec.
Methods for counting points in VDB Point grids.
float RoundDown(float x)
Return x rounded down to the nearest integer.
Definition: Math.h:757
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h:136
Simple random integer generator.
Definition: Math.h:171
Definition: Exceptions.h:92
PointDataGridT::Ptr nonUniformPointScatter(const GridT &grid, const float pointsPerVoxel, const unsigned int seed=0, const float spread=1.0f, InterrupterT *interrupter=nullptr)
Non uniformly scatter points per active voxel. The pointsPerVoxel value is used to weight each grids ...
Definition: points/PointScatter.h:503
Definition: Exceptions.h:40
Simple generator of random numbers over the range [0, 1)
Definition: Math.h:135
PointDataGridT::Ptr uniformPointScatter(const GridT &grid, const Index64 count, const unsigned int seed=0, const float spread=1.0f, InterrupterT *interrupter=nullptr)
The free functions depend on the following class:
Definition: points/PointScatter.h:249
uint64_t Index64
Definition: Types.h:60
This class manages a linear array of pointers to a given tree's leaf nodes, as well as optional auxil...
Definition: LeafManager.h:110
Attribute-owned data structure for points. Point attributes are stored in leaf nodes and ordered by v...
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:188
int Floor(float x)
Return the floor of x.
Definition: Math.h:802
uint32_t Index32
Definition: Types.h:59