OpenVDB  11.0.0
HDDA.h
Go to the documentation of this file.
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3 
4 /// @file HDDA.h
5 ///
6 /// @author Ken Museth
7 ///
8 /// @brief Hierarchical Digital Differential Analyzers specialized for VDB.
9 
10 #ifndef NANOVDB_HDDA_H_HAS_BEEN_INCLUDED
11 #define NANOVDB_HDDA_H_HAS_BEEN_INCLUDED
12 
13 // Comment out to disable this explicit round-off check
14 #define ENFORCE_FORWARD_STEPPING
15 
16 #include <nanovdb/NanoVDB.h> // only dependency
17 
18 namespace nanovdb {
19 
20 /// @brief A Digital Differential Analyzer specialized for OpenVDB grids
21 /// @note Conceptually similar to Bresenham's line algorithm applied
22 /// to a 3D Ray intersecting OpenVDB nodes or voxels. Log2Dim = 0
23 /// corresponds to a voxel and Log2Dim a tree node of size 2^Log2Dim.
24 ///
25 /// @note The Ray template class is expected to have the following
26 /// methods: test(time), t0(), t1(), invDir(), and operator()(time).
27 /// See the example Ray class above for their definition.
28 template<typename RayT, typename CoordT = Coord>
29 class HDDA
30 {
31 public:
32  using RealType = typename RayT::RealType;
33  using RealT = RealType;
34  using Vec3Type = typename RayT::Vec3Type;
35  using Vec3T = Vec3Type;
36  using CoordType = CoordT;
37 
38  /// @brief Default ctor
39  HDDA() = default;
40 
41  /// @brief ctor from ray and dimension at which the DDA marches
42  __hostdev__ HDDA(const RayT& ray, int dim) { this->init(ray, dim); }
43 
44  /// @brief Re-initializes the HDDA
45  __hostdev__ void init(const RayT& ray, RealT startTime, RealT maxTime, int dim)
46  {
47  assert(startTime <= maxTime);
48  mDim = dim;
49  mT0 = startTime;
50  mT1 = maxTime;
51  const Vec3T &pos = ray(mT0), &dir = ray.dir(), &inv = ray.invDir();
52  mVoxel = RoundDown<CoordT>(pos) & (~(dim - 1));
53  for (int axis = 0; axis < 3; ++axis) {
54  if (dir[axis] == RealT(0)) { //handles dir = +/- 0
55  mNext[axis] = Maximum<RealT>::value(); //i.e. disabled!
56  mStep[axis] = 0;
57  } else if (inv[axis] > 0) {
58  mStep[axis] = 1;
59  mNext[axis] = mT0 + (mVoxel[axis] + dim - pos[axis]) * inv[axis];
60  mDelta[axis] = inv[axis];
61  } else {
62  mStep[axis] = -1;
63  mNext[axis] = mT0 + (mVoxel[axis] - pos[axis]) * inv[axis];
64  mDelta[axis] = -inv[axis];
65  }
66  }
67  }
68 
69  /// @brief Simular to init above except it uses the bounds of the input ray
70  __hostdev__ void init(const RayT& ray, int dim) { this->init(ray, ray.t0(), ray.t1(), dim); }
71 
72  /// @brief Updates the HDDA to march with the specified dimension
73  __hostdev__ bool update(const RayT& ray, int dim)
74  {
75  if (mDim == dim)
76  return false;
77  mDim = dim;
78  const Vec3T &pos = ray(mT0), &inv = ray.invDir();
79  mVoxel = RoundDown<CoordT>(pos) & (~(dim - 1));
80  for (int axis = 0; axis < 3; ++axis) {
81  if (mStep[axis] == 0)
82  continue;
83  mNext[axis] = mT0 + (mVoxel[axis] - pos[axis]) * inv[axis];
84  if (mStep[axis] > 0)
85  mNext[axis] += dim * inv[axis];
86  }
87 
88  return true;
89  }
90 
91  __hostdev__ int dim() const { return mDim; }
92 
93  /// @brief Increment the voxel index to next intersected voxel or node
94  /// and returns true if the step in time does not exceed maxTime.
96  {
97  const int axis = MinIndex(mNext);
98 #if 1
99  switch (axis) {
100  case 0:
101  return step<0>();
102  case 1:
103  return step<1>();
104  default:
105  return step<2>();
106  }
107 #else
108  mT0 = mNext[axis];
109  mNext[axis] += mDim * mDelta[axis];
110  mVoxel[axis] += mDim * mStep[axis];
111  return mT0 <= mT1;
112 #endif
113  }
114 
115  /// @brief Return the index coordinates of the next node or voxel
116  /// intersected by the ray. If Log2Dim = 0 the return value is the
117  /// actual signed coordinate of the voxel, else it is the origin
118  /// of the corresponding VDB tree node or tile.
119  /// @note Incurs no computational overhead.
120  __hostdev__ const CoordT& voxel() const { return mVoxel; }
121 
122  /// @brief Return the time (parameterized along the Ray) of the
123  /// first hit of a tree node of size 2^Log2Dim.
124  /// @details This value is initialized to startTime or ray.t0()
125  /// depending on the constructor used.
126  /// @note Incurs no computational overhead.
127  __hostdev__ RealType time() const { return mT0; }
128 
129  /// @brief Return the maximum time (parameterized along the Ray).
130  __hostdev__ RealType maxTime() const { return mT1; }
131 
132  /// @brief Return the time (parameterized along the Ray) of the
133  /// second (i.e. next) hit of a tree node of size 2^Log2Dim.
134  /// @note Incurs a (small) computational overhead.
136  {
137 #if 1 //def __CUDA_ARCH__
138  return fminf(mT1, fminf(mNext[0], fminf(mNext[1], mNext[2])));
139 #else
140  return std::min(mT1, std::min(mNext[0], std::min(mNext[1], mNext[2])));
141 #endif
142  }
143 
144 private:
145  // helper to implement the general form
146  template<int axis>
147  __hostdev__ bool step()
148  {
149 #ifdef ENFORCE_FORWARD_STEPPING
150  //if (mNext[axis] <= mT0) mNext[axis] += mT0 - mNext[axis] + fmaxf(mNext[axis]*1.0e-6f, 1.0e-6f);
151  //if (mNext[axis] <= mT0) mNext[axis] += mT0 - mNext[axis] + (mNext[axis] + 1.0f)*1.0e-6f;
152  if (mNext[axis] <= mT0) {
153  mNext[axis] += mT0 - 0.999999f * mNext[axis] + 1.0e-6f;
154  }
155 #endif
156  mT0 = mNext[axis];
157  mNext[ axis] += mDim * mDelta[axis];
158  mVoxel[axis] += mDim * mStep[ axis];
159  return mT0 <= mT1;
160  }
161 
162  int32_t mDim;
163  RealT mT0, mT1; // min and max allowed times
164  CoordT mVoxel, mStep; // current voxel location and step to next voxel location
165  Vec3T mDelta, mNext; // delta time and next time
166 }; // class HDDA
167 
168 /////////////////////////////////////////// ZeroCrossing ////////////////////////////////////////////
169 
170 /// @brief returns true if the ray intersects a zero-crossing at the voxel level of the grid in the accessor
171 /// The empty-space ray-marching is performed at all levels of the tree using an
172 /// HDDA. If an intersection is detected, then ijk is updated with the index coordinate of the closest
173 /// voxel after the intersection point, v contains the grid values at ijk, and t is set to the time of
174 /// the intersection along the ray.
175 template<typename RayT, typename AccT>
176 inline __hostdev__ bool ZeroCrossing(RayT& ray, AccT& acc, Coord& ijk, typename AccT::ValueType& v, float& t)
177 {
178  if (!ray.clip(acc.root().bbox()) || ray.t1() > 1e20)
179  return false; // clip ray to bbox
180  static const float Delta = 1.0001f;
181  ijk = RoundDown<Coord>(ray.start()); // first hit of bbox
182  HDDA<RayT, Coord> hdda(ray, acc.getDim(ijk, ray));
183  const auto v0 = acc.getValue(ijk);
184  while (hdda.step()) {
185  ijk = RoundDown<Coord>(ray(hdda.time() + Delta));
186  hdda.update(ray, acc.getDim(ijk, ray));
187  if (hdda.dim() > 1 || !acc.isActive(ijk))
188  continue; // either a tile value or an inactive voxel
189  while (hdda.step() && acc.isActive(hdda.voxel())) { // in the narrow band
190  v = acc.getValue(hdda.voxel());
191  if (v * v0 < 0) { // zero crossing
192  ijk = hdda.voxel();
193  t = hdda.time();
194  return true;
195  }
196  }
197  }
198  return false;
199 }
200 
201 /////////////////////////////////////////// DDA ////////////////////////////////////////////
202 
203 /// @brief A Digital Differential Analyzer. Unlike HDDA (defined above) this DDA
204 /// uses a fixed step-size defined by the template parameter Dim!
205 ///
206 /// @note The Ray template class is expected to have the following
207 /// methods: test(time), t0(), t1(), invDir(), and operator()(time).
208 /// See the example Ray class above for their definition.
209 template<typename RayT, typename CoordT = Coord, int Dim = 1>
210 class DDA
211 {
212  static_assert(Dim >= 1, "Dim must be >= 1");
213 
214 public:
215  using RealType = typename RayT::RealType;
216  using RealT = RealType;
217  using Vec3Type = typename RayT::Vec3Type;
218  using Vec3T = Vec3Type;
219  using CoordType = CoordT;
220 
221  /// @brief Default ctor
222  DDA() = default;
223 
224  /// @brief ctor from ray and dimension at which the DDA marches
225  __hostdev__ DDA(const RayT& ray) { this->init(ray); }
226 
227  /// @brief Re-initializes the DDA
228  __hostdev__ void init(const RayT& ray, RealT startTime, RealT maxTime)
229  {
230  assert(startTime <= maxTime);
231  mT0 = startTime;
232  mT1 = maxTime;
233  const Vec3T &pos = ray(mT0), &dir = ray.dir(), &inv = ray.invDir();
234  mVoxel = RoundDown<CoordT>(pos) & (~(Dim - 1));
235  for (int axis = 0; axis < 3; ++axis) {
236  if (dir[axis] == RealT(0)) { //handles dir = +/- 0
237  mNext[axis] = Maximum<RealT>::value(); //i.e. disabled!
238  mStep[axis] = 0;
239  } else if (inv[axis] > 0) {
240  mStep[axis] = Dim;
241  mNext[axis] = (mT0 + (mVoxel[axis] + Dim - pos[axis]) * inv[axis]);
242  mDelta[axis] = inv[axis];
243  } else {
244  mStep[axis] = -Dim;
245  mNext[axis] = mT0 + (mVoxel[axis] - pos[axis]) * inv[axis];
246  mDelta[axis] = -inv[axis];
247  }
248  }
249  }
250 
251  /// @brief Simular to init above except it uses the bounds of the input ray
252  __hostdev__ void init(const RayT& ray) { this->init(ray, ray.t0(), ray.t1()); }
253 
254  /// @brief Increment the voxel index to next intersected voxel or node
255  /// and returns true if the step in time does not exceed maxTime.
257  {
258  const int axis = MinIndex(mNext);
259 #if 1
260  switch (axis) {
261  case 0:
262  return step<0>();
263  case 1:
264  return step<1>();
265  default:
266  return step<2>();
267  }
268 #else
269 #ifdef ENFORCE_FORWARD_STEPPING
270  if (mNext[axis] <= mT0) {
271  mNext[axis] += mT0 - 0.999999f * mNext[axis] + 1.0e-6f;
272  }
273 #endif
274  mT0 = mNext[axis];
275  mNext[axis] += mDelta[axis];
276  mVoxel[axis] += mStep[axis];
277  return mT0 <= mT1;
278 #endif
279  }
280 
281  /// @brief Return the index coordinates of the next node or voxel
282  /// intersected by the ray. If Log2Dim = 0 the return value is the
283  /// actual signed coordinate of the voxel, else it is the origin
284  /// of the corresponding VDB tree node or tile.
285  /// @note Incurs no computational overhead.
286  __hostdev__ const CoordT& voxel() const { return mVoxel; }
287 
288  /// @brief Return the time (parameterized along the Ray) of the
289  /// first hit of a tree node of size 2^Log2Dim.
290  /// @details This value is initialized to startTime or ray.t0()
291  /// depending on the constructor used.
292  /// @note Incurs no computational overhead.
293  __hostdev__ RealType time() const { return mT0; }
294 
295  /// @brief Return the maximum time (parameterized along the Ray).
296  __hostdev__ RealType maxTime() const { return mT1; }
297 
298  /// @brief Return the time (parameterized along the Ray) of the
299  /// second (i.e. next) hit of a tree node of size 2^Log2Dim.
300  /// @note Incurs a (small) computational overhead.
302  {
303  return Min(mT1, Min(mNext[0], Min(mNext[1], mNext[2])));
304  }
305 
306  __hostdev__ int nextAxis() const
307  {
308  return nanovdb::MinIndex(mNext);
309  }
310 
311 private:
312  // helper to implement the general form
313  template<int axis>
314  __hostdev__ bool step()
315  {
316 #ifdef ENFORCE_FORWARD_STEPPING
317  if (mNext[axis] <= mT0) {
318  mNext[axis] += mT0 - 0.999999f * mNext[axis] + 1.0e-6f;
319  }
320 #endif
321  mT0 = mNext[axis];
322  mNext[axis] += mDelta[axis];
323  mVoxel[axis] += mStep[axis];
324  return mT0 <= mT1;
325  }
326 
327  RealT mT0, mT1; // min and max allowed times
328  CoordT mVoxel, mStep; // current voxel location and step to next voxel location
329  Vec3T mDelta, mNext; // delta time and next time
330 }; // class DDA
331 
332 /////////////////////////////////////////// ZeroCrossingNode ////////////////////////////////////////////
333 
334 template<typename RayT, typename NodeT>
335 inline __hostdev__ bool ZeroCrossingNode(RayT& ray, const NodeT& node, float v0, nanovdb::Coord& ijk, float& v, float& t)
336 {
337  BBox<Coord> bbox(node.origin(), node.origin() + Coord(node.dim() - 1));
338 
339  if (!ray.clip(node.bbox())) {
340  return false;
341  }
342 
343  const float t0 = ray.t0();
344 
345  static const float Delta = 1.0001f;
346  ijk = Coord::Floor(ray(ray.t0() + Delta));
347 
348  t = t0;
349  v = 0;
350 
352  while (dda.step()) {
353  ijk = dda.voxel();
354 
355  if (bbox.isInside(ijk) == false)
356  return false;
357 
358  v = node.getValue(ijk);
359  if (v * v0 < 0) {
360  t = dda.time();
361  return true;
362  }
363  }
364  return false;
365 }
366 
367 /////////////////////////////////////////// TreeMarcher ////////////////////////////////////////////
368 
369 /// @brief returns true if the ray intersects an active value at any level of the grid in the accessor.
370 /// The empty-space ray-marching is performed at all levels of the tree using an
371 /// HDDA. If an intersection is detected, then ijk is updated with the index coordinate of the first
372 /// active voxel or tile, and t is set to the time of its intersection along the ray.
373 template<typename RayT, typename AccT>
374 inline __hostdev__ bool firstActive(RayT& ray, AccT& acc, Coord &ijk, float& t)
375 {
376  if (!ray.clip(acc.root().bbox()) || ray.t1() > 1e20) {// clip ray to bbox
377  return false;// missed or undefined bbox
378  }
379  static const float Delta = 1.0001f;// forward step-size along the ray to avoid getting stuck
380  t = ray.t0();// initiate time
381  ijk = RoundDown<Coord>(ray.start()); // first voxel inside bbox
382  for (HDDA<RayT, Coord> hdda(ray, acc.getDim(ijk, ray)); !acc.isActive(ijk); hdda.update(ray, acc.getDim(ijk, ray))) {
383  if (!hdda.step()) return false;// leap-frog HDDA and exit if ray bound is exceeded
384  t = hdda.time() + Delta;// update time
385  ijk = RoundDown<Coord>( ray(t) );// update ijk
386  }
387  return true;
388 }
389 
390 /////////////////////////////////////////// TreeMarcher ////////////////////////////////////////////
391 
392 /// @brief A Tree Marcher for Generic Grids
393 
394 template<typename NodeT, typename RayT, typename AccT, typename CoordT = Coord>
396 {
397 public:
398  using ChildT = typename NodeT::ChildNodeType;
399  using RealType = typename RayT::RealType;
400  using RealT = RealType;
401  using CoordType = CoordT;
402 
403  inline __hostdev__ TreeMarcher(AccT& acc)
404  : mAcc(acc)
405  {
406  }
407 
408  /// @brief Initialize the TreeMarcher with an index-space ray.
409  inline __hostdev__ bool init(const RayT& indexRay)
410  {
411  mRay = indexRay;
412  if (!mRay.clip(mAcc.root().bbox()))
413  return false; // clip ray to bbox
414 
415  // tweak the intersection span into the bbox.
416  // CAVEAT: this will potentially clip some tiny corner intersections.
417  static const float Eps = 0.000001f;
418  const float t0 = mRay.t0() + Eps;
419  const float t1 = mRay.t1() - Eps;
420  if (t0 > t1)
421  return false;
422 
423  const CoordT ijk = RoundDown<Coord>(mRay(t0));
424  const uint32_t dim = mAcc.getDim(ijk, mRay);
425  mHdda.init(mRay, t0, t1, nanovdb::Max(dim, NodeT::dim()));
426 
427  mT0 = (dim <= ChildT::dim()) ? mHdda.time() : -1; // potentially begin a span.
428  mTmax = t1;
429  return true;
430  }
431 
432  /// @brief step the ray through the tree. If the ray hits a node then
433  /// populate t0 & t1, and the node.
434  /// @return true when a node of type NodeT is intersected, false otherwise.
435  inline __hostdev__ bool step(const NodeT** node, float& t0, float& t1)
436  {
437  // CAVEAT: if Delta is too large then it will clip corners of nodes in a visible way.
438  // but it has to be quite large when very far from the grid (due to fp32 rounding)
439  static const float Delta = 0.01f;
440  bool hddaIsValid;
441 
442  do {
443  t0 = mT0;
444 
445  auto currentNode = mAcc.template getNode<NodeT>();
446 
447  // get next node intersection...
448  hddaIsValid = mHdda.step();
449  const CoordT nextIjk = RoundDown<Coord>(mRay(mHdda.time() + Delta));
450  const auto nextDim = mAcc.getDim(nextIjk, mRay);
451  mHdda.update(mRay, (int)Max(nextDim, NodeT::dim()));
452  mT0 = (nextDim <= ChildT::dim()) ? mHdda.time() : -1; // potentially begin a span.
453 
454  if (t0 >= 0) { // we are in a span.
455  t1 = Min(mTmax, mHdda.time());
456 
457  // TODO: clean this up!
458  if (t0 >= t1 || currentNode == nullptr)
459  continue;
460 
461  *node = currentNode;
462  return true;
463  }
464 
465  } while (hddaIsValid);
466 
467  return false;
468  }
469 
470  inline __hostdev__ const RayT& ray() const { return mRay; }
471 
472  inline __hostdev__ RayT& ray() { return mRay; }
473 
474 private:
475  AccT& mAcc;
476  RayT mRay;
477  HDDA<RayT, Coord> mHdda;
478  float mT0;
479  float mTmax;
480 };// TreeMarcher
481 
482 /////////////////////////////////////////// PointTreeMarcher ////////////////////////////////////////////
483 
484 /// @brief A Tree Marcher for Point Grids
485 ///
486 /// @note This class will handle correctly offseting the ray by 0.5 to ensure that
487 /// the underlying HDDA will intersect with the grid-cells. See details below.
488 
489 template<typename AccT, typename RayT, typename CoordT = Coord>
490 class PointTreeMarcher : public TreeMarcher<LeafNode<typename AccT::ValueType>, RayT, AccT, CoordT>
491 {
492  using BaseT = TreeMarcher<LeafNode<typename AccT::ValueType>, RayT, AccT, CoordT>;
493 public:
494  __hostdev__ PointTreeMarcher(AccT& acc) : BaseT(acc) {}
495 
496  /// @brief Initiates this instance with a ray in index space.
497  ///
498  /// @details An offset by 0.5 is applied to the ray to account for the fact that points in vdb
499  /// grids are bucketed into so-called grid cell, which are centered round grid voxels,
500  /// whereas the DDA is based on so-called grid nodes, which are coincident with grid
501  /// voxels. So, rather than offsettting the points by 0.5 to bring them into a grid
502  /// node representation this method offsets the eye of the ray by 0.5, which effectively
503  /// ensures that the DDA operates on grid cells as oppose to grid nodes. This subtle
504  /// but important offset by 0.5 is explined in more details in our online documentation.
505  __hostdev__ bool init(RayT ray) { return BaseT::init(ray.offsetEye(0.5)); }
506 };// PointTreeMarcher
507 
508 } // namespace nanovdb
509 
510 #endif // NANOVDB_HDDA_HAS_BEEN_INCLUDED
__hostdev__ RealType maxTime() const
Return the maximum time (parameterized along the Ray).
Definition: HDDA.h:130
__hostdev__ RealType next() const
Return the time (parameterized along the Ray) of the second (i.e. next) hit of a tree node of size 2^...
Definition: HDDA.h:301
__hostdev__ void init(const RayT &ray)
Simular to init above except it uses the bounds of the input ray.
Definition: HDDA.h:252
__hostdev__ bool firstActive(RayT &ray, AccT &acc, Coord &ijk, float &t)
returns true if the ray intersects an active value at any level of the grid in the accessor...
Definition: HDDA.h:374
RealType RealT
Definition: HDDA.h:216
__hostdev__ bool ZeroCrossing(RayT &ray, AccT &acc, Coord &ijk, typename AccT::ValueType &v, float &t)
returns true if the ray intersects a zero-crossing at the voxel level of the grid in the accessor The...
Definition: HDDA.h:176
__hostdev__ const CoordT & voxel() const
Return the index coordinates of the next node or voxel intersected by the ray. If Log2Dim = 0 the ret...
Definition: HDDA.h:286
__hostdev__ RealType time() const
Return the time (parameterized along the Ray) of the first hit of a tree node of size 2^Log2Dim...
Definition: HDDA.h:293
A Digital Differential Analyzer specialized for OpenVDB grids.
Definition: HDDA.h:29
Type Max(Type a, Type b)
Definition: NanoVDB.h:1110
Vec3Type Vec3T
Definition: HDDA.h:218
Type Min(Type a, Type b)
Definition: NanoVDB.h:1089
__hostdev__ RealType next() const
Return the time (parameterized along the Ray) of the second (i.e. next) hit of a tree node of size 2^...
Definition: HDDA.h:135
__hostdev__ const CoordT & voxel() const
Return the index coordinates of the next node or voxel intersected by the ray. If Log2Dim = 0 the ret...
Definition: HDDA.h:120
Implements a light-weight self-contained VDB data-structure in a single file! In other words...
HDDA()=default
Default ctor.
Definition: NanoVDB.h:247
CoordT CoordType
Definition: HDDA.h:219
__hostdev__ int dim() const
Definition: HDDA.h:91
typename RayT::RealType RealType
Definition: HDDA.h:215
Vec3Type Vec3T
Definition: HDDA.h:35
__hostdev__ bool init(RayT ray)
Initiates this instance with a ray in index space.
Definition: HDDA.h:505
Delta for small floating-point offsets.
Definition: NanoVDB.h:1035
__hostdev__ bool init(const RayT &indexRay)
Initialize the TreeMarcher with an index-space ray.
Definition: HDDA.h:409
__hostdev__ bool step()
Increment the voxel index to next intersected voxel or node and returns true if the step in time does...
Definition: HDDA.h:256
static Coord Floor(const Vec3T &xyz)
Return the largest integer coordinates that are not greater than xyz (node centered conversion)...
Definition: NanoVDB.h:1499
A Tree Marcher for Generic Grids.
Definition: HDDA.h:395
typename RayT::Vec3Type Vec3Type
Definition: HDDA.h:217
typename RayT::Vec3Type Vec3Type
Definition: HDDA.h:34
__hostdev__ RealType maxTime() const
Return the maximum time (parameterized along the Ray).
Definition: HDDA.h:296
__hostdev__ bool ZeroCrossingNode(RayT &ray, const NodeT &node, float v0, nanovdb::Coord &ijk, float &v, float &t)
Definition: HDDA.h:335
__hostdev__ HDDA(const RayT &ray, int dim)
ctor from ray and dimension at which the DDA marches
Definition: HDDA.h:42
__hostdev__ DDA(const RayT &ray)
ctor from ray and dimension at which the DDA marches
Definition: HDDA.h:225
__hostdev__ void init(const RayT &ray, int dim)
Simular to init above except it uses the bounds of the input ray.
Definition: HDDA.h:70
typename LeafNode< AccT::ValueType >::ChildNodeType ChildT
Definition: HDDA.h:398
__hostdev__ const RayT & ray() const
Definition: HDDA.h:470
A Digital Differential Analyzer. Unlike HDDA (defined above) this DDA uses a fixed step-size defined ...
Definition: HDDA.h:210
typename RayT::RealType RealType
Definition: HDDA.h:399
__hostdev__ void init(const RayT &ray, RealT startTime, RealT maxTime)
Re-initializes the DDA.
Definition: HDDA.h:228
typename RayT::RealType RealType
Definition: HDDA.h:32
__hostdev__ RealType time() const
Return the time (parameterized along the Ray) of the first hit of a tree node of size 2^Log2Dim...
Definition: HDDA.h:127
int MinIndex(const Vec3T &v)
Definition: NanoVDB.h:1251
static T value()
Definition: NanoVDB.h:1077
__hostdev__ TreeMarcher(AccT &acc)
Definition: HDDA.h:403
__hostdev__ int nextAxis() const
Definition: HDDA.h:306
__hostdev__ RayT & ray()
Definition: HDDA.h:472
A Tree Marcher for Point Grids.
Definition: HDDA.h:490
__hostdev__ bool update(const RayT &ray, int dim)
Updates the HDDA to march with the specified dimension.
Definition: HDDA.h:73
#define __hostdev__
Definition: NanoVDB.h:213
__hostdev__ void init(const RayT &ray, RealT startTime, RealT maxTime, int dim)
Re-initializes the HDDA.
Definition: HDDA.h:45
__hostdev__ PointTreeMarcher(AccT &acc)
Definition: HDDA.h:494
RealType RealT
Definition: HDDA.h:33
Signed (i, j, k) 32-bit integer coordinate class, similar to openvdb::math::Coord.
Definition: NanoVDB.h:1301
const std::enable_if<!VecTraits< T >::IsVec, T >::type & min(const T &a, const T &b)
Definition: Composite.h:106
__hostdev__ bool step(const NodeT **node, float &t0, float &t1)
step the ray through the tree. If the ray hits a node then populate t0 & t1, and the node...
Definition: HDDA.h:435
__hostdev__ bool step()
Increment the voxel index to next intersected voxel or node and returns true if the step in time does...
Definition: HDDA.h:95