HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
PointMove.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
32 ///
33 /// @file PointMove.h
34 ///
35 /// @brief Ability to move VDB Points using a custom deformer.
36 ///
37 /// Deformers used when moving points are in world space by default and must adhere
38 /// to the interface described in the example below:
39 /// @code
40 /// struct MyDeformer
41 /// {
42 /// // A reset is performed on each leaf in turn before the points in that leaf are
43 /// // deformed. A leaf and leaf index (standard leaf traversal order) are supplied as
44 /// // the arguments, which matches the functor interface for LeafManager::foreach().
45 /// template <typename LeafNoteType>
46 /// void reset(LeafNoteType& leaf, size_t idx);
47 ///
48 /// // Evaluate the deformer and modify the given position to generate the deformed
49 /// // position. An index iterator is supplied as the argument to allow querying the
50 /// // point offset or containing voxel coordinate.
51 /// template <typename IndexIterT>
52 /// void apply(Vec3d& position, const IndexIterT& iter) const;
53 /// };
54 /// @endcode
55 ///
56 /// @note The DeformerTraits struct (defined in PointMask.h) can be used to configure
57 /// a deformer to evaluate in index space.
58 
59 #ifndef OPENVDB_POINTS_POINT_MOVE_HAS_BEEN_INCLUDED
60 #define OPENVDB_POINTS_POINT_MOVE_HAS_BEEN_INCLUDED
61 
62 #include <openvdb/openvdb.h>
63 
66 
67 #include <tbb/concurrent_vector.h>
68 
69 #include <algorithm>
70 #include <iterator> // for std::begin(), std::end()
71 #include <map>
72 #include <numeric> // for std::iota()
73 #include <tuple>
74 #include <unordered_map>
75 #include <vector>
76 
77 class TestPointMove;
78 
79 
80 namespace openvdb {
82 namespace OPENVDB_VERSION_NAME {
83 namespace points {
84 
85 // dummy object for future use
86 namespace future { struct Advect { }; }
87 
88 
89 /// @brief Move points in a PointDataGrid using a custom deformer
90 /// @param points the PointDataGrid containing the points to be moved.
91 /// @param deformer a custom deformer that defines how to move the points.
92 /// @param filter an optional index filter
93 /// @param objectNotInUse for future use, this object is currently ignored
94 /// @param threaded enable or disable threading (threading is enabled by default)
95 template <typename PointDataGridT, typename DeformerT, typename FilterT = NullFilter>
96 inline void movePoints(PointDataGridT& points,
97  DeformerT& deformer,
98  const FilterT& filter = NullFilter(),
99  future::Advect* objectNotInUse = nullptr,
100  bool threaded = true);
101 
102 
103 /// @brief Move points in a PointDataGrid using a custom deformer and a new transform
104 /// @param points the PointDataGrid containing the points to be moved.
105 /// @param transform target transform to use for the resulting points.
106 /// @param deformer a custom deformer that defines how to move the points.
107 /// @param filter an optional index filter
108 /// @param objectNotInUse for future use, this object is currently ignored
109 /// @param threaded enable or disable threading (threading is enabled by default)
110 template <typename PointDataGridT, typename DeformerT, typename FilterT = NullFilter>
111 inline void movePoints(PointDataGridT& points,
112  const math::Transform& transform,
113  DeformerT& deformer,
114  const FilterT& filter = NullFilter(),
115  future::Advect* objectNotInUse = nullptr,
116  bool threaded = true);
117 
118 
119 // define leaf index in use as 32-bit
120 namespace point_move_internal { using LeafIndex = Index32; }
121 
122 
123 /// @brief A Deformer that caches the resulting positions from evaluating another Deformer
124 template <typename T>
126 {
127 public:
129  using Vec3T = typename math::Vec3<T>;
130  using LeafVecT = std::vector<Vec3T>;
131  using LeafMapT = std::unordered_map<LeafIndex, Vec3T>;
132 
133  // Internal data cache to allow the deformer to offer light-weight copying
134  struct Cache
135  {
136  struct Leaf
137  {
138  /// @brief clear data buffers and reset counter
139  void clear() {
140  vecData.clear();
141  mapData.clear();
142  totalSize = 0;
143  }
144 
148  }; // struct Leaf
149 
150  std::vector<Leaf> leafs;
151  }; // struct Cache
152 
153  /// Cache is expected to be persistent for the lifetime of the CachedDeformer
154  explicit CachedDeformer(Cache& cache);
155 
156  /// Caches the result of evaluating the supplied point grid using the deformer and filter
157  /// @param grid the points to be moved
158  /// @param deformer the deformer to apply to the points
159  /// @param filter the point filter to use when evaluating the points
160  /// @param threaded enable or disable threading (threading is enabled by default)
161  template <typename PointDataGridT, typename DeformerT, typename FilterT>
162  void evaluate(PointDataGridT& grid, DeformerT& deformer, const FilterT& filter,
163  bool threaded = true);
164 
165  /// Stores pointers to the vector or map and optionally expands the map into a vector
166  /// @throw IndexError if idx is out-of-range of the leafs in the cache
167  template <typename LeafT>
168  void reset(const LeafT& leaf, size_t idx);
169 
170  /// Retrieve the new position from the cache
171  template <typename IndexIterT>
172  void apply(Vec3d& position, const IndexIterT& iter) const;
173 
174 private:
175  friend class ::TestPointMove;
176 
177  Cache& mCache;
178  const LeafVecT* mLeafVec = nullptr;
179  const LeafMapT* mLeafMap = nullptr;
180 }; // class CachedDeformer
181 
182 
183 ////////////////////////////////////////
184 
185 
186 namespace point_move_internal {
187 
188 using IndexArray = std::vector<Index>;
189 
190 using IndexTriple = std::tuple<LeafIndex, Index, Index>;
191 using IndexTripleArray = tbb::concurrent_vector<IndexTriple>;
192 using GlobalPointIndexMap = std::vector<IndexTripleArray>;
193 using GlobalPointIndexIndices = std::vector<IndexArray>;
194 
195 using IndexPair = std::pair<Index, Index>;
196 using IndexPairArray = std::vector<IndexPair>;
197 using LocalPointIndexMap = std::vector<IndexPairArray>;
198 
199 using LeafIndexArray = std::vector<LeafIndex>;
200 using LeafOffsetArray = std::vector<LeafIndexArray>;
201 using LeafMap = std::unordered_map<Coord, LeafIndex>;
202 
203 
204 template <typename DeformerT, typename TreeT, typename FilterT>
206 {
207  using LeafT = typename TreeT::LeafNodeType;
208  using LeafArrayT = std::vector<LeafT*>;
210 
211  BuildMoveMapsOp(const DeformerT& deformer,
212  GlobalPointIndexMap& globalMoveLeafMap,
213  LocalPointIndexMap& localMoveLeafMap,
214  const LeafMap& targetLeafMap,
215  const math::Transform& targetTransform,
216  const math::Transform& sourceTransform,
217  const FilterT& filter)
218  : mDeformer(deformer)
219  , mGlobalMoveLeafMap(globalMoveLeafMap)
220  , mLocalMoveLeafMap(localMoveLeafMap)
221  , mTargetLeafMap(targetLeafMap)
222  , mTargetTransform(targetTransform)
223  , mSourceTransform(sourceTransform)
224  , mFilter(filter) { }
225 
226  void operator()(LeafT& leaf, size_t idx) const
227  {
228  DeformerT deformer(mDeformer);
229  deformer.reset(leaf, idx);
230 
231  // determine source leaf node origin and offset in the source leaf vector
232 
233  Coord sourceLeafOrigin = leaf.origin();
234 
235  auto sourceHandle = AttributeWriteHandle<Vec3f>::create(leaf.attributeArray("P"));
236 
237  for (auto iter = leaf.beginIndexOn(mFilter); iter; iter++) {
238 
239  const bool useIndexSpace = DeformerTraits<DeformerT>::IndexSpace;
240 
241  // extract index-space position and apply index-space deformation (if applicable)
242 
243  Vec3d positionIS = sourceHandle->get(*iter) + iter.getCoord().asVec3d();
244  if (useIndexSpace) {
245  deformer.apply(positionIS, iter);
246  }
247 
248  // transform to world-space position and apply world-space deformation (if applicable)
249 
250  Vec3d positionWS = mSourceTransform.indexToWorld(positionIS);
251  if (!useIndexSpace) {
252  deformer.apply(positionWS, iter);
253  }
254 
255  // transform to index-space position of target grid
256 
257  positionIS = mTargetTransform.worldToIndex(positionWS);
258 
259  // determine target voxel and offset
260 
261  Coord targetVoxel = Coord::round(positionIS);
262  Index targetOffset = LeafT::coordToOffset(targetVoxel);
263 
264  // set new local position in source transform space (if point has been deformed)
265 
266  Vec3d voxelPosition(positionIS - targetVoxel.asVec3d());
267  sourceHandle->set(*iter, voxelPosition);
268 
269  // determine target leaf node origin and offset in the target leaf vector
270 
271  Coord targetLeafOrigin = targetVoxel & ~(LeafT::DIM - 1);
272  assert(mTargetLeafMap.find(targetLeafOrigin) != mTargetLeafMap.end());
273  const LeafIndex targetLeafOffset(mTargetLeafMap.at(targetLeafOrigin));
274 
275  // insert into move map based on whether point ends up in a new leaf node or not
276 
277  if (targetLeafOrigin == sourceLeafOrigin) {
278  mLocalMoveLeafMap[targetLeafOffset].emplace_back(targetOffset, *iter);
279  }
280  else {
281  mGlobalMoveLeafMap[targetLeafOffset].push_back(IndexTriple(
282  LeafIndex(static_cast<LeafIndex>(idx)), targetOffset, *iter));
283  }
284  }
285  }
286 
287 private:
288  const DeformerT& mDeformer;
289  GlobalPointIndexMap& mGlobalMoveLeafMap;
290  LocalPointIndexMap& mLocalMoveLeafMap;
291  const LeafMap& mTargetLeafMap;
292  const math::Transform& mTargetTransform;
293  const math::Transform& mSourceTransform;
294  const FilterT& mFilter;
295 }; // struct BuildMoveMapsOp
296 
297 template <typename LeafT>
298 inline Index
299 indexOffsetFromVoxel(const Index voxelOffset, const LeafT& leaf, IndexArray& offsets)
300 {
301  // compute the target point index by summing the point index of the previous
302  // voxel with the current number of points added to this voxel, tracked by the
303  // offsets array
304 
305  Index targetOffset = offsets[voxelOffset]++;
306  if (voxelOffset > 0) {
307  targetOffset += static_cast<Index>(leaf.getValue(voxelOffset - 1));
308  }
309  return targetOffset;
310 }
311 
312 
313 #if OPENVDB_ABI_VERSION_NUMBER >= 6
314 
315 
316 template <typename TreeT>
317 struct GlobalMovePointsOp
318 {
319  using LeafT = typename TreeT::LeafNodeType;
320  using LeafArrayT = std::vector<LeafT*>;
321  using LeafManagerT = typename tree::LeafManager<TreeT>;
322  using AttributeArrays = std::vector<AttributeArray*>;
323 
325  LeafManagerT& sourceLeafManager,
326  const Index attributeIndex,
327  const GlobalPointIndexMap& moveLeafMap,
328  const GlobalPointIndexIndices& moveLeafIndices)
329  : mOffsetMap(offsetMap)
330  , mSourceLeafManager(sourceLeafManager)
331  , mAttributeIndex(attributeIndex)
332  , mMoveLeafMap(moveLeafMap)
333  , mMoveLeafIndices(moveLeafIndices) { }
334 
335  // A CopyIterator is designed to use the indices in a GlobalPointIndexMap for this leaf
336  // and match the interface required for AttributeArray::copyValues()
337  struct CopyIterator
338  {
339  CopyIterator(const LeafT& leaf, const IndexArray& sortedIndices,
340  const IndexTripleArray& moveIndices, IndexArray& offsets)
341  : mLeaf(leaf)
342  , mSortedIndices(sortedIndices)
343  , mMoveIndices(moveIndices)
344  , mOffsets(offsets) { }
345 
346  operator bool() const { return bool(mIt); }
347 
348  void reset(Index startIndex, Index endIndex)
349  {
350  mIndex = startIndex;
351  mEndIndex = endIndex;
352  this->advance();
353  }
354 
355  CopyIterator& operator++()
356  {
357  this->advance();
358  return *this;
359  }
360 
361  Index leafIndex(Index i) const
362  {
363  if (i < mSortedIndices.size()) {
364  return std::get<0>(this->leafIndexTriple(i));
365  }
367  }
368 
369  Index sourceIndex() const
370  {
371  assert(mIt);
372  return std::get<2>(*mIt);
373  }
374 
375  Index targetIndex() const
376  {
377  assert(mIt);
378  return indexOffsetFromVoxel(std::get<1>(*mIt), mLeaf, mOffsets);
379  }
380 
381  private:
382  void advance()
383  {
384  if (mIndex >= mEndIndex || mIndex >= mSortedIndices.size()) {
385  mIt = nullptr;
386  }
387  else {
388  mIt = &this->leafIndexTriple(mIndex);
389  }
390  ++mIndex;
391  }
392 
393  const IndexTriple& leafIndexTriple(Index i) const
394  {
395  return mMoveIndices[mSortedIndices[i]];
396  }
397 
398  private:
399  const LeafT& mLeaf;
400  Index mIndex;
401  Index mEndIndex;
402  const IndexArray& mSortedIndices;
403  const IndexTripleArray& mMoveIndices;
404  IndexArray& mOffsets;
405  const IndexTriple* mIt = nullptr;
406  }; // struct CopyIterator
407 
408  void operator()(LeafT& leaf, size_t idx) const
409  {
410  const IndexTripleArray& moveIndices = mMoveLeafMap[idx];
411  if (moveIndices.empty()) return;
412  const IndexArray& sortedIndices = mMoveLeafIndices[idx];
413 
414  // extract per-voxel offsets for this leaf
415 
416  LeafIndexArray& offsets = mOffsetMap[idx];
417 
418  // extract target array and ensure data is out-of-core and non-uniform
419 
420  auto& targetArray = leaf.attributeArray(mAttributeIndex);
421  targetArray.loadData();
422  targetArray.expand();
423 
424  // perform the copy
425 
426  CopyIterator copyIterator(leaf, sortedIndices, moveIndices, offsets);
427 
428  // use the sorted indices to track the index of the source leaf
429 
430  Index sourceLeafIndex = copyIterator.leafIndex(0);
431  Index startIndex = 0;
432 
433  for (size_t i = 1; i <= sortedIndices.size(); i++) {
434  Index endIndex = static_cast<Index>(i);
435  Index newSourceLeafIndex = copyIterator.leafIndex(endIndex);
436 
437  // when it changes, do a batch-copy of all the indices that lie within this range
438  // TODO: this step could use nested parallelization for cases where there are a
439  // large number of points being moved per attribute
440 
441  if (newSourceLeafIndex > sourceLeafIndex) {
442  copyIterator.reset(startIndex, endIndex);
443 
444  const LeafT& sourceLeaf = mSourceLeafManager.leaf(sourceLeafIndex);
445  const auto& sourceArray = sourceLeaf.constAttributeArray(mAttributeIndex);
446  sourceArray.loadData();
447 
448  targetArray.copyValuesUnsafe(sourceArray, copyIterator);
449 
450  sourceLeafIndex = newSourceLeafIndex;
451  startIndex = endIndex;
452  }
453  }
454  }
455 
456 private:
457  LeafOffsetArray& mOffsetMap;
458  LeafManagerT& mSourceLeafManager;
459  const Index mAttributeIndex;
460  const GlobalPointIndexMap& mMoveLeafMap;
461  const GlobalPointIndexIndices& mMoveLeafIndices;
462 }; // struct GlobalMovePointsOp
463 
464 
465 template <typename TreeT>
466 struct LocalMovePointsOp
467 {
468  using LeafT = typename TreeT::LeafNodeType;
469  using LeafArrayT = std::vector<LeafT*>;
470  using LeafManagerT = typename tree::LeafManager<TreeT>;
471  using AttributeArrays = std::vector<AttributeArray*>;
472 
474  const LeafIndexArray& sourceIndices,
475  LeafManagerT& sourceLeafManager,
476  const Index attributeIndex,
477  const LocalPointIndexMap& moveLeafMap)
478  : mOffsetMap(offsetMap)
479  , mSourceIndices(sourceIndices)
480  , mSourceLeafManager(sourceLeafManager)
481  , mAttributeIndex(attributeIndex)
482  , mMoveLeafMap(moveLeafMap) { }
483 
484  // A CopyIterator is designed to use the indices in a LocalPointIndexMap for this leaf
485  // and match the interface required for AttributeArray::copyValues()
486  struct CopyIterator
487  {
488  CopyIterator(const LeafT& leaf, const IndexPairArray& indices, IndexArray& offsets)
489  : mLeaf(leaf)
490  , mIndices(indices)
491  , mOffsets(offsets) { }
492 
493  operator bool() const { return mIndex < static_cast<int>(mIndices.size()); }
494 
495  CopyIterator& operator++() { ++mIndex; return *this; }
496 
497  Index sourceIndex() const
498  {
499  return mIndices[mIndex].second;
500  }
501 
502  Index targetIndex() const
503  {
504  return indexOffsetFromVoxel(mIndices[mIndex].first, mLeaf, mOffsets);
505  }
506 
507  private:
508  const LeafT& mLeaf;
509  const IndexPairArray& mIndices;
510  IndexArray& mOffsets;
511  int mIndex = 0;
512  }; // struct CopyIterator
513 
514  void operator()(LeafT& leaf, size_t idx) const
515  {
516  const IndexPairArray& moveIndices = mMoveLeafMap[idx];
517  if (moveIndices.empty()) return;
518 
519  // extract per-voxel offsets for this leaf
520 
521  LeafIndexArray& offsets = mOffsetMap[idx];
522 
523  // extract source array that has the same origin as the target leaf
524 
525  assert(idx < mSourceIndices.size());
526  const Index sourceLeafOffset(mSourceIndices[idx]);
527  LeafT& sourceLeaf = mSourceLeafManager.leaf(sourceLeafOffset);
528  const auto& sourceArray = sourceLeaf.constAttributeArray(mAttributeIndex);
529  sourceArray.loadData();
530 
531  // extract target array and ensure data is out-of-core and non-uniform
532 
533  auto& targetArray = leaf.attributeArray(mAttributeIndex);
534  targetArray.loadData();
535  targetArray.expand();
536 
537  // perform the copy
538 
539  CopyIterator copyIterator(leaf, moveIndices, offsets);
540  targetArray.copyValuesUnsafe(sourceArray, copyIterator);
541  }
542 
543 private:
544  LeafOffsetArray& mOffsetMap;
545  const LeafIndexArray& mSourceIndices;
546  LeafManagerT& mSourceLeafManager;
547  const Index mAttributeIndex;
548  const LocalPointIndexMap& mMoveLeafMap;
549 }; // struct LocalMovePointsOp
550 
551 
552 #else
553 
554 
555 // The following infrastructure - ArrayProcessor, PerformTypedMoveOp, processTypedArray()
556 // is required to improve AttributeArray copying performance beyond using the virtual function
557 // AttributeArray::set(Index, AttributeArray&, Index). An ABI=6 addition to AttributeArray
558 // improves this by introducing an AttributeArray::copyValues() method to significantly
559 // simplify this logic without incurring the same virtual function cost.
560 
561 
562 /// Helper class used internally by processTypedArray()
563 template<typename ValueType, typename OpType>
565  static inline void call(OpType& op, const AttributeArray& array) {
566 #ifdef _MSC_VER
567  op.operator()<ValueType>(array);
568 #else
569  op.template operator()<ValueType>(array);
570 #endif
571  }
572 };
573 
574 
575 /// @brief Utility function that, given a generic attribute array,
576 /// calls a functor with the fully-resolved value type of the array
577 template<typename ArrayType, typename OpType>
578 bool
579 processTypedArray(const ArrayType& array, OpType& op)
580 {
581  using namespace openvdb;
582  using namespace openvdb::math;
583  if (array.template hasValueType<bool>()) ArrayProcessor<bool, OpType>::call(op, array);
584  else if (array.template hasValueType<int16_t>()) ArrayProcessor<int16_t, OpType>::call(op, array);
585  else if (array.template hasValueType<int32_t>()) ArrayProcessor<int32_t, OpType>::call(op, array);
586  else if (array.template hasValueType<int64_t>()) ArrayProcessor<int64_t, OpType>::call(op, array);
587  else if (array.template hasValueType<float>()) ArrayProcessor<float, OpType>::call(op, array);
588  else if (array.template hasValueType<double>()) ArrayProcessor<double, OpType>::call(op, array);
589  else if (array.template hasValueType<Vec3<int32_t>>()) ArrayProcessor<Vec3<int32_t>, OpType>::call(op, array);
590  else if (array.template hasValueType<Vec3<float>>()) ArrayProcessor<Vec3<float>, OpType>::call(op, array);
591  else if (array.template hasValueType<Vec3<double>>()) ArrayProcessor<Vec3<double>, OpType>::call(op, array);
592  else if (array.template hasValueType<GroupType>()) ArrayProcessor<GroupType, OpType>::call(op, array);
593  else if (array.template hasValueType<StringIndexType>()) ArrayProcessor<StringIndexType, OpType>::call(op, array);
594  else if (array.template hasValueType<Mat3<float>>()) ArrayProcessor<Mat3<float>, OpType>::call(op, array);
595  else if (array.template hasValueType<Mat3<double>>()) ArrayProcessor<Mat3<double>, OpType>::call(op, array);
596  else if (array.template hasValueType<Mat4<float>>()) ArrayProcessor<Mat4<float>, OpType>::call(op, array);
597  else if (array.template hasValueType<Mat4<double>>()) ArrayProcessor<Mat4<double>, OpType>::call(op, array);
598  else if (array.template hasValueType<Quat<float>>()) ArrayProcessor<Quat<float>, OpType>::call(op, array);
599  else if (array.template hasValueType<Quat<double>>()) ArrayProcessor<Quat<double>, OpType>::call(op, array);
600  else return false;
601  return true;
602 }
603 
604 
605 /// Cache read and write attribute handles to amortize construction cost
607 {
608  using HandleArray = std::vector<AttributeHandle<int>::Ptr>;
609 
610  AttributeHandles(const size_t size)
611  : mHandles() { mHandles.reserve(size); }
612 
613  AttributeArray& getArray(const Index leafOffset)
614  {
615  auto* handle = reinterpret_cast<AttributeWriteHandle<int>*>(mHandles[leafOffset].get());
616  assert(handle);
617  return handle->array();
618  }
619 
620  const AttributeArray& getConstArray(const Index leafOffset) const
621  {
622  const auto* handle = mHandles[leafOffset].get();
623  assert(handle);
624  return handle->array();
625  }
626 
627  template <typename ValueT>
629  {
630  auto* handle = reinterpret_cast<AttributeHandle<ValueT>*>(mHandles[leafOffset].get());
631  assert(handle);
632  return *handle;
633  }
634 
635  template <typename ValueT>
637  {
638  auto* handle = reinterpret_cast<AttributeWriteHandle<ValueT>*>(mHandles[leafOffset].get());
639  assert(handle);
640  return *handle;
641  }
642 
643  /// Create a handle and reinterpret cast as an int handle to store
645  {
647  : mHandles(handles) { }
648 
649  template<typename ValueT>
650  void operator()(const AttributeArray& array) const
651  {
652  auto* handleAsInt = reinterpret_cast<AttributeHandle<int>*>(
654  mHandles.emplace_back(handleAsInt);
655  }
656 
657  private:
658  HandleArray& mHandles;
659  }; // struct CacheHandleOp
660 
661  template <typename LeafRangeT>
662  void cache(const LeafRangeT& range, const Index attributeIndex)
663  {
664  using namespace openvdb::math;
665 
666  mHandles.clear();
667  CacheHandleOp op(mHandles);
668 
669  for (auto leaf = range.begin(); leaf; ++leaf) {
670  const auto& array = leaf->constAttributeArray(attributeIndex);
672  }
673  }
674 
675 private:
676  HandleArray mHandles;
677 }; // struct AttributeHandles
678 
679 
680 template <typename TreeT>
682 {
683  using LeafT = typename TreeT::LeafNodeType;
684  using LeafArrayT = std::vector<LeafT*>;
686 
688  AttributeHandles& targetHandles,
689  AttributeHandles& sourceHandles,
690  const Index attributeIndex,
691  const GlobalPointIndexMap& moveLeafMap,
692  const GlobalPointIndexIndices& moveLeafIndices)
693  : mOffsetMap(offsetMap)
694  , mTargetHandles(targetHandles)
695  , mSourceHandles(sourceHandles)
696  , mAttributeIndex(attributeIndex)
697  , mMoveLeafMap(moveLeafMap)
698  , mMoveLeafIndices(moveLeafIndices) { }
699 
701  {
702  PerformTypedMoveOp(AttributeHandles& targetHandles, AttributeHandles& sourceHandles,
703  Index targetOffset, const LeafT& targetLeaf,
704  IndexArray& offsets, const IndexTripleArray& indices,
705  const IndexArray& sortedIndices)
706  : mTargetHandles(targetHandles)
707  , mSourceHandles(sourceHandles)
708  , mTargetOffset(targetOffset)
709  , mTargetLeaf(targetLeaf)
710  , mOffsets(offsets)
711  , mIndices(indices)
712  , mSortedIndices(sortedIndices) { }
713 
714  template<typename ValueT>
715  void operator()(const AttributeArray&) const
716  {
717  auto& targetHandle = mTargetHandles.getWriteHandle<ValueT>(mTargetOffset);
718  targetHandle.expand();
719 
720  for (const auto& index : mSortedIndices) {
721  const auto& it = mIndices[index];
722  const auto& sourceHandle = mSourceHandles.getHandle<ValueT>(std::get<0>(it));
723  const Index targetIndex = indexOffsetFromVoxel(std::get<1>(it), mTargetLeaf, mOffsets);
724  for (Index i = 0; i < sourceHandle.stride(); i++) {
725  ValueT sourceValue = sourceHandle.get(std::get<2>(it), i);
726  targetHandle.set(targetIndex, i, sourceValue);
727  }
728  }
729  }
730 
731  private:
732  AttributeHandles& mTargetHandles;
733  AttributeHandles& mSourceHandles;
734  Index mTargetOffset;
735  const LeafT& mTargetLeaf;
736  IndexArray& mOffsets;
737  const IndexTripleArray& mIndices;
738  const IndexArray& mSortedIndices;
739  }; // struct PerformTypedMoveOp
740 
741  void performMove(Index targetOffset, const LeafT& targetLeaf,
742  IndexArray& offsets, const IndexTripleArray& indices,
743  const IndexArray& sortedIndices) const
744  {
745  auto& targetArray = mTargetHandles.getArray(targetOffset);
746  targetArray.loadData();
747  targetArray.expand();
748 
749  for (const auto& index : sortedIndices) {
750  const auto& it = indices[index];
751 
752  const auto& sourceArray = mSourceHandles.getConstArray(std::get<0>(it));
753 
754  const Index sourceOffset = std::get<2>(it);
755  const Index targetOffset = indexOffsetFromVoxel(std::get<1>(it), targetLeaf, offsets);
756 
757  targetArray.set(targetOffset, sourceArray, sourceOffset);
758  }
759  }
760 
761  void operator()(LeafT& leaf, size_t aIdx) const
762  {
763  const Index idx(static_cast<Index>(aIdx));
764  const auto& moveIndices = mMoveLeafMap[aIdx];
765  if (moveIndices.empty()) return;
766  const auto& sortedIndices = mMoveLeafIndices[aIdx];
767 
768  // extract per-voxel offsets for this leaf
769 
770  auto& offsets = mOffsetMap[aIdx];
771 
772  const auto& array = leaf.constAttributeArray(mAttributeIndex);
773 
774  PerformTypedMoveOp op(mTargetHandles, mSourceHandles, idx, leaf, offsets,
775  moveIndices, sortedIndices);
776  if (!processTypedArray(array, op)) {
777  this->performMove(idx, leaf, offsets, moveIndices, sortedIndices);
778  }
779  }
780 
781 private:
782  LeafOffsetArray& mOffsetMap;
783  AttributeHandles& mTargetHandles;
784  AttributeHandles& mSourceHandles;
785  const Index mAttributeIndex;
786  const GlobalPointIndexMap& mMoveLeafMap;
787  const GlobalPointIndexIndices& mMoveLeafIndices;
788 }; // struct GlobalMovePointsOp
789 
790 
791 template <typename TreeT>
793 {
794  using LeafT = typename TreeT::LeafNodeType;
795  using LeafArrayT = std::vector<LeafT*>;
797 
799  AttributeHandles& targetHandles,
800  const LeafIndexArray& sourceIndices,
801  AttributeHandles& sourceHandles,
802  const Index attributeIndex,
803  const LocalPointIndexMap& moveLeafMap)
804  : mOffsetMap(offsetMap)
805  , mTargetHandles(targetHandles)
806  , mSourceIndices(sourceIndices)
807  , mSourceHandles(sourceHandles)
808  , mAttributeIndex(attributeIndex)
809  , mMoveLeafMap(moveLeafMap) { }
810 
812  {
813  PerformTypedMoveOp(AttributeHandles& targetHandles, AttributeHandles& sourceHandles,
814  Index targetOffset, Index sourceOffset, const LeafT& targetLeaf,
815  IndexArray& offsets, const IndexPairArray& indices)
816  : mTargetHandles(targetHandles)
817  , mSourceHandles(sourceHandles)
818  , mTargetOffset(targetOffset)
819  , mSourceOffset(sourceOffset)
820  , mTargetLeaf(targetLeaf)
821  , mOffsets(offsets)
822  , mIndices(indices) { }
823 
824  template<typename ValueT>
825  void operator()(const AttributeArray&) const
826  {
827  auto& targetHandle = mTargetHandles.getWriteHandle<ValueT>(mTargetOffset);
828  const auto& sourceHandle = mSourceHandles.getHandle<ValueT>(mSourceOffset);
829 
830  targetHandle.expand();
831 
832  for (const auto& it : mIndices) {
833  const Index targetIndex = indexOffsetFromVoxel(it.first, mTargetLeaf, mOffsets);
834  for (Index i = 0; i < sourceHandle.stride(); i++) {
835  ValueT sourceValue = sourceHandle.get(it.second, i);
836  targetHandle.set(targetIndex, i, sourceValue);
837  }
838  }
839  }
840 
841  private:
842  AttributeHandles& mTargetHandles;
843  AttributeHandles& mSourceHandles;
844  Index mTargetOffset;
845  Index mSourceOffset;
846  const LeafT& mTargetLeaf;
847  IndexArray& mOffsets;
848  const IndexPairArray& mIndices;
849  }; // struct PerformTypedMoveOp
850 
851  template <typename ValueT>
852  void performTypedMove(Index sourceOffset, Index targetOffset, const LeafT& targetLeaf,
853  IndexArray& offsets, const IndexPairArray& indices) const
854  {
855  auto& targetHandle = mTargetHandles.getWriteHandle<ValueT>(targetOffset);
856  const auto& sourceHandle = mSourceHandles.getHandle<ValueT>(sourceOffset);
857 
858  targetHandle.expand();
859 
860  for (const auto& it : indices) {
861  const Index tgtOffset = indexOffsetFromVoxel(it.first, targetLeaf, offsets);
862  for (Index i = 0; i < sourceHandle.stride(); i++) {
863  ValueT sourceValue = sourceHandle.get(it.second, i);
864  targetHandle.set(tgtOffset, i, sourceValue);
865  }
866  }
867  }
868 
869  void performMove(Index targetOffset, Index sourceOffset, const LeafT& targetLeaf,
870  IndexArray& offsets, const IndexPairArray& indices) const
871  {
872  auto& targetArray = mTargetHandles.getArray(targetOffset);
873  const auto& sourceArray = mSourceHandles.getConstArray(sourceOffset);
874 
875  for (const auto& it : indices) {
876  const Index sourceOffset = it.second;
877  const Index targetOffset = indexOffsetFromVoxel(it.first, targetLeaf, offsets);
878 
879  targetArray.set(targetOffset, sourceArray, sourceOffset);
880  }
881  }
882 
883  void operator()(const LeafT& leaf, size_t aIdx) const
884  {
885  const Index idx(static_cast<Index>(aIdx));
886  const auto& moveIndices = mMoveLeafMap.at(aIdx);
887  if (moveIndices.empty()) return;
888 
889  // extract target leaf and per-voxel offsets for this leaf
890 
891  auto& offsets = mOffsetMap[aIdx];
892 
893  // extract source leaf that has the same origin as the target leaf (if any)
894 
895  assert(aIdx < mSourceIndices.size());
896  const Index sourceOffset(mSourceIndices[aIdx]);
897 
898  const auto& array = leaf.constAttributeArray(mAttributeIndex);
899 
900  PerformTypedMoveOp op(mTargetHandles, mSourceHandles,
901  idx, sourceOffset, leaf, offsets, moveIndices);
902  if (!processTypedArray(array, op)) {
903  this->performMove(idx, sourceOffset, leaf, offsets, moveIndices);
904  }
905  }
906 
907 private:
908  LeafOffsetArray& mOffsetMap;
909  AttributeHandles& mTargetHandles;
910  const LeafIndexArray& mSourceIndices;
911  AttributeHandles& mSourceHandles;
912  const Index mAttributeIndex;
913  const LocalPointIndexMap& mMoveLeafMap;
914 }; // struct LocalMovePointsOp
915 
916 
917 #endif // OPENVDB_ABI_VERSION_NUMBER >= 6
918 
919 
920 } // namespace point_move_internal
921 
922 
923 ////////////////////////////////////////
924 
925 
926 template <typename PointDataGridT, typename DeformerT, typename FilterT>
927 inline void movePoints( PointDataGridT& points,
928  const math::Transform& transform,
929  DeformerT& deformer,
930  const FilterT& filter,
931  future::Advect* objectNotInUse,
932  bool threaded)
933 {
935  using PointDataTreeT = typename PointDataGridT::TreeType;
936  using LeafT = typename PointDataTreeT::LeafNodeType;
937  using LeafManagerT = typename tree::LeafManager<PointDataTreeT>;
938 
939  using namespace point_move_internal;
940 
941  // this object is for future use only
942  assert(!objectNotInUse);
943  (void)objectNotInUse;
944 
945  PointDataTreeT& tree = points.tree();
946 
947  // early exit if no LeafNodes
948 
949  PointDataTree::LeafCIter iter = tree.cbeginLeaf();
950 
951  if (!iter) return;
952 
953  // build voxel topology taking into account any point group deletion
954 
955  auto newPoints = point_mask_internal::convertPointsToScalar<PointDataGrid>(
956  points, transform, filter, deformer, threaded);
957  auto& newTree = newPoints->tree();
958 
959  // create leaf managers for both trees
960 
961  LeafManagerT sourceLeafManager(tree);
962  LeafManagerT targetLeafManager(newTree);
963 
964  // extract the existing attribute set
965  const auto& existingAttributeSet = points.tree().cbeginLeaf()->attributeSet();
966 
967  // build a coord -> index map for looking up target leafs by origin and a faster
968  // unordered map for finding the source index from a target index
969 
970  LeafMap targetLeafMap;
971  LeafIndexArray sourceIndices(targetLeafManager.leafCount(),
973 
974  LeafOffsetArray offsetMap(targetLeafManager.leafCount());
975 
976  {
977  LeafMap sourceLeafMap;
978  auto sourceRange = sourceLeafManager.leafRange();
979  for (auto leaf = sourceRange.begin(); leaf; ++leaf) {
980  sourceLeafMap.insert({leaf->origin(), LeafIndex(static_cast<LeafIndex>(leaf.pos()))});
981  }
982  auto targetRange = targetLeafManager.leafRange();
983  for (auto leaf = targetRange.begin(); leaf; ++leaf) {
984  targetLeafMap.insert({leaf->origin(), LeafIndex(static_cast<LeafIndex>(leaf.pos()))});
985  }
986 
987  // acquire registry lock to avoid locking when appending attributes in parallel
988 
990 
991  // perform four independent per-leaf operations in parallel
992  targetLeafManager.foreach(
993  [&](LeafT& leaf, size_t idx) {
994  // map frequency => cumulative histogram
995  auto* buffer = leaf.buffer().data();
996  for (Index i = 1; i < leaf.buffer().size(); i++) {
997  buffer[i] = buffer[i-1] + buffer[i];
998  }
999  // replace attribute set with a copy of the existing one
1000  leaf.replaceAttributeSet(
1001  new AttributeSet(existingAttributeSet, leaf.getLastValue(), &lock),
1002  /*allowMismatchingDescriptors=*/true);
1003  // store the index of the source leaf in a corresponding target leaf array
1004  const auto it = sourceLeafMap.find(leaf.origin());
1005  if (it != sourceLeafMap.end()) {
1006  sourceIndices[idx] = it->second;
1007  }
1008  // allocate offset maps
1009  offsetMap[idx].resize(LeafT::SIZE);
1010  },
1011  threaded);
1012  }
1013 
1014  // moving leaf
1015 
1016  GlobalPointIndexMap globalMoveLeafMap(targetLeafManager.leafCount());
1017  LocalPointIndexMap localMoveLeafMap(targetLeafManager.leafCount());
1018 
1019  // build global and local move leaf maps and update local positions
1020 
1021  if (filter.state() == index::ALL) {
1022  NullFilter nullFilter;
1023  BuildMoveMapsOp<DeformerT, PointDataTreeT, NullFilter> op(deformer,
1024  globalMoveLeafMap, localMoveLeafMap, targetLeafMap,
1025  transform, points.transform(), nullFilter);
1026  sourceLeafManager.foreach(op, threaded);
1027  } else {
1028  BuildMoveMapsOp<DeformerT, PointDataTreeT, FilterT> op(deformer,
1029  globalMoveLeafMap, localMoveLeafMap, targetLeafMap,
1030  transform, points.transform(), filter);
1031  sourceLeafManager.foreach(op, threaded);
1032  }
1033 
1034  // build a sorted index vector for each leaf that references the global move map
1035  // indices in order of their source leafs and voxels to ensure determinism in the
1036  // resulting point orders
1037 
1038  GlobalPointIndexIndices globalMoveLeafIndices(globalMoveLeafMap.size());
1039 
1040  targetLeafManager.foreach(
1041  [&](LeafT& /*leaf*/, size_t idx) {
1042  const IndexTripleArray& moveIndices = globalMoveLeafMap[idx];
1043  if (moveIndices.empty()) return;
1044 
1045  IndexArray& sortedIndices = globalMoveLeafIndices[idx];
1046  sortedIndices.resize(moveIndices.size());
1047  std::iota(std::begin(sortedIndices), std::end(sortedIndices), 0);
1048  std::sort(std::begin(sortedIndices), std::end(sortedIndices),
1049  [&](int i, int j)
1050  {
1051  const Index& indexI0(std::get<0>(moveIndices[i]));
1052  const Index& indexJ0(std::get<0>(moveIndices[j]));
1053  if (indexI0 < indexJ0) return true;
1054  if (indexI0 > indexJ0) return false;
1055  return std::get<2>(moveIndices[i]) < std::get<2>(moveIndices[j]);
1056  }
1057  );
1058  },
1059  threaded);
1060 
1061 #if OPENVDB_ABI_VERSION_NUMBER < 6
1062  // initialize attribute handles
1063  AttributeHandles sourceHandles(sourceLeafManager.leafCount());
1064  AttributeHandles targetHandles(targetLeafManager.leafCount());
1065 #endif
1066 
1067  for (const auto& it : existingAttributeSet.descriptor().map()) {
1068 
1069  const Index attributeIndex = static_cast<Index>(it.second);
1070 
1071  // zero offsets
1072  targetLeafManager.foreach(
1073  [&offsetMap](const LeafT& /*leaf*/, size_t idx) {
1074  std::fill(offsetMap[idx].begin(), offsetMap[idx].end(), 0);
1075  },
1076  threaded);
1077 
1078 #if OPENVDB_ABI_VERSION_NUMBER >= 6
1079 
1080  // move points between leaf nodes
1081 
1082  GlobalMovePointsOp<PointDataTreeT> globalMoveOp(offsetMap,
1083  sourceLeafManager, attributeIndex, globalMoveLeafMap, globalMoveLeafIndices);
1084  targetLeafManager.foreach(globalMoveOp, threaded);
1085 
1086  // move points within leaf nodes
1087 
1088  LocalMovePointsOp<PointDataTreeT> localMoveOp(offsetMap,
1089  sourceIndices, sourceLeafManager, attributeIndex, localMoveLeafMap);
1090  targetLeafManager.foreach(localMoveOp, threaded);
1091 #else
1092  // cache attribute handles
1093 
1094  sourceHandles.cache(sourceLeafManager.leafRange(), attributeIndex);
1095  targetHandles.cache(targetLeafManager.leafRange(), attributeIndex);
1096 
1097  // move points between leaf nodes
1098 
1099  GlobalMovePointsOp<PointDataTreeT> globalMoveOp(offsetMap, targetHandles,
1100  sourceHandles, attributeIndex, globalMoveLeafMap, globalMoveLeafIndices);
1101  targetLeafManager.foreach(globalMoveOp, threaded);
1102 
1103  // move points within leaf nodes
1104 
1105  LocalMovePointsOp<PointDataTreeT> localMoveOp(offsetMap, targetHandles,
1106  sourceIndices, sourceHandles,
1107  attributeIndex, localMoveLeafMap);
1108  targetLeafManager.foreach(localMoveOp, threaded);
1109 #endif // OPENVDB_ABI_VERSION_NUMBER >= 6
1110  }
1111 
1112  points.setTree(newPoints->treePtr());
1113 }
1114 
1115 
1116 template <typename PointDataGridT, typename DeformerT, typename FilterT>
1117 inline void movePoints( PointDataGridT& points,
1118  DeformerT& deformer,
1119  const FilterT& filter,
1120  future::Advect* objectNotInUse,
1121  bool threaded)
1122 {
1123  movePoints(points, points.transform(), deformer, filter, objectNotInUse, threaded);
1124 }
1125 
1126 
1127 ////////////////////////////////////////
1128 
1129 
1130 template <typename T>
1132  : mCache(cache) { }
1133 
1134 
1135 template <typename T>
1136 template <typename PointDataGridT, typename DeformerT, typename FilterT>
1137 void CachedDeformer<T>::evaluate(PointDataGridT& grid, DeformerT& deformer, const FilterT& filter,
1138  bool threaded)
1139 {
1140  using TreeT = typename PointDataGridT::TreeType;
1141  using LeafT = typename TreeT::LeafNodeType;
1142  using LeafManagerT = typename tree::LeafManager<TreeT>;
1143  LeafManagerT leafManager(grid.tree());
1144 
1145  // initialize cache
1146  auto& leafs = mCache.leafs;
1147  leafs.resize(leafManager.leafCount());
1148 
1149  const auto& transform = grid.transform();
1150 
1151  // insert deformed positions into the cache
1152 
1153  auto cachePositionsOp = [&](const LeafT& leaf, size_t idx) {
1154 
1155  const Index64 totalPointCount = leaf.pointCount();
1156  if (totalPointCount == 0) return;
1157 
1158  // deformer is copied to ensure that it is unique per-thread
1159 
1160  DeformerT newDeformer(deformer);
1161 
1162  newDeformer.reset(leaf, idx);
1163 
1164  auto handle = AttributeHandle<Vec3f>::create(leaf.constAttributeArray("P"));
1165 
1166  auto& cache = leafs[idx];
1167  cache.clear();
1168 
1169  // only insert into a vector directly if the filter evaluates all points
1170  // and all points are stored in active voxels
1171  const bool useVector = filter.state() == index::ALL &&
1172  (leaf.isDense() || (leaf.onPointCount() == leaf.pointCount()));
1173  if (useVector) {
1174  cache.vecData.resize(totalPointCount);
1175  }
1176 
1177  for (auto iter = leaf.beginIndexOn(filter); iter; iter++) {
1178 
1179  // extract index-space position and apply index-space deformation (if defined)
1180 
1181  Vec3d position = handle->get(*iter) + iter.getCoord().asVec3d();
1182 
1183  // if deformer is designed to be used in index-space, perform deformation prior
1184  // to transforming position to world-space, otherwise perform deformation afterwards
1185 
1187  newDeformer.apply(position, iter);
1188  position = transform.indexToWorld(position);
1189  }
1190  else {
1191  position = transform.indexToWorld(position);
1192  newDeformer.apply(position, iter);
1193  }
1194 
1195  // insert new position into the cache
1196 
1197  if (useVector) {
1198  cache.vecData[*iter] = static_cast<Vec3T>(position);
1199  }
1200  else {
1201  cache.mapData.insert({*iter, static_cast<Vec3T>(position)});
1202  }
1203  }
1204 
1205  // store the total number of points to allow use of an expanded vector on access
1206 
1207  if (!cache.mapData.empty()) {
1208  cache.totalSize = static_cast<Index>(totalPointCount);
1209  }
1210  };
1211 
1212  leafManager.foreach(cachePositionsOp, threaded);
1213 }
1214 
1215 
1216 template <typename T>
1217 template <typename LeafT>
1218 void CachedDeformer<T>::reset(const LeafT& /*leaf*/, size_t idx)
1219 {
1220  if (idx >= mCache.leafs.size()) {
1221  if (mCache.leafs.empty()) {
1222  throw IndexError("No leafs in cache, perhaps CachedDeformer has not been evaluated?");
1223  } else {
1224  throw IndexError("Leaf index is out-of-range of cache leafs.");
1225  }
1226  }
1227  auto& cache = mCache.leafs[idx];
1228  if (!cache.mapData.empty()) {
1229  mLeafMap = &cache.mapData;
1230  mLeafVec = nullptr;
1231  }
1232  else {
1233  mLeafVec = &cache.vecData;
1234  mLeafMap = nullptr;
1235  }
1236 }
1237 
1238 
1239 template <typename T>
1240 template <typename IndexIterT>
1241 void CachedDeformer<T>::apply(Vec3d& position, const IndexIterT& iter) const
1242 {
1243  assert(*iter >= 0);
1244 
1245  if (mLeafMap) {
1246  auto it = mLeafMap->find(*iter);
1247  if (it == mLeafMap->end()) return;
1248  position = static_cast<openvdb::Vec3d>(it->second);
1249  }
1250  else {
1251  assert(mLeafVec);
1252 
1253  if (mLeafVec->empty()) return;
1254  assert(*iter < mLeafVec->size());
1255  position = static_cast<openvdb::Vec3d>((*mLeafVec)[*iter]);
1256  }
1257 }
1258 
1259 
1260 } // namespace points
1261 } // namespace OPENVDB_VERSION_NAME
1262 } // namespace openvdb
1263 
1264 #endif // OPENVDB_POINTS_POINT_MOVE_HAS_BEEN_INCLUDED
1265 
1266 // Copyright (c) DreamWorks Animation LLC
1267 // All rights reserved. This software is distributed under the
1268 // Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ )
vint4 max(const vint4 &a, const vint4 &b)
Definition: simd.h:4703
GLenum GLint * range
Definition: glew.h:3500
void movePoints(PointDataGridT &points, DeformerT &deformer, const FilterT &filter=NullFilter(), future::Advect *objectNotInUse=nullptr, bool threaded=true)
Move points in a PointDataGrid using a custom deformer.
Definition: PointMove.h:1117
GLsizeiptr size
Definition: glew.h:1681
Vec3d indexToWorld(const Vec3d &xyz) const
Apply this transformation to the given coordinates.
Definition: Transform.h:135
void cache(const LeafRangeT &range, const Index attributeIndex)
Definition: PointMove.h:662
Helper class used internally by processTypedArray()
Definition: PointMove.h:564
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
ImageBuf OIIO_API fill(cspan< float > values, ROI roi, int nthreads=0)
GLuint GLsizei const GLuint const GLintptr * offsets
Definition: glew.h:4117
std::unordered_map< LeafIndex, Vec3T > LeafMapT
Definition: PointMove.h:131
const GLint * first
Definition: glew.h:1528
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:200
AttributeHandle< ValueT > & getHandle(const Index leafOffset)
Definition: PointMove.h:628
void apply(Vec3d &position, const IndexIterT &iter) const
Retrieve the new position from the cache.
Definition: PointMove.h:1241
GLboolean reset
Definition: glew.h:4959
GlobalMovePointsOp(LeafOffsetArray &offsetMap, AttributeHandles &targetHandles, AttributeHandles &sourceHandles, const Index attributeIndex, const GlobalPointIndexMap &moveLeafMap, const GlobalPointIndexIndices &moveLeafIndices)
Definition: PointMove.h:687
A no-op filter that can be used when iterating over all indices.
Definition: IndexIterator.h:77
std::tuple< LeafIndex, Index, Index > IndexTriple
Definition: PointMove.h:190
static Ptr create(AttributeArray &array, const bool expand=true)
Cache read and write attribute handles to amortize construction cost.
Definition: PointMove.h:606
LocalMovePointsOp(LeafOffsetArray &offsetMap, AttributeHandles &targetHandles, const LeafIndexArray &sourceIndices, AttributeHandles &sourceHandles, const Index attributeIndex, const LocalPointIndexMap &moveLeafMap)
Definition: PointMove.h:798
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
Definition: glew.h:2981
Base class for storing attribute data.
void performTypedMove(Index sourceOffset, Index targetOffset, const LeafT &targetLeaf, IndexArray &offsets, const IndexPairArray &indices) const
Definition: PointMove.h:852
void reset(const LeafT &leaf, size_t idx)
Definition: PointMove.h:1218
CachedDeformer(Cache &cache)
Cache is expected to be persistent for the lifetime of the CachedDeformer.
Definition: PointMove.h:1131
tbb::concurrent_vector< IndexTriple > IndexTripleArray
Definition: PointMove.h:191
Index indexOffsetFromVoxel(const Index voxelOffset, const LeafT &leaf, IndexArray &offsets)
Definition: PointMove.h:299
void clear()
clear data buffers and reset counter
Definition: PointMove.h:139
A Deformer that caches the resulting positions from evaluating another Deformer.
Definition: PointMove.h:125
GLuint buffer
Definition: glew.h:1680
Deformer Traits for optionally configuring deformers to be applied in index-space. The default is world-space.
Definition: PointMask.h:103
GLuint GLuint GLsizei GLenum const void * indices
Definition: glew.h:1253
GLuint GLuint end
Definition: glew.h:1253
void
Definition: png.h:1083
This class manages a linear array of pointers to a given tree's leaf nodes, as well as optional auxil...
Definition: LeafManager.h:109
void evaluate(PointDataGridT &grid, DeformerT &deformer, const FilterT &filter, bool threaded=true)
Definition: PointMove.h:1137
bool processTypedArray(const ArrayType &array, OpType &op)
Utility function that, given a generic attribute array, calls a functor with the fully-resolved value...
Definition: PointMove.h:579
void performMove(Index targetOffset, const LeafT &targetLeaf, IndexArray &offsets, const IndexTripleArray &indices, const IndexArray &sortedIndices) const
Definition: PointMove.h:741
std::unordered_map< Coord, LeafIndex > LeafMap
Definition: PointMove.h:201
Create a handle and reinterpret cast as an int handle to store.
Definition: PointMove.h:644
vfloat4 round(const vfloat4 &a)
Definition: simd.h:7186
AttributeWriteHandle< ValueT > & getWriteHandle(const Index leafOffset)
Definition: PointMove.h:636
std::vector< IndexTripleArray > GlobalPointIndexMap
Definition: PointMove.h:192
BuildMoveMapsOp(const DeformerT &deformer, GlobalPointIndexMap &globalMoveLeafMap, LocalPointIndexMap &localMoveLeafMap, const LeafMap &targetLeafMap, const math::Transform &targetTransform, const math::Transform &sourceTransform, const FilterT &filter)
Definition: PointMove.h:211
void performMove(Index targetOffset, Index sourceOffset, const LeafT &targetLeaf, IndexArray &offsets, const IndexPairArray &indices) const
Definition: PointMove.h:869
static Ptr create(const AttributeArray &array, const bool collapseOnDestruction=true)
static void call(OpType &op, const AttributeArray &array)
Definition: PointMove.h:565
const AttributeArray & getConstArray(const Index leafOffset) const
Definition: PointMove.h:620
PerformTypedMoveOp(AttributeHandles &targetHandles, AttributeHandles &sourceHandles, Index targetOffset, Index sourceOffset, const LeafT &targetLeaf, IndexArray &offsets, const IndexPairArray &indices)
Definition: PointMove.h:813
GLuint GLdouble GLdouble GLint GLint const GLdouble * points
Definition: glew.h:3446
Methods for extracting masks from VDB Point grids.
Ordered collection of uniquely-named attribute arrays.
Definition: AttributeSet.h:62
PerformTypedMoveOp(AttributeHandles &targetHandles, AttributeHandles &sourceHandles, Index targetOffset, const LeafT &targetLeaf, IndexArray &offsets, const IndexTripleArray &indices, const IndexArray &sortedIndices)
Definition: PointMove.h:702
#define SIZE
Definition: simple.C:40
GLenum array
Definition: glew.h:9066
Vec3d worldToIndex(const Vec3d &xyz) const
Apply this transformation to the given coordinates.
Definition: Transform.h:137
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h:146
void sort(I begin, I end, const Pred &pred)
Definition: pugixml.cpp:7334
Attribute-owned data structure for points. Point attributes are stored in leaf nodes and ordered by v...
Base class for tree-traversal iterators over all leaf nodes (but not leaf voxels) ...