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