HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
PointTransfer.h
Go to the documentation of this file.
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3 //
4 /// @author Nick Avramoussis
5 ///
6 /// @file PointTransfer.h
7 ///
8 /// @brief Framework methods for rasterizing PointDataGrid data to Trees.
9 ///
10 /// @details Provides a generic inherited interface for deriving transfer
11 /// schemes that represent how point data should be rasterized. The provided
12 /// components together support the transfer of multiple attributes to
13 /// arbitrary and multiple grid types. Target grids must have the same
14 /// transform, but this transform can differ from the source PointDataGrid
15 /// (multiple instantiations of rasterize() should instead be invoked to
16 /// transfer to grids of different transforms). Arbitrary attributes can be
17 /// accessed and transfered to arbitrary trees.
18 ///
19 
20 #ifndef OPENVEB_POINTS_TRANSFER_HAS_BEEN_INCLUDED
21 #define OPENVEB_POINTS_TRANSFER_HAS_BEEN_INCLUDED
22 
23 #include <openvdb/openvdb.h>
24 #include <openvdb/Types.h>
25 #include <openvdb/Grid.h>
26 #include <openvdb/math/Transform.h>
29 
30 #include <type_traits>
31 #include <tuple>
32 
33 namespace openvdb {
35 namespace OPENVDB_VERSION_NAME {
36 namespace points {
37 
38 /// @par A transfer scheme must be configured to call the provided
39 /// rasterize methods. See below for an example or
40 /// PointRasterizeSDF.h/PointRasterizeTrilinear.h for implementations.
41 /// @code
42 /// struct Transfer
43 /// {
44 /// /// @return Returns the tree topology to loop over. This can be different
45 /// /// from the destination tree i.e. This can act as a mask.
46 /// inline auto& topology();
47 ///
48 /// /// @brief The maximum lookup range of this transfer scheme in index
49 /// /// space of the source points.
50 /// /// @details The return value represent how far away from the destination
51 /// /// leaf node points should be accessed.
52 /// /// @param origin The leaf origin of the topology being accessed
53 /// /// @param idx The leaf index of the topology being accessed
54 /// inline Int32 range(const Coord& origin, size_t idx) const;
55 ///
56 /// /// @brief The initialize function, called on each leaf which has valid
57 /// /// topology to write to.
58 /// /// @param origin The leaf origin of the topology being accessed
59 /// /// @param idx The leaf index of the topology being accessed
60 /// /// @param bounds The active voxel bounds of the leaf
61 /// inline void initialize(const Coord& origin, size_t idx, const CoordBBox& bounds);
62 ///
63 /// /// @brief Run each time a point leaf is accessed. Typically this is
64 /// /// where attribute handles can be constructed
65 /// /// @param leaf The PointDataLeafNode which is being accessed.
66 /// /// @return Return true to continue rasterization, false to early exit
67 /// /// and skip the current leaf's contribution to the destination volume.
68 /// inline bool startPointLeaf(const PointDataTree::LeafNodeType& leaf);
69 ///
70 /// /// @brief The point stamp function. Each point which contributes to
71 /// /// the current leaf will call this function exactly once.
72 /// /// @param ijk The current voxel containing the point being rasterized.
73 /// /// May be outside the destination leaf node depending on the range()
74 /// /// @param id The point index being rasterized
75 /// /// @param bounds The active bounds of the leaf node.
76 /// void rasterizePoint(const Coord& ijk,
77 /// const Index id,
78 /// const CoordBBox& bounds);
79 ///
80 /// /// @brief Run each time a point leaf is finished with.
81 /// /// @param leaf The PointDataLeafNode which was being accessed.
82 /// /// @return Return true to continue rasterization, false to early exit
83 /// /// and stop rasterization to the destination leaf node.
84 /// inline bool endPointLeaf(const PointDataTree::LeafNodeType& leaf);
85 ///
86 /// /// @brief The finalization function for the given destination tree(s).
87 /// /// @param origin The leaf origin of the topology being accessed
88 /// /// @param idx The leaf index of the topology being accessed
89 /// /// @return Return true to stop, false to recursively rasterize
90 /// inline bool finalize(const Coord& origin, size_t idx);
91 /// };
92 /// @endcode
93 ///
94 ///
95 /// Below is a full example using the native components.
96 ///
97 /// @code
98 /// /// @brief Sum point distances into a target float tree
99 /// /// Note: Using TransformTransfer to handle different index spaces, and
100 /// /// VolumeTransfer for automatic buffer setup
101 /// struct MyTransfer :
102 /// public TransformTransfer,
103 /// public VolumeTransfer<FloatTree>
104 /// {
105 /// MyTransfer(FloatGrid& dest, const PointDataGrid& source)
106 /// : TransformTransfer(source.transform(), dest.transform())
107 /// , VolumeTransfer(dest.tree())
108 /// , mHandle(nullptr) {}
109 ///
110 /// MyTransfer(const MyTransfer& other)
111 /// : TransformTransfer(other)
112 /// , VolumeTransfer(other)
113 /// , mHandle(nullptr) {}
114 ///
115 /// /// @brief Range in index space of the source points
116 /// Int32 range(const Coord&, size_t) const { return Int32(1); }
117 ///
118 /// /// @brief Every time we start a new point leaf, init the position array.
119 /// /// Always return true as we don't skip any leaf nodes.
120 /// bool startPointLeaf(const PointDataTree::LeafNodeType& leaf)
121 /// {
122 /// mHandle.reset(new AttributeHandle<Vec3f>(leaf.constAttributeArray("P"));
123 /// return true;
124 /// }
125 ///
126 /// /// @brief For each point, compute its relative index space position in
127 /// /// the destination tree and sum the length of its distance
128 /// void rasterizePoint(const Coord& ijk, const Index id, const CoordBBox& bounds)
129 /// {
130 /// Vec3d P = ijk.asVec3d() + Vec3d(this->mHandle->get(id));
131 /// P = this->transformSourceToTarget(P); // TransformTransfer::transformSourceToTarget
132 /// // for each active voxel, accumulate distance
133 /// const auto* mask = this->mask(); // VolumeTransfer::mask
134 /// for (auto& coord : bounds) {
135 /// const Index voxel = FloatTree::LeafNodeType::coordToOffset(coord);
136 /// if (!mask->isOn(voxel)) continue;
137 /// Vec3d dist = coord.asVec3d() - P;
138 /// this->buffer()[voxel] += dist.length(); // VolumeTransfer::buffer
139 /// }
140 /// }
141 ///
142 /// /// @brief Return true for endPointLeaf() to continue, false for finalize() so
143 /// /// we don't recurse.
144 /// bool endPointLeaf(const PointDataTree::LeafNodeType&) { return true; }
145 /// bool finalize(const Coord&, size_t) { return false; }
146 ///
147 /// private:
148 /// std::unique_ptr<AttributeHandle<Vec3f>> mHandle;
149 /// };
150 /// @endcode
151 
152 
153 /// @brief Perform potentially complex rasterization from a user defined
154 /// transfer scheme.
155 /// @details The method works by looping over a single Tree topology, looking
156 /// up point data at a position relative to that topology and passing that
157 /// data to a transfer scheme TransferT.
158 /// @note Each thread receives a copy of the transfer scheme object.
159 /// @param points the point data grid to rasterize
160 /// @param transfer the transfer scheme
161 /// @param filter optional point filter
162 /// @param interrupter optional interrupter
163 template <typename PointDataTreeOrGridT,
164  typename TransferT,
165  typename FilterT = NullFilter,
166  typename InterrupterT = util::NullInterrupter>
167 inline void
168 rasterize(const PointDataTreeOrGridT& points,
169  TransferT& transfer,
170  const FilterT& filter = NullFilter(),
171  InterrupterT* interrupter = nullptr);
172 
173 
174 ///////////////////////////////////////////////////
175 
176 /// @brief The TransformTransfer module should be used if the source transform
177 /// of the input points and the target transforms of the destination volumes
178 /// differ. The default rasterizer will skip index to world (and vice versa)
179 /// transformations unless a transfer scheme derives from a TransformTransfer.
181 {
183  const math::Transform& tt)
184  : mSourceTransform(st)
185  , mTargetTransform(tt) {}
186 
187  template <typename T>
188  inline auto transformSourceToTarget(const T& value) const
189  {
190  const auto result = mSourceTransform.indexToWorld(value);
191  return mTargetTransform.worldToIndex(result);
192  }
193 
194  template <typename T>
195  inline auto transformTargetToSource(const T& value) const
196  {
197  const auto result = mTargetTransform.indexToWorld(value);
198  return mSourceTransform.worldToIndex(result);
199  }
200 
201  const math::Transform& sourceTransform() const { return mSourceTransform; }
202  const math::Transform& targetTransform() const { return mTargetTransform; }
203 
204 private:
205  const math::Transform& mSourceTransform;
206  const math::Transform& mTargetTransform;
207 };
208 
209 /// @brief The VolumeTransfer module provides methods to automatically setup
210 /// and access destination buffers for multiple target volumes of arbitrary
211 /// types. Deriving from a VolumeTransfer ensures that the available
212 /// buffers correlate to the order of the provided tree arguments.
213 template <typename ...TreeTypes>
215 {
216  static const size_t Size = sizeof...(TreeTypes);
217  using TreeTupleT = std::tuple<TreeTypes*...>;
218 
219  template <size_t Idx> using TreeType = typename std::tuple_element<Idx, std::tuple<TreeTypes...>>::type;
220  template <size_t Idx> using ValueType = typename TreeType<Idx>::ValueType;
221  template <typename T> struct TypeResolver { using Type = typename T::ValueType; };
223 
224  VolumeTransfer(TreeTypes*... trees);
225 
227  : VolumeTransfer(&trees...) {}
228 
230  : mTreeArray(other.mTreeArray)
231  , mBuffers()
232  , mMasks()
233  {
234  mBuffers.fill(nullptr);
235  mMasks.fill(nullptr);
236  }
237 
238  inline TreeType<0>& topology() { return *(std::get<0>(mTreeArray)); }
239 
240  inline void initialize(const Coord& origin, const size_t, const CoordBBox&);
241 
242  template <size_t Idx>
244  {
245  return static_cast<ValueType<Idx>*>(mBuffers[Idx]);
246  }
247 
248  template <size_t Idx>
249  inline const ValueType<Idx>* buffer() const
250  {
251  return static_cast<ValueType<Idx>*>(mBuffers[Idx]);
252  }
253 
254  template <size_t Idx>
255  inline NodeMaskT* mask() { return mMasks[Idx]; }
256  inline NodeMaskT* mask(const size_t idx) { return mMasks[idx]; }
257 
258  template <size_t Idx>
259  inline const NodeMaskT* mask() const { return mMasks[Idx]; }
260  inline const NodeMaskT* mask(const size_t idx) const { return mMasks[idx]; }
261 
262  template <typename FunctorT>
263  inline void foreach(const FunctorT& functor);
264 
265 private:
266  const TreeTupleT mTreeArray;
267  std::array<void*, Size> mBuffers;
268  std::array<NodeMaskT*, Size> mMasks;
269 };
270 
271 /// @brief VolumeTransfer specialization for a single target volume
272 /// @todo this specialization should avoid the probe
273 template <typename TreeT>
274 struct VolumeTransfer<TreeT>
275 {
276  using TreeType = TreeT;
277  using ValueType = typename TreeType::ValueType;
278  using NodeMaskT = typename TreeType::LeafNodeType::NodeMaskType;
279 
281  "One or more template arguments to VolumeTransfer "
282  "are not a valid openvdb::Tree type.");
283 
285  : mTree(tree)
286  , mBuffer(nullptr)
287  , mMask(nullptr) {
288  assert(tree);
289  }
290 
292  : VolumeTransfer(&tree) {}
293 
295  : mTree(other.mTree)
296  , mBuffer(nullptr)
297  , mMask(nullptr) {}
298 
299  inline TreeType& topology() { return *mTree; }
300 
301  inline void initialize(const Coord& origin, const size_t, const CoordBBox&)
302  {
303  assert(mTree);
304  if (auto leaf = mTree->probeLeaf(origin)) {
305  mBuffer = leaf->buffer().data();
306  mMask = &(leaf->getValueMask());
307  }
308  else {
309  mBuffer = nullptr;
310  mMask = nullptr;
311  }
312  }
313 
314  inline ValueType* buffer() { return mBuffer; }
315  inline const ValueType* buffer() const { return mBuffer; }
316  inline NodeMaskT* mask() { return mMask; }
317  inline const NodeMaskT* mask() const { return mMask; }
318 
319  // compatibility with multi tree containers
320  template <size_t> inline ValueType* buffer() { return this->buffer(); }
321  template <size_t> inline const ValueType* buffer() const { return this->buffer(); }
322  template <size_t> inline NodeMaskT* mask() { return this->mask(); }
323  template <size_t> inline const NodeMaskT* mask() const { return this->mask(); }
324 
325 private:
326  TreeType* const mTree;
327  ValueType* mBuffer;
328  NodeMaskT* mMask;
329 };
330 
331 namespace transfer_internal
332 {
333 template<typename T, typename F, size_t... Is>
334 void foreach(T&& t, const F& func, std::integer_sequence<size_t, Is...>)
335 {
336  auto init = { (func(std::get<Is>(t), Is), 0)... };
337  (void)init;
338 }
339 
340 template<typename T, typename F, size_t... Is>
341 void foreach(void** buffers, const F& func, std::integer_sequence<size_t, Is...>)
342 {
343  int init[sizeof...(Is)] = {
344  (func(static_cast<typename std::tuple_element<Is, T>::type*>
345  (*(buffers + Is)), Is), 0)...
346  };
347 }
348 
349 template<typename T, template <typename> class R, typename F, size_t... Is>
350 void foreach(void** buffers, const F& func, std::integer_sequence<size_t, Is...>)
351 {
352  int init[sizeof...(Is)] = {
353  (func(static_cast<typename R<typename std::tuple_element<Is, T>::type>::Type*>
354  (*(buffers + Is)), Is), 0)...
355  };
356 }
357 }
358 
359 template <typename ...TreeTypes>
361  : mTreeArray({ trees... })
362  , mBuffers()
363  , mMasks()
364 {
365  transfer_internal::foreach(mTreeArray, [](auto&& tree, const size_t) {
368  "One or more template arguments to VolumeTransfer "
369  "are not a valid openvdb::Tree type.");
370  assert(tree);
371  }, std::make_integer_sequence<size_t, Size>());
372 
373  mBuffers.fill(nullptr);
374  mMasks.fill(nullptr);
375 }
376 
377 template <typename ...TreeTypes>
378 inline void VolumeTransfer<TreeTypes...>::initialize(const Coord& origin, const size_t, const CoordBBox&)
379 {
380  transfer_internal::foreach(mTreeArray,
381  [&](auto&& tree, const size_t i) {
382  assert(tree);
383  if (auto leaf = tree->probeLeaf(origin)) {
384  mBuffers[i] = static_cast<void*>(leaf->buffer().data());
385  mMasks[i] = &(leaf->getValueMask());
386  }
387  else {
388  mBuffers[i] = nullptr;
389  mMasks[i] = nullptr;
390  }
391  }, std::make_integer_sequence<size_t, Size>());
392 }
393 
394 template <typename ...TreeTypes>
395 template <typename FunctorT>
396 inline void VolumeTransfer<TreeTypes...>::foreach(const FunctorT& functor)
397 {
398  transfer_internal::foreach<TreeTupleT, TypeResolver>(mBuffers.data(), functor,
399  std::make_integer_sequence<size_t, Size>());
400 }
401 
402 namespace transfer_internal
403 {
404 template <typename TransferT,
405  typename TopologyT,
406  typename PointFilterT = points::NullFilter,
407  typename InterrupterT = util::NullInterrupter>
409 {
412 
413  static const Index DIM = TopologyT::LeafNodeType::DIM;
414  static const Int32 DIM32 = static_cast<Int32>(DIM);
415  static const Index LOG2DIM = TopologyT::LeafNodeType::LOG2DIM;
416 
418  const TransferT& transfer,
419  const PointFilterT& filter = PointFilterT(),
420  InterrupterT* interrupter = nullptr)
421  : mPointAccessor(tree)
422  , mTransfer(transfer)
423  , mFilter(filter)
424  , mInterrupter(interrupter) {}
425 
426  void operator()(LeafNodeT& leaf, const size_t idx) const
427  {
428  if (util::wasInterrupted(mInterrupter)) {
429  thread::cancelGroupExecution();
430  return;
431  }
432 
433  const Coord& origin = leaf.origin();
434  auto& mask = leaf.getValueMask();
435 
436  CoordBBox bounds;
437 
438  bool state;
439  if (mask.isConstant(state)) {
440  if (!state) return; // all inactive
441  else bounds = leaf.getNodeBoundingBox();
442  }
443  else {
444  // Use evalActiveBoundingBox over getNodeBoundingBox()
445  // to get a better approximation
446  leaf.evalActiveBoundingBox(bounds);
447  assert(!bounds.empty());
448  }
449 
450  mTransfer.initialize(origin, idx, bounds);
451 
452  CoordBBox search = bounds.expandBy(mTransfer.range(origin, idx));
453  this->transform<>(search);
454 
455  // start the iteration from a leaf origin
456  const Coord min = (search.min() & ~(DIM-1));
457  const Coord& max = search.max();
458  PointFilterT localFilter(mFilter);
459 
460  // loop over overlapping leaf nodes
461  Coord leafOrigin;
462  for (leafOrigin[0] = min[0]; leafOrigin[0] <= max[0]; leafOrigin[0]+=DIM32) {
463  for (leafOrigin[1] = min[1]; leafOrigin[1] <= max[1]; leafOrigin[1]+=DIM32) {
464  for (leafOrigin[2] = min[2]; leafOrigin[2] <= max[2]; leafOrigin[2]+=DIM32) {
465 
466  // if no overlap, continue
467  CoordBBox pbox = CoordBBox::createCube(leafOrigin, DIM32);
468  pbox.intersect(search);
469  if (pbox.empty()) continue;
470 
471  // if no points, continue
472  const auto* pointLeaf = mPointAccessor.probeConstLeaf(leafOrigin);
473  if (!pointLeaf) continue;
474  if (!mTransfer.startPointLeaf(*pointLeaf)) continue;
475  localFilter.reset(*pointLeaf);
476 
477  // loop over point voxels which contribute to this leaf
478  const Coord& pmin(pbox.min());
479  const Coord& pmax(pbox.max());
480  for (Coord ijk = pmin; ijk.x() <= pmax.x(); ++ijk.x()) {
481  const Index i = ((ijk.x() & (DIM-1u)) << 2*LOG2DIM); // unsigned bit shift mult
482  for (ijk.y() = pmin.y(); ijk.y() <= pmax.y(); ++ijk.y()) {
483  const Index ij = i + ((ijk.y() & (DIM-1u)) << LOG2DIM);
484  for (ijk.z() = pmin.z(); ijk.z() <= pmax.z(); ++ijk.z()) {
485  // voxel should be in this points leaf
486  assert((ijk & ~(DIM-1u)) == leafOrigin);
487  const Index index = ij + /*k*/(ijk.z() & (DIM-1u));
488  const Index end = pointLeaf->getValue(index);
489  Index id = (index == 0) ? 0 : Index(pointLeaf->getValue(index - 1));
490  for (; id < end; ++id) {
491  if (!localFilter.valid(&id)) continue;
492  mTransfer.rasterizePoint(ijk, id, bounds);
493  } //point idx
494  }
495  }
496  } // outer point voxel
497 
498  if (!mTransfer.endPointLeaf(*pointLeaf)) {
499  // rescurse if necessary
500  if (!mTransfer.finalize(origin, idx)) {
501  this->operator()(leaf, idx);
502  }
503  return;
504  }
505  }
506  }
507  } // outer leaf node
508 
509  // rescurse if necessary
510  if (!mTransfer.finalize(origin, idx)) {
511  this->operator()(leaf, idx);
512  }
513  }
514 
515  void operator()(const typename LeafManagerT::LeafRange& range) const
516  {
517  for (auto leaf = range.begin(); leaf; ++leaf) {
518  (*this)(*leaf, leaf.pos());
519  }
520  }
521 
522 private:
523 
524  template <typename EnableT = TransferT>
526  transform(CoordBBox& bounds) const
527  {
528  const TransformTransfer* transform =
529  static_cast<TransformTransfer*>(&mTransfer);
530  const BBoxd bbox(bounds.min().asVec3d(), bounds.max().asVec3d());
531  bounds = transform->sourceTransform().worldToIndexCellCentered(
532  transform->targetTransform().indexToWorld(bbox));
533  }
534 
535  template <typename EnableT = TransferT>
537  transform(CoordBBox&) const {}
538 
539 private:
540  const PointDataGrid::ConstAccessor mPointAccessor;
541  mutable TransferT mTransfer;
542  const PointFilterT& mFilter;
543  InterrupterT* mInterrupter;
544 };
545 
546 } // namespace transfer_internal
547 
548 ///////////////////////////////////////////////////
549 ///////////////////////////////////////////////////
550 
551 template <typename PointDataTreeOrGridT,
552  typename TransferT,
553  typename FilterT,
554  typename InterrupterT>
555 inline void
556 rasterize(const PointDataTreeOrGridT& points,
557  TransferT& transfer,
558  const FilterT& filter,
559  InterrupterT* interrupter)
560 {
561  using PointTreeT = typename TreeAdapter<PointDataTreeOrGridT>::TreeType;
563  "Provided points to rasterize is not a derived TreeBase type.");
564 
565  const auto& tree = TreeAdapter<PointDataTreeOrGridT>::tree(points);
566 
567  auto& topology = transfer.topology();
568  using TreeT = typename std::decay<decltype(topology)>::type;
571  raster(tree, transfer, filter, interrupter);
572  manager.foreach(raster);
573 }
574 
575 } // namespace points
576 } // namespace OPENVDB_VERSION_NAME
577 } // namespace openvdb
578 
579 #endif //OPENVEB_POINTS_TRANSFER_HAS_BEEN_INCLUDED
const NodeMaskT * mask(const size_t idx) const
typename TreeType< 0 >::LeafNodeType::NodeMaskType NodeMaskT
GLenum GLint * range
Definition: glcorearb.h:1925
GLdouble GLdouble GLint GLint const GLdouble * points
Definition: glad.h:2676
Vec3d indexToWorld(const Vec3d &xyz) const
Apply this transformation to the given coordinates.
Definition: Transform.h:108
void rasterize(const PointDataTreeOrGridT &points, TransferT &transfer, const FilterT &filter=NullFilter(), InterrupterT *interrupter=nullptr)
Perform potentially complex rasterization from a user defined transfer scheme.
void
Definition: png.h:1083
The TransformTransfer module should be used if the source transform of the input points and the targe...
GLsizei const GLfloat * value
Definition: glcorearb.h:824
typename TreeType::LeafNodeType::NodeMaskType NodeMaskT
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:239
ImageBuf OIIO_API min(Image_or_Const A, Image_or_Const B, ROI roi={}, int nthreads=0)
**But if you need a result
Definition: thread.h:613
void initialize(const Coord &origin, const size_t, const CoordBBox &)
TransformTransfer(const math::Transform &st, const math::Transform &tt)
GT_API const UT_StringHolder topology
GLuint GLuint end
Definition: glcorearb.h:475
const GLuint * buffers
Definition: glcorearb.h:661
GLint GLuint mask
Definition: glcorearb.h:124
void initialize(const Coord &origin, const size_t, const CoordBBox &)
This class manages a linear array of pointers to a given tree's leaf nodes, as well as optional auxil...
Definition: LeafManager.h:84
HUSD_API const char * raster()
GridTypes::Transform< internal::ToTreeType > TreeTypes
Definition: openvdb.h:123
GLuint id
Definition: glcorearb.h:655
static TreeType & tree(TreeType &t)
Definition: Grid.h:1076
void foreach(const LeafOp &op, bool threaded=true, size_t grainSize=1)
Threaded method that applies a user-supplied functor to each leaf node in the LeafManager.
Definition: LeafManager.h:483
GLdouble t
Definition: glad.h:2397
auto search(const T &set, const V &val) -> std::pair< bool, decltype(std::begin(detail::smart_deref(set)))>
A search function.
Definition: CLI11.h:3170
GLenum func
Definition: glcorearb.h:783
GT_API const UT_StringHolder st
typename std::tuple_element< Idx, std::tuple< TreeTypes...>>::type TreeType
GLuint index
Definition: glcorearb.h:786
void foreach(T &&t, const F &func, std::integer_sequence< size_t, Is...>)
Coord worldToIndexCellCentered(const Vec3d &xyz) const
Apply this transformation to the given coordinates.
Definition: Transform.h:111
ImageBuf OIIO_API max(Image_or_Const A, Image_or_Const B, ROI roi={}, int nthreads=0)
void operator()(const typename LeafManagerT::LeafRange &range) const
The VolumeTransfer module provides methods to automatically setup and access destination buffers for ...
tree::Tree< tree::RootNode< tree::InternalNode< tree::InternalNode< PointDataLeafNode< PointDataIndex32, 3 >, 4 >, 5 >>> PointDataTree
Point index tree configured to match the default VDB configurations.
Definition: core.h:1131
typename TreeType< Idx >::ValueType ValueType
Vec3d worldToIndex(const Vec3d &xyz) const
Apply this transformation to the given coordinates.
Definition: Transform.h:110
bool wasInterrupted(T *i, int percent=-1)
type
Definition: core.h:1059
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h:119
RasterizePoints(const points::PointDataTree &tree, const TransferT &transfer, const PointFilterT &filter=PointFilterT(), InterrupterT *interrupter=nullptr)
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
Definition: glcorearb.h:1297