HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
PointConversion.h
Go to the documentation of this file.
1 ///////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (c) 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 //
29 ///////////////////////////////////////////////////////////////////////////
30 
31 /// @author Dan Bailey, Nick Avramoussis
32 ///
33 /// @file points/PointConversion.h
34 ///
35 /// @brief Convert points and attributes to and from VDB Point Data grids.
36 
37 #ifndef OPENVDB_POINTS_POINT_CONVERSION_HAS_BEEN_INCLUDED
38 #define OPENVDB_POINTS_POINT_CONVERSION_HAS_BEEN_INCLUDED
39 
40 #include <openvdb/math/Transform.h>
41 
45 
46 #include "AttributeArrayString.h"
47 #include "AttributeSet.h"
48 #include "IndexFilter.h"
49 #include "PointAttribute.h"
50 #include "PointDataGrid.h"
51 #include "PointGroup.h"
52 
53 #include <tbb/parallel_reduce.h>
54 
55 #include <type_traits>
56 
57 namespace openvdb {
59 namespace OPENVDB_VERSION_NAME {
60 namespace points {
61 
62 
63 /// @brief Localises points with position into a @c PointDataGrid into two stages:
64 /// allocation of the leaf attribute data and population of the positions.
65 ///
66 /// @param pointIndexGrid a PointIndexGrid into the points.
67 /// @param positions list of world space point positions.
68 /// @param xform world to index space transform.
69 /// @param positionDefaultValue metadata default position value
70 ///
71 /// @note The position data must be supplied in a Point-Partitioner compatible
72 /// data structure. A convenience PointAttributeVector class is offered.
73 ///
74 /// @note The position data is populated separately to perform world space to
75 /// voxel space conversion and apply quantisation.
76 ///
77 /// @note A @c PointIndexGrid to the points must be supplied to perform this
78 /// operation. Typically this is built implicitly by the PointDataGrid constructor.
79 
80 template<
81  typename CompressionT,
82  typename PointDataGridT,
83  typename PositionArrayT,
84  typename PointIndexGridT>
85 inline typename PointDataGridT::Ptr
86 createPointDataGrid(const PointIndexGridT& pointIndexGrid,
87  const PositionArrayT& positions,
88  const math::Transform& xform,
89  Metadata::Ptr positionDefaultValue = Metadata::Ptr());
90 
91 
92 /// @brief Convenience method to create a @c PointDataGrid from a std::vector of
93 /// point positions.
94 ///
95 /// @param positions list of world space point positions.
96 /// @param xform world to index space transform.
97 /// @param positionDefaultValue metadata default position value
98 ///
99 /// @note This method implicitly wraps the std::vector for a Point-Partitioner compatible
100 /// data structure and creates the required @c PointIndexGrid to the points.
101 
102 template <typename CompressionT, typename PointDataGridT, typename ValueT>
103 inline typename PointDataGridT::Ptr
104 createPointDataGrid(const std::vector<ValueT>& positions,
105  const math::Transform& xform,
106  Metadata::Ptr positionDefaultValue = Metadata::Ptr());
107 
108 
109 /// @brief Stores point attribute data in an existing @c PointDataGrid attribute.
110 ///
111 /// @param tree the PointDataGrid to be populated.
112 /// @param pointIndexTree a PointIndexTree into the points.
113 /// @param attributeName the name of the VDB Points attribute to be populated.
114 /// @param data a wrapper to the attribute data.
115 /// @param stride the stride of the attribute
116 /// @param insertMetadata true if strings are to be automatically inserted as metadata.
117 ///
118 /// @note A @c PointIndexGrid to the points must be supplied to perform this
119 /// operation. This is required to ensure the same point index ordering.
120 template <typename PointDataTreeT, typename PointIndexTreeT, typename PointArrayT>
121 inline void
122 populateAttribute( PointDataTreeT& tree,
123  const PointIndexTreeT& pointIndexTree,
124  const openvdb::Name& attributeName,
125  const PointArrayT& data,
126  const Index stride = 1,
127  const bool insertMetadata = true);
128 
129 /// @brief Convert the position attribute from a Point Data Grid
130 ///
131 /// @param positionAttribute the position attribute to be populated.
132 /// @param grid the PointDataGrid to be converted.
133 /// @param pointOffsets a vector of cumulative point offsets for each leaf
134 /// @param startOffset a value to shift all the point offsets by
135 /// @param filter an index filter
136 /// @param inCoreOnly true if out-of-core leaf nodes are to be ignored
137 ///
138 
139 template <typename PositionAttribute, typename PointDataGridT, typename FilterT = NullFilter>
140 inline void
141 convertPointDataGridPosition( PositionAttribute& positionAttribute,
142  const PointDataGridT& grid,
143  const std::vector<Index64>& pointOffsets,
144  const Index64 startOffset,
145  const FilterT& filter = NullFilter(),
146  const bool inCoreOnly = false);
147 
148 
149 /// @brief Convert the attribute from a PointDataGrid
150 ///
151 /// @param attribute the attribute to be populated.
152 /// @param tree the PointDataTree to be converted.
153 /// @param pointOffsets a vector of cumulative point offsets for each leaf.
154 /// @param startOffset a value to shift all the point offsets by
155 /// @param arrayIndex the index in the Descriptor of the array to be converted.
156 /// @param stride the stride of the attribute
157 /// @param filter an index filter
158 /// @param inCoreOnly true if out-of-core leaf nodes are to be ignored
159 template <typename TypedAttribute, typename PointDataTreeT, typename FilterT = NullFilter>
160 inline void
162  const PointDataTreeT& tree,
163  const std::vector<Index64>& pointOffsets,
164  const Index64 startOffset,
165  const unsigned arrayIndex,
166  const Index stride = 1,
167  const FilterT& filter = NullFilter(),
168  const bool inCoreOnly = false);
169 
170 
171 /// @brief Convert the group from a PointDataGrid
172 ///
173 /// @param group the group to be populated.
174 /// @param tree the PointDataTree to be converted.
175 /// @param pointOffsets a vector of cumulative point offsets for each leaf
176 /// @param startOffset a value to shift all the point offsets by
177 /// @param index the group index to be converted.
178 /// @param filter an index filter
179 /// @param inCoreOnly true if out-of-core leaf nodes are to be ignored
180 ///
181 
182 template <typename Group, typename PointDataTreeT, typename FilterT = NullFilter>
183 inline void
185  const PointDataTreeT& tree,
186  const std::vector<Index64>& pointOffsets,
187  const Index64 startOffset,
188  const AttributeSet::Descriptor::GroupIndex index,
189  const FilterT& filter = NullFilter(),
190  const bool inCoreOnly = false);
191 
192 /// @ brief Given a container of world space positions and a target points per voxel,
193 /// compute a uniform voxel size that would best represent the storage of the points in a grid.
194 /// This voxel size is typically used for conversion of the points into a PointDataGrid.
195 ///
196 /// @param positions array of world space positions
197 /// @param pointsPerVoxel the target number of points per voxel, must be positive and non-zero
198 /// @param transform voxel size will be computed using this optional transform if provided
199 /// @param decimalPlaces for readability, truncate voxel size to this number of decimals
200 /// @param interrupter an optional interrupter
201 ///
202 /// @note if none or one point provided in positions, the default voxel size of 0.1 will be returned
203 ///
204 template<typename PositionWrapper, typename InterrupterT = openvdb::util::NullInterrupter>
205 inline float
206 computeVoxelSize( const PositionWrapper& positions,
207  const uint32_t pointsPerVoxel,
209  const Index decimalPlaces = 5,
210  InterrupterT* const interrupter = nullptr);
211 
212 
213 ////////////////////////////////////////
214 
215 
216 /// @brief Point-partitioner compatible STL vector attribute wrapper for convenience
217 template<typename ValueType>
219 public:
220  using PosType = ValueType;
221  using value_type= ValueType;
222 
223  PointAttributeVector(const std::vector<value_type>& data,
224  const Index stride = 1)
225  : mData(data)
226  , mStride(stride) { }
227 
228  size_t size() const { return mData.size(); }
229  void getPos(size_t n, ValueType& xyz) const { xyz = mData[n]; }
230  void get(ValueType& value, size_t n) const { value = mData[n]; }
231  void get(ValueType& value, size_t n, openvdb::Index m) const { value = mData[n * mStride + m]; }
232 
233 private:
234  const std::vector<value_type>& mData;
235  const Index mStride;
236 }; // PointAttributeVector
237 
238 
239 ////////////////////////////////////////
240 
241 
242 namespace point_conversion_internal {
243 
244 
245 // ConversionTraits to create the relevant Attribute Handles from a LeafNode
246 template <typename T> struct ConversionTraits
247 {
250  static T zero() { return zeroVal<T>(); }
251  template <typename LeafT>
252  static typename Handle::Ptr handleFromLeaf(LeafT& leaf, Index index) {
253  const AttributeArray& array = leaf.constAttributeArray(index);
254  return Handle::create(array);
255  }
256  template <typename LeafT>
257  static typename WriteHandle::Ptr writeHandleFromLeaf(LeafT& leaf, Index index) {
258  AttributeArray& array = leaf.attributeArray(index);
259  return WriteHandle::create(array);
260  }
261 }; // ConversionTraits
262 template <> struct ConversionTraits<openvdb::Name>
263 {
266  static openvdb::Name zero() { return ""; }
267  template <typename LeafT>
268  static typename Handle::Ptr handleFromLeaf(LeafT& leaf, Index index) {
269  const AttributeArray& array = leaf.constAttributeArray(index);
270  const AttributeSet::Descriptor& descriptor = leaf.attributeSet().descriptor();
271  return Handle::create(array, descriptor.getMetadata());
272  }
273  template <typename LeafT>
274  static typename WriteHandle::Ptr writeHandleFromLeaf(LeafT& leaf, Index index) {
275  AttributeArray& array = leaf.attributeArray(index);
276  const AttributeSet::Descriptor& descriptor = leaf.attributeSet().descriptor();
277  return WriteHandle::create(array, descriptor.getMetadata());
278  }
279 }; // ConversionTraits<openvdb::Name>
280 
281 template< typename PointDataTreeType,
282  typename PointIndexTreeType,
283  typename AttributeListType>
285 
287  using LeafRangeT = typename LeafManagerT::LeafRange;
288  using PointIndexLeafNode = typename PointIndexTreeType::LeafNodeType;
292 
293  PopulateAttributeOp(const PointIndexTreeType& pointIndexTree,
294  const AttributeListType& data,
295  const size_t index,
296  const Index stride = 1)
297  : mPointIndexTree(pointIndexTree)
298  , mData(data)
299  , mIndex(index)
300  , mStride(stride) { }
301 
302  void operator()(const typename LeafManagerT::LeafRange& range) const {
303 
304  for (auto leaf = range.begin(); leaf; ++leaf) {
305 
306  // obtain the PointIndexLeafNode (using the origin of the current leaf)
307 
308  const PointIndexLeafNode* pointIndexLeaf =
309  mPointIndexTree.probeConstLeaf(leaf->origin());
310 
311  if (!pointIndexLeaf) continue;
312 
313  typename HandleT::Ptr attributeWriteHandle =
314  ConversionTraits<ValueType>::writeHandleFromLeaf(*leaf, static_cast<Index>(mIndex));
315 
316  Index64 index = 0;
317 
318  const IndexArray& indices = pointIndexLeaf->indices();
319 
320  for (const Index64 leafIndex: indices)
321  {
323  for (Index i = 0; i < mStride; i++) {
324  mData.get(value, leafIndex, i);
325  attributeWriteHandle->set(static_cast<Index>(index), i, value);
326  }
327  index++;
328  }
329 
330  // attempt to compact the array
331 
332  attributeWriteHandle->compact();
333  }
334  }
335 
336  //////////
337 
338  const PointIndexTreeType& mPointIndexTree;
339  const AttributeListType& mData;
340  const size_t mIndex;
341  const Index mStride;
342 };
343 
344 template<typename PointDataTreeType, typename Attribute, typename FilterT>
346 
347  using LeafNode = typename PointDataTreeType::LeafNodeType;
348  using ValueType = typename Attribute::ValueType;
349  using HandleT = typename Attribute::Handle;
352  using LeafRangeT = typename LeafManagerT::LeafRange;
353 
355  const std::vector<Index64>& pointOffsets,
356  const Index64 startOffset,
357  const math::Transform& transform,
358  const size_t index,
359  const FilterT& filter,
360  const bool inCoreOnly)
361  : mAttribute(attribute)
362  , mPointOffsets(pointOffsets)
363  , mStartOffset(startOffset)
364  , mTransform(transform)
365  , mIndex(index)
366  , mFilter(filter)
367  , mInCoreOnly(inCoreOnly)
368  {
369  // only accept Vec3f as ValueType
370  static_assert(VecTraits<ValueType>::Size == 3 &&
372  "ValueType is not Vec3f");
373  }
374 
375  template <typename IterT>
376  void convert(IterT& iter, HandleT& targetHandle,
377  SourceHandleT& sourceHandle, Index64& offset) const
378  {
379  for (; iter; ++iter) {
380  const Vec3d xyz = iter.getCoord().asVec3d();
381  const Vec3d pos = sourceHandle.get(*iter);
382  targetHandle.set(static_cast<Index>(offset++), /*stride=*/0,
383  mTransform.indexToWorld(pos + xyz));
384  }
385  }
386 
387  void operator()(const LeafRangeT& range) const
388  {
389  HandleT pHandle(mAttribute);
390 
391  for (auto leaf = range.begin(); leaf; ++leaf) {
392 
393  assert(leaf.pos() < mPointOffsets.size());
394 
395  if (mInCoreOnly && leaf->buffer().isOutOfCore()) continue;
396 
398 
399  if (leaf.pos() > 0) offset += mPointOffsets[leaf.pos() - 1];
400 
401  auto handle = SourceHandleT::create(leaf->constAttributeArray(mIndex));
402 
403  if (mFilter.state() == index::ALL) {
404  auto iter = leaf->beginIndexOn();
405  convert(iter, pHandle, *handle, offset);
406  }
407  else {
408  auto iter = leaf->beginIndexOn(mFilter);
409  convert(iter, pHandle, *handle, offset);
410  }
411  }
412  }
413 
414  //////////
415 
417  const std::vector<Index64>& mPointOffsets;
420  const size_t mIndex;
421  const FilterT& mFilter;
422  const bool mInCoreOnly;
423 }; // ConvertPointDataGridPositionOp
424 
425 
426 template<typename PointDataTreeType, typename Attribute, typename FilterT>
428 
429  using LeafNode = typename PointDataTreeType::LeafNodeType;
430  using ValueType = typename Attribute::ValueType;
431  using HandleT = typename Attribute::Handle;
434  using LeafRangeT = typename LeafManagerT::LeafRange;
435 
437  const std::vector<Index64>& pointOffsets,
438  const Index64 startOffset,
439  const size_t index,
440  const Index stride,
441  const FilterT& filter,
442  const bool inCoreOnly)
443  : mAttribute(attribute)
444  , mPointOffsets(pointOffsets)
445  , mStartOffset(startOffset)
446  , mIndex(index)
447  , mStride(stride)
448  , mFilter(filter)
449  , mInCoreOnly(inCoreOnly) { }
450 
451  template <typename IterT>
452  void convert(IterT& iter, HandleT& targetHandle,
453  SourceHandleT& sourceHandle, Index64& offset) const
454  {
455  if (sourceHandle.isUniform()) {
456  const ValueType uniformValue(sourceHandle.get(0));
457  for (; iter; ++iter) {
458  for (Index i = 0; i < mStride; i++) {
459  targetHandle.set(static_cast<Index>(offset), i, uniformValue);
460  }
461  offset++;
462  }
463  }
464  else {
465  for (; iter; ++iter) {
466  for (Index i = 0; i < mStride; i++) {
467  targetHandle.set(static_cast<Index>(offset), i,
468  sourceHandle.get(*iter, /*stride=*/i));
469  }
470  offset++;
471  }
472  }
473  }
474 
475  void operator()(const LeafRangeT& range) const
476  {
477  HandleT pHandle(mAttribute);
478 
479  for (auto leaf = range.begin(); leaf; ++leaf) {
480 
481  assert(leaf.pos() < mPointOffsets.size());
482 
483  if (mInCoreOnly && leaf->buffer().isOutOfCore()) continue;
484 
486 
487  if (leaf.pos() > 0) offset += mPointOffsets[leaf.pos() - 1];
488 
489  typename SourceHandleT::Ptr handle = ConversionTraits<ValueType>::handleFromLeaf(
490  *leaf, static_cast<Index>(mIndex));
491 
492  if (mFilter.state() == index::ALL) {
493  auto iter = leaf->beginIndexOn();
494  convert(iter, pHandle, *handle, offset);
495  } else {
496  auto iter = leaf->beginIndexOn(mFilter);
497  convert(iter, pHandle, *handle, offset);
498  }
499  }
500  }
501 
502  //////////
503 
505  const std::vector<Index64>& mPointOffsets;
507  const size_t mIndex;
508  const Index mStride;
509  const FilterT& mFilter;
510  const bool mInCoreOnly;
511 }; // ConvertPointDataGridAttributeOp
512 
513 template<typename PointDataTreeType, typename Group, typename FilterT>
515 
516  using LeafNode = typename PointDataTreeType::LeafNodeType;
517  using GroupIndex = AttributeSet::Descriptor::GroupIndex;
519  using LeafRangeT = typename LeafManagerT::LeafRange;
520 
522  const std::vector<Index64>& pointOffsets,
523  const Index64 startOffset,
524  const AttributeSet::Descriptor::GroupIndex index,
525  const FilterT& filter,
526  const bool inCoreOnly)
527  : mGroup(group)
528  , mPointOffsets(pointOffsets)
529  , mStartOffset(startOffset)
530  , mIndex(index)
531  , mFilter(filter)
532  , mInCoreOnly(inCoreOnly) { }
533 
534  template <typename IterT>
535  void convert(IterT& iter, const GroupAttributeArray& groupArray, Index64& offset) const
536  {
537  const auto bitmask = static_cast<GroupType>(1 << mIndex.second);
538 
539  if (groupArray.isUniform()) {
540  if (groupArray.get(0) & bitmask) {
541  for (; iter; ++iter) {
542  mGroup.setOffsetOn(static_cast<Index>(offset));
543  offset++;
544  }
545  }
546  }
547  else {
548  for (; iter; ++iter) {
549  if (groupArray.get(*iter) & bitmask) {
550  mGroup.setOffsetOn(static_cast<Index>(offset));
551  }
552  offset++;
553  }
554  }
555  }
556 
557  void operator()(const LeafRangeT& range) const
558  {
559  for (auto leaf = range.begin(); leaf; ++leaf) {
560 
561  assert(leaf.pos() < mPointOffsets.size());
562 
563  if (mInCoreOnly && leaf->buffer().isOutOfCore()) continue;
564 
566 
567  if (leaf.pos() > 0) offset += mPointOffsets[leaf.pos() - 1];
568 
569  const AttributeArray& array = leaf->constAttributeArray(mIndex.first);
570  assert(isGroup(array));
571  const GroupAttributeArray& groupArray = GroupAttributeArray::cast(array);
572 
573  if (mFilter.state() == index::ALL) {
574  auto iter = leaf->beginIndexOn();
575  convert(iter, groupArray, offset);
576  }
577  else {
578  auto iter = leaf->beginIndexOn(mFilter);
579  convert(iter, groupArray, offset);
580  }
581  }
582  }
583 
584  //////////
585 
586  Group& mGroup;
587  const std::vector<Index64>& mPointOffsets;
590  const FilterT& mFilter;
591  const bool mInCoreOnly;
592 }; // ConvertPointDataGridGroupOp
593 
594 template<typename PositionArrayT>
596 {
597  CalculatePositionBounds(const PositionArrayT& positions,
598  const math::Mat4d& inverse)
599  : mPositions(positions)
600  , mInverseMat(inverse)
601  , mMin(std::numeric_limits<Real>::max())
602  , mMax(-std::numeric_limits<Real>::max()) {}
603 
605  : mPositions(other.mPositions)
606  , mInverseMat(other.mInverseMat)
607  , mMin(std::numeric_limits<Real>::max())
608  , mMax(-std::numeric_limits<Real>::max()) {}
609 
610  void operator()(const tbb::blocked_range<size_t>& range) {
611  Vec3R pos;
612  for (size_t n = range.begin(), N = range.end(); n != N; ++n) {
613  mPositions.getPos(n, pos);
614  pos = mInverseMat.transform(pos);
615  mMin = math::minComponent(mMin, pos);
616  mMax = math::maxComponent(mMax, pos);
617  }
618  }
619 
620  void join(const CalculatePositionBounds& other) {
621  mMin = math::minComponent(mMin, other.mMin);
622  mMax = math::maxComponent(mMax, other.mMax);
623  }
624 
626  return BBoxd(mMin, mMax);
627  }
628 
629 private:
630  const PositionArrayT& mPositions;
631  const math::Mat4d& mInverseMat;
632  Vec3R mMin, mMax;
633 };
634 
635 } // namespace point_conversion_internal
636 
637 
638 ////////////////////////////////////////
639 
640 
641 template<typename CompressionT, typename PointDataGridT, typename PositionArrayT, typename PointIndexGridT>
642 inline typename PointDataGridT::Ptr
643 createPointDataGrid(const PointIndexGridT& pointIndexGrid, const PositionArrayT& positions,
644  const math::Transform& xform, Metadata::Ptr positionDefaultValue)
645 {
646  using PointDataTreeT = typename PointDataGridT::TreeType;
647  using LeafT = typename PointDataTree::LeafNodeType;
648  using PointIndexLeafT = typename PointIndexGridT::TreeType::LeafNodeType;
649  using PointIndexT = typename PointIndexLeafT::ValueType;
650  using LeafManagerT = typename tree::LeafManager<PointDataTreeT>;
651  using PositionAttributeT = TypedAttributeArray<Vec3f, CompressionT>;
652 
653  const NamePair positionType = PositionAttributeT::attributeType();
654 
655  // construct the Tree using a topology copy of the PointIndexGrid
656 
657  const auto& pointIndexTree = pointIndexGrid.tree();
658  typename PointDataTreeT::Ptr treePtr(new PointDataTreeT(pointIndexTree));
659 
660  // create attribute descriptor from position type
661 
662  auto descriptor = AttributeSet::Descriptor::create(positionType);
663 
664  // add default value for position if provided
665 
666  if (positionDefaultValue) descriptor->setDefaultValue("P", *positionDefaultValue);
667 
668  // retrieve position index
669 
670  const size_t positionIndex = descriptor->find("P");
671  assert(positionIndex != AttributeSet::INVALID_POS);
672 
673  // acquire registry lock to avoid locking when appending attributes in parallel
674 
676 
677  // populate position attribute
678 
679  LeafManagerT leafManager(*treePtr);
680  leafManager.foreach(
681  [&](LeafT& leaf, size_t /*idx*/) {
682 
683  // obtain the PointIndexLeafNode (using the origin of the current leaf)
684 
685  const auto* pointIndexLeaf = pointIndexTree.probeConstLeaf(leaf.origin());
686  assert(pointIndexLeaf);
687 
688  // initialise the attribute storage
689 
690  Index pointCount(static_cast<Index>(pointIndexLeaf->indices().size()));
691  leaf.initializeAttributes(descriptor, pointCount, &lock);
692 
693  // create write handle for position
694 
695  auto attributeWriteHandle = AttributeWriteHandle<Vec3f, CompressionT>::create(
696  leaf.attributeArray(positionIndex));
697 
698  Index index = 0;
699 
700  const PointIndexT
701  *begin = static_cast<PointIndexT*>(nullptr),
702  *end = static_cast<PointIndexT*>(nullptr);
703 
704  // iterator over every active voxel in the point index leaf
705 
706  for (auto iter = pointIndexLeaf->cbeginValueOn(); iter; ++iter) {
707 
708  // find the voxel center
709 
710  const Coord& ijk = iter.getCoord();
711  const Vec3d& positionCellCenter(ijk.asVec3d());
712 
713  // obtain pointers for this voxel from begin to end in the indices array
714 
715  pointIndexLeaf->getIndices(ijk, begin, end);
716 
717  while (begin < end) {
718 
719  typename PositionArrayT::value_type positionWorldSpace;
720  positions.getPos(*begin, positionWorldSpace);
721 
722  // compute the index-space position and then subtract the voxel center
723 
724  const Vec3d positionIndexSpace = xform.worldToIndex(positionWorldSpace);
725  const Vec3f positionVoxelSpace(positionIndexSpace - positionCellCenter);
726 
727  attributeWriteHandle->set(index++, positionVoxelSpace);
728 
729  ++begin;
730  }
731  }
732  },
733  /*threaded=*/true);
734 
735  auto grid = PointDataGridT::create(treePtr);
736  grid->setTransform(xform.copy());
737  return grid;
738 }
739 
740 
741 ////////////////////////////////////////
742 
743 
744 template <typename CompressionT, typename PointDataGridT, typename ValueT>
745 inline typename PointDataGridT::Ptr
746 createPointDataGrid(const std::vector<ValueT>& positions,
747  const math::Transform& xform,
748  Metadata::Ptr positionDefaultValue)
749 {
750  const PointAttributeVector<ValueT> pointList(positions);
751 
752  tools::PointIndexGrid::Ptr pointIndexGrid = tools::createPointIndexGrid<tools::PointIndexGrid>(pointList, xform);
753  return createPointDataGrid<CompressionT, PointDataGridT>(*pointIndexGrid, pointList, xform, positionDefaultValue);
754 }
755 
756 
757 ////////////////////////////////////////
758 
759 
760 template <typename PointDataTreeT, typename PointIndexTreeT, typename PointArrayT>
761 inline void
762 populateAttribute(PointDataTreeT& tree, const PointIndexTreeT& pointIndexTree,
763  const openvdb::Name& attributeName, const PointArrayT& data, const Index stride,
764  const bool insertMetadata)
765 {
767  using ValueType = typename PointArrayT::value_type;
768 
769  auto iter = tree.cbeginLeaf();
770 
771  if (!iter) return;
772 
773  const size_t index = iter->attributeSet().find(attributeName);
774 
775  if (index == AttributeSet::INVALID_POS) {
776  OPENVDB_THROW(KeyError, "Attribute not found to populate - " << attributeName << ".");
777  }
778 
779  if (insertMetadata) {
781  }
782 
783  // populate attribute
784 
785  typename tree::LeafManager<PointDataTreeT> leafManager(tree);
786 
787  PopulateAttributeOp<PointDataTreeT,
788  PointIndexTreeT,
789  PointArrayT> populate(pointIndexTree, data, index, stride);
790  tbb::parallel_for(leafManager.leafRange(), populate);
791 }
792 
793 
794 ////////////////////////////////////////
795 
796 
797 template <typename PositionAttribute, typename PointDataGridT, typename FilterT>
798 inline void
799 convertPointDataGridPosition( PositionAttribute& positionAttribute,
800  const PointDataGridT& grid,
801  const std::vector<Index64>& pointOffsets,
802  const Index64 startOffset,
803  const FilterT& filter,
804  const bool inCoreOnly)
805 {
806  using TreeType = typename PointDataGridT::TreeType;
807  using LeafManagerT = typename tree::LeafManager<const TreeType>;
808 
810 
811  const TreeType& tree = grid.tree();
812  auto iter = tree.cbeginLeaf();
813 
814  if (!iter) return;
815 
816  const size_t positionIndex = iter->attributeSet().find("P");
817 
818  positionAttribute.expand();
819  LeafManagerT leafManager(tree);
820  ConvertPointDataGridPositionOp<TreeType, PositionAttribute, FilterT> convert(
821  positionAttribute, pointOffsets, startOffset, grid.transform(), positionIndex,
822  filter, inCoreOnly);
823  tbb::parallel_for(leafManager.leafRange(), convert);
824  positionAttribute.compact();
825 }
826 
827 
828 ////////////////////////////////////////
829 
830 
831 template <typename TypedAttribute, typename PointDataTreeT, typename FilterT>
832 inline void
834  const PointDataTreeT& tree,
835  const std::vector<Index64>& pointOffsets,
836  const Index64 startOffset,
837  const unsigned arrayIndex,
838  const Index stride,
839  const FilterT& filter,
840  const bool inCoreOnly)
841 {
842  using LeafManagerT = typename tree::LeafManager<const PointDataTreeT>;
843 
845 
846  auto iter = tree.cbeginLeaf();
847 
848  if (!iter) return;
849 
850  attribute.expand();
851  LeafManagerT leafManager(tree);
852  ConvertPointDataGridAttributeOp<PointDataTreeT, TypedAttribute, FilterT> convert(
853  attribute, pointOffsets, startOffset, arrayIndex, stride,
854  filter, inCoreOnly);
855  tbb::parallel_for(leafManager.leafRange(), convert);
856  attribute.compact();
857 }
858 
859 
860 ////////////////////////////////////////
861 
862 
863 template <typename Group, typename PointDataTreeT, typename FilterT>
864 inline void
866  const PointDataTreeT& tree,
867  const std::vector<Index64>& pointOffsets,
868  const Index64 startOffset,
869  const AttributeSet::Descriptor::GroupIndex index,
870  const FilterT& filter,
871  const bool inCoreOnly)
872 {
873  using LeafManagerT= typename tree::LeafManager<const PointDataTreeT>;
874 
876 
877  auto iter = tree.cbeginLeaf();
878  if (!iter) return;
879 
880  LeafManagerT leafManager(tree);
881  ConvertPointDataGridGroupOp<PointDataTree, Group, FilterT> convert(
882  group, pointOffsets, startOffset, index,
883  filter, inCoreOnly);
884  tbb::parallel_for(leafManager.leafRange(), convert);
885 
886  // must call this after modifying point groups in parallel
887 
888  group.finalize();
889 }
890 
891 template<typename PositionWrapper, typename InterrupterT>
892 inline float
893 computeVoxelSize( const PositionWrapper& positions,
894  const uint32_t pointsPerVoxel,
895  const math::Mat4d transform,
896  const Index decimalPlaces,
897  InterrupterT* const interrupter)
898 {
899  using namespace point_conversion_internal;
900 
901  struct Local {
902 
903  static bool voxelSizeFromVolume(const double volume,
904  const size_t estimatedVoxelCount,
905  float& voxelSize)
906  {
907  // dictated by the math::ScaleMap limit
908  static const double minimumVoxelVolume(3e-15);
909  static const double maximumVoxelVolume(std::numeric_limits<float>::max());
910 
911  double voxelVolume = volume / static_cast<double>(estimatedVoxelCount);
912  bool valid = true;
913 
914  if (voxelVolume < minimumVoxelVolume) {
915  voxelVolume = minimumVoxelVolume;
916  valid = false;
917  }
918  else if (voxelVolume > maximumVoxelVolume) {
919  voxelVolume = maximumVoxelVolume;
920  valid = false;
921  }
922 
923  voxelSize = static_cast<float>(math::Pow(voxelVolume, 1.0/3.0));
924  return valid;
925  }
926 
927  static float truncate(const float voxelSize, Index decPlaces)
928  {
929  float truncatedVoxelSize = voxelSize;
930 
931  // attempt to truncate from decPlaces -> 11
932  for (int i = decPlaces; i < 11; i++) {
933  truncatedVoxelSize = static_cast<float>(math::Truncate(double(voxelSize), i));
934  if (truncatedVoxelSize != 0.0f) break;
935  }
936 
937  return truncatedVoxelSize;
938  }
939  };
940 
941  if (pointsPerVoxel == 0) OPENVDB_THROW(ValueError, "Points per voxel cannot be zero.");
942 
943  // constructed with the default voxel size as specified by openvdb interface values
944 
945  float voxelSize(0.1f);
946 
947  const size_t numPoints = positions.size();
948 
949  // return the default voxel size if we have zero or only 1 point
950 
951  if (numPoints <= 1) return voxelSize;
952 
953  size_t targetVoxelCount(numPoints / size_t(pointsPerVoxel));
954  if (targetVoxelCount == 0) targetVoxelCount++;
955 
956  // calculate the world space, transform-oriented bounding box
957 
958  math::Mat4d inverseTransform = transform.inverse();
959  inverseTransform = math::unit(inverseTransform);
960 
961  tbb::blocked_range<size_t> range(0, numPoints);
962  CalculatePositionBounds<PositionWrapper> calculateBounds(positions, inverseTransform);
963  tbb::parallel_reduce(range, calculateBounds);
964 
965  BBoxd bbox = calculateBounds.getBoundingBox();
966 
967  // return default size if points are coincident
968 
969  if (bbox.min() == bbox.max()) return voxelSize;
970 
971  double volume = bbox.volume();
972 
973  // handle points that are collinear or coplanar by expanding the volume
974 
975  if (math::isApproxZero(volume)) {
976  Vec3d extents = bbox.extents().sorted().reversed();
977  if (math::isApproxZero(extents[1])) {
978  // colinear (maxExtent^3)
979  volume = extents[0]*extents[0]*extents[0];
980  }
981  else {
982  // coplanar (maxExtent*nextMaxExtent^2)
983  volume = extents[0]*extents[1]*extents[1];
984  }
985  }
986 
987  double previousVolume = volume;
988 
989  if (!Local::voxelSizeFromVolume(volume, targetVoxelCount, voxelSize)) {
990  OPENVDB_LOG_DEBUG("Out of range, clamping voxel size.");
991  return voxelSize;
992  }
993 
994  size_t previousVoxelCount(0);
995  size_t voxelCount(1);
996 
997  if (interrupter) interrupter->start("Computing voxel size");
998 
999  while (voxelCount > previousVoxelCount)
1000  {
1001  math::Transform::Ptr newTransform;
1002 
1003  if (!math::isIdentity(transform))
1004  {
1005  // if using a custom transform, pre-scale by coefficients
1006  // which define the new voxel size
1007 
1008  math::Mat4d matrix(transform);
1009  matrix.preScale(Vec3d(voxelSize) / math::getScale(matrix));
1010  newTransform = math::Transform::createLinearTransform(matrix);
1011  }
1012  else
1013  {
1014  newTransform = math::Transform::createLinearTransform(voxelSize);
1015  }
1016 
1017  // create a mask grid of the points from the calculated voxel size
1018  // this is the same function call as tools::createPointMask() which has
1019  // been duplicated to provide an interrupter
1020 
1021  MaskGrid::Ptr mask = createGrid<MaskGrid>(false);
1022  mask->setTransform(newTransform);
1023  tools::PointsToMask<MaskGrid, InterrupterT> pointMaskOp(*mask, interrupter);
1024  pointMaskOp.addPoints(positions);
1025 
1026  if (interrupter && util::wasInterrupted(interrupter)) break;
1027 
1028  previousVoxelCount = voxelCount;
1029  voxelCount = mask->activeVoxelCount();
1030  volume = math::Pow3(voxelSize) * static_cast<float>(voxelCount);
1031 
1032  // stop if no change in the volume or the volume has increased
1033 
1034  if (volume >= previousVolume) break;
1035  previousVolume = volume;
1036 
1037  const float previousVoxelSize = voxelSize;
1038 
1039  // compute the new voxel size and if invalid return the previous value
1040 
1041  if (!Local::voxelSizeFromVolume(volume, targetVoxelCount, voxelSize)) {
1042  voxelSize = previousVoxelSize;
1043  break;
1044  }
1045 
1046  // halt convergence if the voxel size has decreased by less
1047  // than 10% in this iteration
1048 
1049  if (voxelSize / previousVoxelSize > 0.9f) break;
1050  }
1051 
1052  if (interrupter) interrupter->end();
1053 
1054  // truncate the voxel size for readability and return the value
1055 
1056  return Local::truncate(voxelSize, decimalPlaces);
1057 }
1058 
1059 
1060 ////////////////////////////////////////
1061 
1062 
1063 // deprecated functions
1064 
1065 
1066 template <typename PositionAttribute, typename PointDataGridT>
1068 inline void
1069 convertPointDataGridPosition( PositionAttribute& positionAttribute,
1070  const PointDataGridT& grid,
1071  const std::vector<Index64>& pointOffsets,
1072  const Index64 startOffset,
1073  const std::vector<Name>& includeGroups,
1074  const std::vector<Name>& excludeGroups,
1075  const bool inCoreOnly = false)
1076 {
1077  auto leaf = grid.tree().cbeginLeaf();
1078  if (!leaf) return;
1079  MultiGroupFilter filter(includeGroups, excludeGroups, leaf->attributeSet());
1080  convertPointDataGridPosition(positionAttribute, grid, pointOffsets, startOffset,
1081  filter, inCoreOnly);
1082 }
1083 
1084 
1085 template <typename TypedAttribute, typename PointDataTreeT>
1087 inline void
1089  const PointDataTreeT& tree,
1090  const std::vector<Index64>& pointOffsets,
1091  const Index64 startOffset,
1092  const unsigned arrayIndex,
1093  const Index stride,
1094  const std::vector<Name>& includeGroups,
1095  const std::vector<Name>& excludeGroups,
1096  const bool inCoreOnly = false)
1097 {
1098  auto leaf = tree.cbeginLeaf();
1099  if (!leaf) return;
1100  MultiGroupFilter filter(includeGroups, excludeGroups, leaf->attributeSet());
1101  convertPointDataGridAttribute(attribute, tree, pointOffsets, startOffset,
1102  arrayIndex, stride, filter, inCoreOnly);
1103 }
1104 
1105 
1106 template <typename Group, typename PointDataTreeT>
1108 inline void
1110  const PointDataTreeT& tree,
1111  const std::vector<Index64>& pointOffsets,
1112  const Index64 startOffset,
1113  const AttributeSet::Descriptor::GroupIndex index,
1114  const std::vector<Name>& includeGroups,
1115  const std::vector<Name>& excludeGroups,
1116  const bool inCoreOnly = false)
1117 {
1118  auto leaf = tree.cbeginLeaf();
1119  if (!leaf) return;
1120  MultiGroupFilter filter(includeGroups, excludeGroups, leaf->attributeSet());
1121  convertPointDataGridGroup(group, tree, pointOffsets, startOffset,
1122  index, filter, inCoreOnly);
1123 }
1124 
1125 
1126 } // namespace points
1127 } // namespace OPENVDB_VERSION_NAME
1128 } // namespace openvdb
1129 
1130 #endif // OPENVDB_POINTS_POINT_CONVERSION_HAS_BEEN_INCLUDED
1131 
1132 // Copyright (c) DreamWorks Animation LLC
1133 // All rights reserved. This software is distributed under the
1134 // Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ )
bool isUniform() const override
Return true if this array is stored as a single uniform value.
Vec2< T > minComponent(const Vec2< T > &v1, const Vec2< T > &v2)
Return component-wise minimum of the two vectors.
Definition: Vec2.h:530
vint4 max(const vint4 &a, const vint4 &b)
Definition: simd.h:4703
void parallel_for(int64_t start, int64_t end, std::function< void(int64_t index)> &&task, parallel_options opt=parallel_options(0, Split_Y, 1))
Definition: parallel.h:153
GLenum GLint * range
Definition: glew.h:3500
Definition: ImfName.h:53
This tool produces a grid where every voxel that contains a point is active. It employes thread-local...
Type Truncate(Type x, unsigned int digits)
Return x truncated to the given number of decimal digits.
Definition: Math.h:844
void operator()(const typename LeafManagerT::LeafRange &range) const
PointDataGridT::Ptr createPointDataGrid(const PointIndexGridT &pointIndexGrid, const PositionArrayT &positions, const math::Transform &xform, Metadata::Ptr positionDefaultValue=Metadata::Ptr())
Localises points with position into a PointDataGrid into two stages: allocation of the leaf attribute...
Vec3d indexToWorld(const Vec3d &xyz) const
Apply this transformation to the given coordinates.
Definition: Transform.h:135
Type Pow(Type x, int n)
Return xn.
Definition: Math.h:535
LeafRange leafRange(size_t grainsize=1) const
Return a TBB-compatible LeafRange.
Definition: LeafManager.h:385
FMT_CONSTEXPR auto begin(const C &c) -> decltype(c.begin())
Definition: format.h:251
GLuint GLenum GLenum transform
Definition: glew.h:14742
GLuint index
Definition: glew.h:1814
ValueType get(Index n) const
Return the value at index n.
bool isIdentity(const MatType &m)
Determine if a matrix is an identity matrix.
Definition: Mat.h:892
Point group manipulation in a VDB Point Grid.
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:200
void convert(IterT &iter, HandleT &targetHandle, SourceHandleT &sourceHandle, Index64 &offset) const
Index filters primarily designed to be used with a FilterIndexIter.
const GLdouble * m
Definition: glew.h:9124
#define OPENVDB_LOG_DEBUG(mesg)
Definition: logging.h:304
GLenum GLint GLuint mask
Definition: glew.h:1845
Makes every voxel of a grid active if it contains a point.
Definition: PointsToMask.h:94
MatType unit(const MatType &mat, typename MatType::value_type eps=1.0e-8)
Return a copy of the given matrix with its upper 3×3 rows normalized.
Definition: Mat.h:680
uint64 value_type
Definition: GA_PrimCompat.h:29
static Ptr create(AttributeArray &array, const bool expand=true)
bool isGroup(const AttributeArray &array)
CalculatePositionBounds(const PositionArrayT &positions, const math::Mat4d &inverse)
float computeVoxelSize(const PositionWrapper &positions, const uint32_t pointsPerVoxel, const math::Mat4d transform=math::Mat4d::identity(), const Index decimalPlaces=5, InterrupterT *const interrupter=nullptr)
SYS_FORCE_INLINE const_iterator end() const
void populateAttribute(PointDataTreeT &tree, const PointIndexTreeT &pointIndexTree, const openvdb::Name &attributeName, const PointArrayT &data, const Index stride=1, const bool insertMetadata=true)
Stores point attribute data in an existing PointDataGrid attribute.
ConvertPointDataGridPositionOp(Attribute &attribute, const std::vector< Index64 > &pointOffsets, const Index64 startOffset, const math::Transform &transform, const size_t index, const FilterT &filter, const bool inCoreOnly)
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
Definition: glew.h:2981
void OIIO_API split(string_view str, std::vector< string_view > &result, string_view sep=string_view(), int maxsplit=-1)
Base class for storing attribute data.
Vec3< T > reversed() const
Return the vector (z, y, x)
Definition: Vec3.h:485
GLclampf f
Definition: glew.h:3499
ConvertPointDataGridAttributeOp(Attribute &attribute, const std::vector< Index64 > &pointOffsets, const Index64 startOffset, const size_t index, const Index stride, const FilterT &filter, const bool inCoreOnly)
#define OPENVDB_DEPRECATED
Definition: Platform.h:69
void preScale(const Vec3< T0 > &v)
Definition: Mat4.h:782
GLint GLenum GLsizei GLint GLsizei const void * data
Definition: glew.h:1379
GLuint GLuint GLsizei GLenum const void * indices
Definition: glew.h:1253
Attribute array storage for string data using Descriptor Metadata.
GLuint GLuint end
Definition: glew.h:1253
OPENVDB_API void calculateBounds(const Transform &t, const Vec3d &minWS, const Vec3d &maxWS, Vec3d &minIS, Vec3d &maxIS)
Calculate an axis-aligned bounding box in index space from an axis-aligned bounding box in world spac...
GLsizei n
Definition: glew.h:4040
This class manages a linear array of pointers to a given tree's leaf nodes, as well as optional auxil...
Definition: LeafManager.h:109
Type Pow3(Type x)
Return x3.
Definition: Math.h:526
ConvertPointDataGridGroupOp(Group &group, const std::vector< Index64 > &pointOffsets, const Index64 startOffset, const AttributeSet::Descriptor::GroupIndex index, const FilterT &filter, const bool inCoreOnly)
Vec3< T > sorted() const
Return a vector with the components of this in ascending order.
Definition: Vec3.h:475
void convert(IterT &iter, const GroupAttributeArray &groupArray, Index64 &offset) const
Index64 pointCount(const PointDataTreeT &tree, const FilterT &filter=NullFilter(), const bool inCoreOnly=false, const bool threaded=true)
Count the total number of points in a PointDataTree.
Definition: PointCount.h:115
std::pair< Name, Name > NamePair
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
GLsizei stride
Definition: glew.h:1523
Point attribute manipulation in a VDB Point Grid.
typename RootNodeType::LeafNodeType LeafNodeType
Definition: Tree.h:212
Typed class for storing attribute data.
Set of Attribute Arrays which tracks metadata about each array.
ElementType volume() const
Return the volume enclosed by this bounding box.
Definition: BBox.h:127
Space-partitioning acceleration structure for points. Partitions the points into voxels to accelerate...
void convertPointDataGridAttribute(TypedAttribute &attribute, const PointDataTreeT &tree, const std::vector< Index64 > &pointOffsets, const Index64 startOffset, const unsigned arrayIndex, const Index stride=1, const FilterT &filter=NullFilter(), const bool inCoreOnly=false)
Convert the attribute from a PointDataGrid.
GLuint GLdouble GLdouble GLint GLint const GLdouble * points
Definition: glew.h:3446
Vec4< T0 > transform(const Vec4< T0 > &v) const
Transform a Vec4 by post-multiplication.
Definition: Mat4.h:1044
math::BBox< Vec3d > BBoxd
Definition: Types.h:91
Vec2< T > maxComponent(const Vec2< T > &v1, const Vec2< T > &v2)
Return component-wise maximum of the two vectors.
Definition: Vec2.h:539
Vec3< typename MatType::value_type > getScale(const MatType &mat)
Return a Vec3 representing the lengths of the passed matrix's upper 3×3's rows.
Definition: Mat.h:665
static const Mat4< double > & identity()
Predefined constant for identity matrix.
Definition: Mat4.h:152
Index64 pointOffsets(std::vector< Index64 > &pointOffsets, const PointDataTreeT &tree, const FilterT &filter=NullFilter(), const bool inCoreOnly=false, const bool threaded=true)
Populate an array of cumulative point offsets per leaf node.
Definition: PointCount.h:149
GA_API const UT_StringHolder N
OIIO_API bool attribute(string_view name, TypeDesc type, const void *val)
Point-partitioner compatible STL vector attribute wrapper for convenience.
GLenum array
Definition: glew.h:9066
void convert(IterT &iter, HandleT &targetHandle, SourceHandleT &sourceHandle, Index64 &offset) const
void convertPointDataGridGroup(Group &group, const PointDataTreeT &tree, const std::vector< Index64 > &pointOffsets, const Index64 startOffset, const AttributeSet::Descriptor::GroupIndex index, const FilterT &filter=NullFilter(), const bool inCoreOnly=false)
Convert the group from a PointDataGrid.
static Transform::Ptr createLinearTransform(double voxelSize=1.0)
Create and return a shared pointer to a new transform.
Vec3d worldToIndex(const Vec3d &xyz) const
Apply this transformation to the given coordinates.
Definition: Transform.h:137
bool wasInterrupted(T *i, int percent=-1)
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h:146
GLsizei const GLfloat * value
Definition: glew.h:1849
Attribute-owned data structure for points. Point attributes are stored in leaf nodes and ordered by v...
GLuint GLenum matrix
Definition: glew.h:14742
Mat4 inverse(T tolerance=0) const
Definition: Mat4.h:531
void convertPointDataGridPosition(PositionAttribute &positionAttribute, const PointDataGridT &grid, const std::vector< Index64 > &pointOffsets, const Index64 startOffset, const FilterT &filter=NullFilter(), const bool inCoreOnly=false)
Convert the position attribute from a Point Data Grid.
#define OPENVDB_THROW(exception, message)
Definition: Exceptions.h:109
PopulateAttributeOp(const PointIndexTreeType &pointIndexTree, const AttributeListType &data, const size_t index, const Index stride=1)
void addPoints(const PointListT &points, size_t grainSize=1024)
Activates the state of any voxel in the input grid that contains a point.
Definition: PointsToMask.h:150
GLboolean GLuint group
Definition: glew.h:2745
void * Handle
Definition: plugin.h:53
PointAttributeVector(const std::vector< value_type > &data, const Index stride=1)
GLintptr offset
Definition: glew.h:1682