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