OpenVDB 13.0.1
Loading...
Searching...
No Matches
RayIntersector.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 RayIntersector.h
5///
6/// @author Ken Museth
7///
8/// @brief Accelerated intersection of a ray with a narrow-band level
9/// set or a generic (e.g. density) volume. This will of course be
10/// useful for respectively surface and volume rendering.
11///
12/// @details This file defines two main classes,
13/// LevelSetRayIntersector and VolumeRayIntersector, as well as the
14/// three support classes LevelSetHDDA, VolumeHDDA and LinearSearchImpl.
15/// The LevelSetRayIntersector is templated on the LinearSearchImpl class
16/// and calls instances of the LevelSetHDDA class. The reason to split
17/// level set ray intersection into three classes is twofold. First
18/// LevelSetRayIntersector defines the public API for client code and
19/// LinearSearchImpl defines the actual algorithm used for the
20/// ray level-set intersection. In other words this design will allow
21/// for the public API to be fixed while the intersection algorithm
22/// can change without resolving to (slow) virtual methods. Second,
23/// LevelSetHDDA, which implements a hierarchical Differential Digital
24/// Analyzer, relies on partial template specialization, so it has to
25/// be a standalone class (as opposed to a member class of
26/// LevelSetRayIntersector). The VolumeRayIntersector is conceptually
27/// much simpler than the LevelSetRayIntersector, and hence it only
28/// depends on VolumeHDDA that implements the hierarchical
29/// Differential Digital Analyzer.
30
31
32#ifndef OPENVDB_TOOLS_RAYINTERSECTOR_HAS_BEEN_INCLUDED
33#define OPENVDB_TOOLS_RAYINTERSECTOR_HAS_BEEN_INCLUDED
34
35#include <openvdb/math/DDA.h>
36#include <openvdb/math/Math.h>
37#include <openvdb/math/Ray.h>
39#include <openvdb/Grid.h>
40#include <openvdb/Types.h>
41#include <openvdb/util/Assert.h>
42#include "Morphology.h"
43#include <iostream>
44#include <type_traits>
45
46
47namespace openvdb {
49namespace OPENVDB_VERSION_NAME {
50namespace tools {
51
52// Helper class that implements the actual search of the zero-crossing
53// of the level set along the direction of a ray. This particular
54// implementation uses iterative linear search.
55template<typename GridT, int Iterations = 0, typename RealT = double>
56class LinearSearchImpl;
57
58
59///////////////////////////////////// LevelSetRayIntersector /////////////////////////////////////
60
61
62/// @brief This class provides the public API for intersecting a ray
63/// with a narrow-band level set.
64///
65/// @details It wraps a SearchImplT with a simple public API and
66/// performs the actual hierarchical tree node and voxel traversal.
67///
68/// @warning Use the (default) copy-constructor to make sure each
69/// computational thread has their own instance of this class. This is
70/// important since the SearchImplT contains a ValueAccessor that is
71/// not thread-safe. However copying is very efficient.
72///
73/// @see tools/RayTracer.h for examples of intended usage.
74///
75/// @todo Add TrilinearSearchImpl, as an alternative to LinearSearchImpl,
76/// that performs analytical 3D trilinear intersection tests, i.e., solves
77/// cubic equations. This is slower but also more accurate than the 1D
78/// linear interpolation in LinearSearchImpl.
79template<typename GridT,
80 typename SearchImplT = LinearSearchImpl<GridT>,
81 int NodeLevel = GridT::TreeType::RootNodeType::ChildNodeType::LEVEL,
82 typename RayT = math::Ray<Real> >
84{
85public:
86 using GridType = GridT;
87 using RayType = RayT;
88 using RealType = typename RayT::RealType;
89 using Vec3Type = typename RayT::Vec3T;
90 using ValueT = typename GridT::ValueType;
91 using TreeT = typename GridT::TreeType;
92
93 static_assert(NodeLevel >= -1 && NodeLevel < int(TreeT::DEPTH)-1, "NodeLevel out of range");
94 static_assert(std::is_floating_point<ValueT>::value,
95 "level set grids must have scalar, floating-point value types");
96
97 /// @brief Constructor
98 /// @param grid level set grid to intersect rays against.
99 /// @param isoValue optional iso-value for the ray-intersection.
100 LevelSetRayIntersector(const GridT& grid, const ValueT& isoValue = zeroVal<ValueT>())
101 : mTester(grid, isoValue)
102 {
103 if (!grid.hasUniformVoxels() ) {
104 OPENVDB_THROW(RuntimeError,
105 "LevelSetRayIntersector only supports uniform voxels!");
106 }
107 if (grid.getGridClass() != GRID_LEVEL_SET) {
108 OPENVDB_THROW(RuntimeError,
109 "LevelSetRayIntersector only supports level sets!"
110 "\nUse Grid::setGridClass(openvdb::GRID_LEVEL_SET)");
111 }
112 }
113
114 /// @brief Return the iso-value used for ray-intersections
115 const ValueT& getIsoValue() const { return mTester.getIsoValue(); }
116
117 /// @brief Return @c true if the index-space ray intersects the level set.
118 /// @param iRay ray represented in index space.
119 bool intersectsIS(const RayType& iRay) const
120 {
121 if (!mTester.setIndexRay(iRay)) return false;//missed bbox
123 }
124
125 /// @brief Return @c true if the index-space ray intersects the level set
126 /// @param iRay ray represented in index space.
127 /// @param iTime if an intersection was found it is assigned the time of the
128 /// intersection along the index ray.
129 bool intersectsIS(const RayType& iRay, RealType &iTime) const
130 {
131 if (!mTester.setIndexRay(iRay)) return false;//missed bbox
132 if (!math::LevelSetHDDA<TreeT, NodeLevel>::test(mTester)) return false;//missed level set
133 iTime = mTester.getIndexTime();
134 return true;
135 }
136
137 /// @brief Return @c true if the index-space ray intersects the level set.
138 /// @param iRay ray represented in index space.
139 /// @param xyz if an intersection was found it is assigned the
140 /// intersection point in index space, otherwise it is unchanged.
141 bool intersectsIS(const RayType& iRay, Vec3Type& xyz) const
142 {
143 if (!mTester.setIndexRay(iRay)) return false;//missed bbox
144 if (!math::LevelSetHDDA<TreeT, NodeLevel>::test(mTester)) return false;//missed level set
145 mTester.getIndexPos(xyz);
146 return true;
147 }
148
149 /// @brief Return @c true if the index-space ray intersects the level set.
150 /// @param iRay ray represented in index space.
151 /// @param xyz if an intersection was found it is assigned the
152 /// intersection point in index space, otherwise it is unchanged.
153 /// @param iTime if an intersection was found it is assigned the time of the
154 /// intersection along the index ray.
155 bool intersectsIS(const RayType& iRay, Vec3Type& xyz, RealType &iTime) const
156 {
157 if (!mTester.setIndexRay(iRay)) return false;//missed bbox
158 if (!math::LevelSetHDDA<TreeT, NodeLevel>::test(mTester)) return false;//missed level set
159 mTester.getIndexPos(xyz);
160 iTime = mTester.getIndexTime();
161 return true;
162 }
163
164 /// @brief Return @c true if the world-space ray intersects the level set.
165 /// @param wRay ray represented in world space.
166 bool intersectsWS(const RayType& wRay) const
167 {
168 if (!mTester.setWorldRay(wRay)) return false;//missed bbox
170 }
171
172 /// @brief Return @c true if the world-space ray intersects the level set.
173 /// @param wRay ray represented in world space.
174 /// @param wTime if an intersection was found it is assigned the time of the
175 /// intersection along the world ray.
176 bool intersectsWS(const RayType& wRay, RealType &wTime) const
177 {
178 if (!mTester.setWorldRay(wRay)) return false;//missed bbox
179 if (!math::LevelSetHDDA<TreeT, NodeLevel>::test(mTester)) return false;//missed level set
180 wTime = mTester.getWorldTime();
181 return true;
182 }
183
184 /// @brief Return @c true if the world-space ray intersects the level set.
185 /// @param wRay ray represented in world space.
186 /// @param world if an intersection was found it is assigned the
187 /// intersection point in world space, otherwise it is unchanged
188 bool intersectsWS(const RayType& wRay, Vec3Type& world) const
189 {
190 if (!mTester.setWorldRay(wRay)) return false;//missed bbox
191 if (!math::LevelSetHDDA<TreeT, NodeLevel>::test(mTester)) return false;//missed level set
192 mTester.getWorldPos(world);
193 return true;
194 }
195
196 /// @brief Return @c true if the world-space ray intersects the level set.
197 /// @param wRay ray represented in world space.
198 /// @param world if an intersection was found it is assigned the
199 /// intersection point in world space, otherwise it is unchanged.
200 /// @param wTime if an intersection was found it is assigned the time of the
201 /// intersection along the world ray.
202 bool intersectsWS(const RayType& wRay, Vec3Type& world, RealType &wTime) const
203 {
204 if (!mTester.setWorldRay(wRay)) return false;//missed bbox
205 if (!math::LevelSetHDDA<TreeT, NodeLevel>::test(mTester)) return false;//missed level set
206 mTester.getWorldPos(world);
207 wTime = mTester.getWorldTime();
208 return true;
209 }
210
211 /// @brief Return @c true if the world-space ray intersects the level set.
212 /// @param wRay ray represented in world space.
213 /// @param world if an intersection was found it is assigned the
214 /// intersection point in world space, otherwise it is unchanged.
215 /// @param normal if an intersection was found it is assigned the normal
216 /// of the level set surface in world space, otherwise it is unchanged.
217 bool intersectsWS(const RayType& wRay, Vec3Type& world, Vec3Type& normal) const
218 {
219 if (!mTester.setWorldRay(wRay)) return false;//missed bbox
220 if (!math::LevelSetHDDA<TreeT, NodeLevel>::test(mTester)) return false;//missed level set
221 mTester.getWorldPosAndNml(world, normal);
222 return true;
223 }
224
225 /// @brief Return @c true if the world-space ray intersects the level set.
226 /// @param wRay ray represented in world space.
227 /// @param world if an intersection was found it is assigned the
228 /// intersection point in world space, otherwise it is unchanged.
229 /// @param normal if an intersection was found it is assigned the normal
230 /// of the level set surface in world space, otherwise it is unchanged.
231 /// @param wTime if an intersection was found it is assigned the time of the
232 /// intersection along the world ray.
233 bool intersectsWS(const RayType& wRay, Vec3Type& world, Vec3Type& normal, RealType &wTime) const
234 {
235 if (!mTester.setWorldRay(wRay)) return false;//missed bbox
236 if (!math::LevelSetHDDA<TreeT, NodeLevel>::test(mTester)) return false;//missed level set
237 mTester.getWorldPosAndNml(world, normal);
238 wTime = mTester.getWorldTime();
239 return true;
240 }
241
242private:
243
244 mutable SearchImplT mTester;
245
246};// LevelSetRayIntersector
247
248
249////////////////////////////////////// VolumeRayIntersector //////////////////////////////////////
250
251
252/// @brief This class provides the public API for intersecting a ray
253/// with a generic (e.g. density) volume.
254/// @details Internally it performs the actual hierarchical tree node traversal.
255/// @warning Use the (default) copy-constructor to make sure each
256/// computational thread has their own instance of this class. This is
257/// important since it contains a ValueAccessor that is
258/// not thread-safe and a CoordBBox of the active voxels that should
259/// not be re-computed for each thread. However copying is very efficient.
260/// @par Example:
261/// @code
262/// // Create an instance for the master thread
263/// VolumeRayIntersector inter(grid);
264/// // For each additional thread use the copy constructor. This
265/// // amortizes the overhead of computing the bbox of the active voxels!
266/// VolumeRayIntersector inter2(inter);
267/// // Before each ray-traversal set the index ray.
268/// iter.setIndexRay(ray);
269/// // or world ray
270/// iter.setWorldRay(ray);
271/// // Now you can begin the ray-marching using consecutive calls to VolumeRayIntersector::march
272/// double t0=0, t1=0;// note the entry and exit times are with respect to the INDEX ray
273/// while ( inter.march(t0, t1) ) {
274/// // perform line-integration between t0 and t1
275/// }}
276/// @endcode
277template<typename GridT,
278 int NodeLevel = GridT::TreeType::RootNodeType::ChildNodeType::LEVEL,
279 typename RayT = math::Ray<Real> >
281{
282public:
283 using GridType = GridT;
284 using RayType = RayT;
285 using RealType = typename RayT::RealType;
286 using RootType = typename GridT::TreeType::RootNodeType;
288
289 static_assert(NodeLevel >= 0 && NodeLevel < int(TreeT::DEPTH)-1, "NodeLevel out of range");
290
291 /// @brief Grid constructor
292 /// @param grid Generic grid to intersect rays against.
293 /// @param dilationCount The number of voxel dilations performed
294 /// on (a boolean copy of) the input grid. This allows the
295 /// intersector to account for the size of interpolation kernels
296 /// in client code.
297 /// @throw RuntimeError if the voxels of the grid are not uniform
298 /// or the grid is empty.
299 VolumeRayIntersector(const GridT& grid, int dilationCount = 0)
300 : mIsMaster(true)
301 , mTree(new TreeT(grid.tree(), false, TopologyCopy()))
302 , mGrid(&grid)
303 , mAccessor(*mTree)
304 {
305 if (!grid.hasUniformVoxels() ) {
306 OPENVDB_THROW(RuntimeError,
307 "VolumeRayIntersector only supports uniform voxels!");
308 }
309 if ( grid.empty() ) {
310 OPENVDB_THROW(RuntimeError, "LinearSearchImpl does not supports empty grids");
311 }
312
313 // Dilate active voxels to better account for the size of interpolation kernels
315
316 mTree->root().evalActiveBoundingBox(mBBox, /*visit individual voxels*/false);
317
318 mBBox.max().offset(1);//padding so the bbox of a node becomes (origin,origin + node_dim)
319 }
320
321 /// @brief Grid and BBox constructor
322 /// @param grid Generic grid to intersect rays against.
323 /// @param bbox The axis-aligned bounding-box in the index space of the grid.
324 /// @warning It is assumed that bbox = (min, min + dim) where min denotes
325 /// to the smallest grid coordinates and dim are the integer length of the bbox.
326 /// @throw RuntimeError if the voxels of the grid are not uniform
327 /// or the grid is empty.
329 : mIsMaster(true)
330 , mTree(new TreeT(grid.tree(), false, TopologyCopy()))
331 , mGrid(&grid)
332 , mAccessor(*mTree)
333 , mBBox(bbox)
334 {
335 if (!grid.hasUniformVoxels() ) {
336 OPENVDB_THROW(RuntimeError,
337 "VolumeRayIntersector only supports uniform voxels!");
338 }
339 if ( grid.empty() ) {
340 OPENVDB_THROW(RuntimeError, "LinearSearchImpl does not supports empty grids");
341 }
342 }
343
344 /// @brief Shallow copy constructor
345 /// @warning This copy constructor creates shallow copies of data
346 /// members of the instance passed as the argument. For
347 /// performance reasons we are not using shared pointers (their
348 /// mutex-lock impairs multi-threading).
350 : mIsMaster(false)
351 , mTree(other.mTree)//shallow copy
352 , mGrid(other.mGrid)//shallow copy
353 , mAccessor(*mTree)//initialize new (vs deep copy)
354 , mRay(other.mRay)//deep copy
355 , mTmax(other.mTmax)//deep copy
356 , mBBox(other.mBBox)//deep copy
357 {
358 }
359
360 /// @brief Destructor
361 ~VolumeRayIntersector() { if (mIsMaster) delete mTree; }
362
363 /// @brief Return @c false if the index ray misses the bbox of the grid.
364 /// @param iRay Ray represented in index space.
365 /// @warning Call this method (or setWorldRay) before the ray
366 /// traversal starts and use the return value to decide if further
367 /// marching is required.
368 inline bool setIndexRay(const RayT& iRay)
369 {
370 mRay = iRay;
371 const bool hit = mRay.clip(mBBox);
372 if (hit) mTmax = mRay.t1();
373 return hit;
374 }
375
376 /// @brief Return @c false if the world ray misses the bbox of the grid.
377 /// @param wRay Ray represented in world space.
378 /// @warning Call this method (or setIndexRay) before the ray
379 /// traversal starts and use the return value to decide if further
380 /// marching is required.
381 /// @details Since hit times are computed with respect to the ray
382 /// represented in index space of the current grid, it is
383 /// recommended that either the client code uses getIndexPos to
384 /// compute index position from hit times or alternatively keeps
385 /// an instance of the index ray and instead uses setIndexRay to
386 /// initialize the ray.
387 inline bool setWorldRay(const RayT& wRay)
388 {
389 return this->setIndexRay(wRay.worldToIndex(*mGrid));
390 }
391
392 inline typename RayT::TimeSpan march()
393 {
394 const typename RayT::TimeSpan t = mHDDA.march(mRay, mAccessor);
395 if (t.t1>0) mRay.setTimes(t.t1 + math::Delta<RealType>::value(), mTmax);
396 return t;
397 }
398
399 /// @brief Return @c true if the ray intersects active values,
400 /// i.e. either active voxels or tiles. Only when a hit is
401 /// detected are t0 and t1 updated with the corresponding entry
402 /// and exit times along the INDEX ray!
403 /// @note Note that t0 and t1 are only resolved at the node level
404 /// (e.g. a LeafNode with active voxels) as opposed to the individual
405 /// active voxels.
406 /// @param t0 If the return value > 0 this is the time of the
407 /// first hit of an active tile or leaf.
408 /// @param t1 If the return value > t0 this is the time of the
409 /// first hit (> t0) of an inactive tile or exit point of the
410 /// BBOX for the leaf nodes.
411 /// @warning t0 and t1 are computed with respect to the ray represented in
412 /// index space of the current grid, not world space!
413 inline bool march(RealType& t0, RealType& t1)
414 {
415 const typename RayT::TimeSpan t = this->march();
416 t.get(t0, t1);
417 return t.valid();
418 }
419
420 /// @brief Generates a list of hits along the ray.
421 ///
422 /// @param list List of hits represented as time spans.
423 ///
424 /// @note ListType is a list of RayType::TimeSpan and is required to
425 /// have the two methods: clear() and push_back(). Thus, it could
426 /// be std::vector<typename RayType::TimeSpan> or
427 /// std::deque<typename RayType::TimeSpan>.
428 template <typename ListType>
429 inline void hits(ListType& list)
430 {
431 mHDDA.hits(mRay, mAccessor, list);
432 }
433
434 /// @brief Return the floating-point index position along the
435 /// current index ray at the specified time.
436 inline Vec3R getIndexPos(RealType time) const { return mRay(time); }
437
438 /// @brief Return the floating-point world position along the
439 /// current index ray at the specified time.
440 inline Vec3R getWorldPos(RealType time) const { return mGrid->indexToWorld(mRay(time)); }
441
442 inline RealType getWorldTime(RealType time) const
443 {
444 return time*mGrid->transform().baseMap()->applyJacobian(mRay.dir()).length();
445 }
446
447 /// @brief Return a const reference to the input grid.
448 const GridT& grid() const { return *mGrid; }
449
450 /// @brief Return a const reference to the (potentially dilated)
451 /// bool tree used to accelerate the ray marching.
452 const TreeT& tree() const { return *mTree; }
453
454 /// @brief Return a const reference to the BBOX of the grid
455 const math::CoordBBox& bbox() const { return mBBox; }
456
457 /// @brief Print bbox, statistics, memory usage and other information.
458 /// @param os a stream to which to write textual information
459 /// @param verboseLevel 1: print bbox only; 2: include boolean tree
460 /// statistics; 3: include memory usage
461 void print(std::ostream& os = std::cout, int verboseLevel = 1)
462 {
463 if (verboseLevel>0) {
464 os << "BBox: " << mBBox << std::endl;
465 if (verboseLevel==2) {
466 mTree->print(os, 1);
467 } else if (verboseLevel>2) {
468 mTree->print(os, 2);
469 }
470 }
471 }
472
473private:
474 using AccessorT = typename tree::ValueAccessor<const TreeT,/*IsSafe=*/false>;
475
476 const bool mIsMaster;
477 TreeT* mTree;
478 const GridT* mGrid;
479 AccessorT mAccessor;
480 RayT mRay;
481 RealType mTmax;
482 math::CoordBBox mBBox;
484
485};// VolumeRayIntersector
486
487
488//////////////////////////////////////// LinearSearchImpl ////////////////////////////////////////
489
490
491/// @brief Implements linear iterative search for an iso-value of
492/// the level set along the direction of the ray.
493///
494/// @note Since this class is used internally in
495/// LevelSetRayIntersector (define above) and LevelSetHDDA (defined below)
496/// client code should never interact directly with its API. This also
497/// explains why we are not concerned with the fact that several of
498/// its methods are unsafe to call unless roots were already detected.
499///
500/// @details It is approximate due to the limited number of iterations
501/// which can can be defined with a template parameter. However the default value
502/// has proven surprisingly accurate and fast. In fact more iterations
503/// are not guaranteed to give significantly better results.
504///
505/// @warning Since the root-searching algorithm is approximate
506/// (first-order) it is possible to miss intersections if the
507/// iso-value is too close to the inside or outside of the narrow
508/// band (typically a distance less than a voxel unit).
509///
510/// @warning Since this class internally stores a ValueAccessor it is NOT thread-safe,
511/// so make sure to give each thread its own instance. This of course also means that
512/// the cost of allocating an instance should (if possible) be amortized over
513/// as many ray intersections as possible.
514template<typename GridT, int Iterations, typename RealT>
516{
517public:
520 using ValueT = typename GridT::ValueType;
521 using AccessorT = typename GridT::ConstAccessor;
523
524 /// @brief Constructor from a grid.
525 /// @throw RunTimeError if the grid is empty.
526 /// @throw ValueError if the isoValue is not inside the narrow-band.
527 LinearSearchImpl(const GridT& grid, const ValueT& isoValue = zeroVal<ValueT>())
528 : mStencil(grid),
529 mIsoValue(isoValue),
530 mMinValue(isoValue - ValueT(2 * grid.voxelSize()[0])),
531 mMaxValue(isoValue + ValueT(2 * grid.voxelSize()[0]))
532 {
533 if ( grid.empty() ) {
534 OPENVDB_THROW(RuntimeError, "LinearSearchImpl does not supports empty grids");
535 }
536 if (mIsoValue<= -grid.background() ||
537 mIsoValue>= grid.background() ){
538 OPENVDB_THROW(ValueError, "The iso-value must be inside the narrow-band!");
539 }
540 grid.tree().root().evalActiveBoundingBox(mBBox, /*visit individual voxels*/false);
541 }
542
543 /// @brief Return the iso-value used for ray-intersections
544 const ValueT& getIsoValue() const { return mIsoValue; }
545
546 /// @brief Return @c false if the ray misses the bbox of the grid.
547 /// @param iRay Ray represented in index space.
548 /// @warning Call this method before the ray traversal starts.
549 inline bool setIndexRay(const RayT& iRay)
550 {
551 mRay = iRay;
552 return mRay.clip(mBBox);//did it hit the bbox
553 }
554
555 /// @brief Return @c false if the ray misses the bbox of the grid.
556 /// @param wRay Ray represented in world space.
557 /// @warning Call this method before the ray traversal starts.
558 inline bool setWorldRay(const RayT& wRay)
559 {
560 mRay = wRay.worldToIndex(mStencil.grid());
561 return mRay.clip(mBBox);//did it hit the bbox
562 }
563
564 /// @brief Get the intersection point in index space.
565 /// @param xyz The position in index space of the intersection.
566 inline void getIndexPos(VecT& xyz) const { xyz = mRay(mTime); }
567
568 /// @brief Get the intersection point in world space.
569 /// @param xyz The position in world space of the intersection.
570 inline void getWorldPos(VecT& xyz) const { xyz = mStencil.grid().indexToWorld(mRay(mTime)); }
571
572 /// @brief Get the intersection point and normal in world space
573 /// @param xyz The position in world space of the intersection.
574 /// @param nml The surface normal in world space of the intersection.
575 inline void getWorldPosAndNml(VecT& xyz, VecT& nml)
576 {
577 this->getIndexPos(xyz);
578 mStencil.moveTo(xyz);
579 nml = mStencil.gradient(xyz);
580 nml.normalize();
581 xyz = mStencil.grid().indexToWorld(xyz);
582 }
583
584 /// @brief Return the time of intersection along the index ray.
585 inline RealT getIndexTime() const { return mTime; }
586
587 /// @brief Return the time of intersection along the world ray.
588 inline RealT getWorldTime() const
589 {
590 return mTime*mStencil.grid().transform().baseMap()->applyJacobian(mRay.dir()).length();
591 }
592
593private:
594
595 /// @brief Initiate the local voxel intersection test.
596 /// @warning Make sure to call this method before the local voxel intersection test.
597 inline void init(RealT t0)
598 {
599 mT[0] = t0;
600 mV[0] = static_cast<ValueT>(this->interpValue(t0));
601 }
602
603 inline void setRange(RealT t0, RealT t1) { mRay.setTimes(t0, t1); }
604
605 /// @brief Return a const reference to the ray.
606 inline const RayT& ray() const { return mRay; }
607
608 /// @brief Return true if a node of the specified type exists at ijk.
609 template <typename NodeT>
610 inline bool hasNode(const Coord& ijk)
611 {
612 return mStencil.accessor().template probeConstNode<NodeT>(ijk) != nullptr;
613 }
614
615 /// @brief Return @c true if an intersection is detected.
616 /// @param ijk Grid coordinate of the node origin or voxel being tested.
617 /// @param time Time along the index ray being tested.
618 /// @warning Only if an intersection is detected is it safe to
619 /// call getIndexPos, getWorldPos and getWorldPosAndNml!
620 inline bool operator()(const Coord& ijk, RealT time)
621 {
622 ValueT V;
623 if (mStencil.accessor().probeValue(ijk, V) &&//within narrow band
624 V>mMinValue && V<mMaxValue) {// and close to iso-value?
625 mT[1] = time;
626 mV[1] = static_cast<ValueT>(this->interpValue(time));
627 if (math::ZeroCrossing(mV[0], mV[1])) {
628 mTime = this->interpTime();
630 for (int n=0; Iterations>0 && n<Iterations; ++n) {//resolved at compile-time
631 V = static_cast<ValueT>(this->interpValue(mTime));
632 const int m = math::ZeroCrossing(mV[0], V) ? 1 : 0;
633 mV[m] = V;
634 mT[m] = mTime;
635 mTime = this->interpTime();
636 }
638 return true;
639 }
640 mT[0] = mT[1];
641 mV[0] = mV[1];
642 }
643 return false;
644 }
645
646 inline RealT interpTime()
647 {
648 OPENVDB_ASSERT( math::isApproxLarger(mT[1], mT[0], RealT(1e-6) ) );
649 return mT[0]+(mT[1]-mT[0])*mV[0]/(mV[0]-mV[1]);
650 }
651
652 inline RealT interpValue(RealT time)
653 {
654 const VecT pos = mRay(time);
655 mStencil.moveTo(pos);
656 return mStencil.interpolation(pos) - mIsoValue;
657 }
658
659 template<typename, int> friend struct math::LevelSetHDDA;
660
661 RayT mRay;
662 StencilT mStencil;
663 RealT mTime;//time of intersection
664 ValueT mV[2];
665 RealT mT[2];
666 const ValueT mIsoValue, mMinValue, mMaxValue;
667 math::CoordBBox mBBox;
668};// LinearSearchImpl
669
670} // namespace tools
671} // namespace OPENVDB_VERSION_NAME
672} // namespace openvdb
673
674#endif // OPENVDB_TOOLS_RAYINTERSECTOR_HAS_BEEN_INCLUDED
#define OPENVDB_ASSERT(X)
Definition Assert.h:41
Digital Differential Analyzers specialized for VDB.
General-purpose arithmetic and comparison routines, most of which accept arbitrary value types (or at...
Implementation of morphological dilation and erosion.
#define OPENVDB_NO_UNREACHABLE_CODE_WARNING_END
Definition Platform.h:164
#define OPENVDB_NO_UNREACHABLE_CODE_WARNING_BEGIN
Definition Platform.h:163
Tag dispatch class that distinguishes topology copy constructors from deep copy constructors.
Definition Types.h:754
Definition Stencils.h:301
Axis-aligned bounding box of signed integer coordinates.
Definition Coord.h:252
Definition Ray.h:28
Ray worldToIndex(const GridType &grid) const
Return a new ray in the index space of the specified grid, assuming the existing ray is represented i...
Definition Ray.h:172
bool clip(const Vec3T &center, RealT radius)
Return true if this ray intersects the specified sphere.
Definition Ray.h:218
Definition Vec3.h:25
bool normalize(T eps=T(1.0e-7))
this = normalized this
Definition Vec3.h:363
Helper class that implements Hierarchical Digital Differential Analyzers for ray intersections agains...
Definition DDA.h:189
bool intersectsWS(const RayType &wRay) const
Return true if the world-space ray intersects the level set.
Definition RayIntersector.h:166
bool intersectsWS(const RayType &wRay, Vec3Type &world, RealType &wTime) const
Return true if the world-space ray intersects the level set.
Definition RayIntersector.h:202
bool intersectsIS(const RayType &iRay, Vec3Type &xyz) const
Return true if the index-space ray intersects the level set.
Definition RayIntersector.h:141
typename GridT::TreeType TreeT
Definition RayIntersector.h:91
const ValueT & getIsoValue() const
Return the iso-value used for ray-intersections.
Definition RayIntersector.h:115
bool intersectsIS(const RayType &iRay, Vec3Type &xyz, RealType &iTime) const
Return true if the index-space ray intersects the level set.
Definition RayIntersector.h:155
LevelSetRayIntersector(const GridT &grid, const ValueT &isoValue=zeroVal< ValueT >())
Constructor.
Definition RayIntersector.h:100
RayT RayType
Definition RayIntersector.h:87
bool intersectsWS(const RayType &wRay, RealType &wTime) const
Return true if the world-space ray intersects the level set.
Definition RayIntersector.h:176
bool intersectsIS(const RayType &iRay) const
Return true if the index-space ray intersects the level set.
Definition RayIntersector.h:119
typename RayT::Vec3T Vec3Type
Definition RayIntersector.h:89
bool intersectsWS(const RayType &wRay, Vec3Type &world) const
Return true if the world-space ray intersects the level set.
Definition RayIntersector.h:188
bool intersectsWS(const RayType &wRay, Vec3Type &world, Vec3Type &normal) const
Return true if the world-space ray intersects the level set.
Definition RayIntersector.h:217
typename GridT::ValueType ValueT
Definition RayIntersector.h:90
typename RayT::RealType RealType
Definition RayIntersector.h:88
GridT GridType
Definition RayIntersector.h:86
bool intersectsWS(const RayType &wRay, Vec3Type &world, Vec3Type &normal, RealType &wTime) const
Return true if the world-space ray intersects the level set.
Definition RayIntersector.h:233
bool intersectsIS(const RayType &iRay, RealType &iTime) const
Return true if the index-space ray intersects the level set.
Definition RayIntersector.h:129
bool setIndexRay(const RayT &iRay)
Return false if the ray misses the bbox of the grid.
Definition RayIntersector.h:549
void getIndexPos(VecT &xyz) const
Get the intersection point in index space.
Definition RayIntersector.h:566
RealT getIndexTime() const
Return the time of intersection along the index ray.
Definition RayIntersector.h:585
LinearSearchImpl(const GridT &grid, const ValueT &isoValue=zeroVal< ValueT >())
Constructor from a grid.
Definition RayIntersector.h:527
math::BoxStencil< GridT > StencilT
Definition RayIntersector.h:522
const ValueT & getIsoValue() const
Return the iso-value used for ray-intersections.
Definition RayIntersector.h:544
math::Vec3< RealT > VecT
Definition RayIntersector.h:519
typename GridT::ConstAccessor AccessorT
Definition RayIntersector.h:521
math::Ray< RealT > RayT
Definition RayIntersector.h:518
typename GridT::ValueType ValueT
Definition RayIntersector.h:520
bool setWorldRay(const RayT &wRay)
Return false if the ray misses the bbox of the grid.
Definition RayIntersector.h:558
RealT getWorldTime() const
Return the time of intersection along the world ray.
Definition RayIntersector.h:588
void getWorldPos(VecT &xyz) const
Get the intersection point in world space.
Definition RayIntersector.h:570
void getWorldPosAndNml(VecT &xyz, VecT &nml)
Get the intersection point and normal in world space.
Definition RayIntersector.h:575
bool setIndexRay(const RayT &iRay)
Return false if the index ray misses the bbox of the grid.
Definition RayIntersector.h:368
const math::CoordBBox & bbox() const
Return a const reference to the BBOX of the grid.
Definition RayIntersector.h:455
typename GridT::TreeType::RootNodeType RootType
Definition RayIntersector.h:286
~VolumeRayIntersector()
Destructor.
Definition RayIntersector.h:361
VolumeRayIntersector(const VolumeRayIntersector &other)
Shallow copy constructor.
Definition RayIntersector.h:349
VolumeRayIntersector(const GridT &grid, const math::CoordBBox &bbox)
Grid and BBox constructor.
Definition RayIntersector.h:328
RealType getWorldTime(RealType time) const
Definition RayIntersector.h:442
bool march(RealType &t0, RealType &t1)
Return true if the ray intersects active values, i.e. either active voxels or tiles....
Definition RayIntersector.h:413
void print(std::ostream &os=std::cout, int verboseLevel=1)
Print bbox, statistics, memory usage and other information.
Definition RayIntersector.h:461
tree::Tree< typename RootType::template ValueConverter< bool >::Type > TreeT
Definition RayIntersector.h:287
Vec3R getWorldPos(RealType time) const
Return the floating-point world position along the current index ray at the specified time.
Definition RayIntersector.h:440
RayT RayType
Definition RayIntersector.h:284
void hits(ListType &list)
Generates a list of hits along the ray.
Definition RayIntersector.h:429
const TreeT & tree() const
Return a const reference to the (potentially dilated) bool tree used to accelerate the ray marching.
Definition RayIntersector.h:452
const GridT & grid() const
Return a const reference to the input grid.
Definition RayIntersector.h:448
VolumeRayIntersector(const GridT &grid, int dilationCount=0)
Grid constructor.
Definition RayIntersector.h:299
bool setWorldRay(const RayT &wRay)
Return false if the world ray misses the bbox of the grid.
Definition RayIntersector.h:387
Vec3R getIndexPos(RealType time) const
Return the floating-point index position along the current index ray at the specified time.
Definition RayIntersector.h:436
typename RayT::RealType RealType
Definition RayIntersector.h:285
GridT GridType
Definition RayIntersector.h:283
RayT::TimeSpan march()
Definition RayIntersector.h:392
Definition Tree.h:195
static const Index DEPTH
Definition Tree.h:205
@ NN_FACE
Definition Morphology.h:60
void dilateActiveValues(TreeOrLeafManagerT &tree, const int iterations=1, const NearestNeighbors nn=NN_FACE, const TilePolicy mode=PRESERVE_TILES, const bool threaded=true)
Topologically dilate all active values (i.e. both voxels and tiles) in a tree using one of three near...
Definition Morphology.h:1057
@ IGNORE_TILES
Definition Morphology.h:82
ValueAccessorImpl< TreeType, IsSafe, MutexType, openvdb::make_index_sequence< CacheLevels > > ValueAccessor
Default alias for a ValueAccessor. This is simply a helper alias for the generic definition but takes...
Definition ValueAccessor.h:86
@ GRID_LEVEL_SET
Definition Types.h:526
constexpr T zeroVal()
Return the value of type T that corresponds to zero.
Definition Math.h:71
math::Vec3< Real > Vec3R
Definition Types.h:53
Definition Exceptions.h:13
A Ray class.
Defines various finite difference stencils by means of the "curiously recurring template pattern" on ...
static T value()
Definition Math.h:167
Helper class that implements Hierarchical Digital Differential Analyzers and is specialized for ray i...
Definition DDA.h:146
static bool test(TesterT &tester)
Definition DDA.h:151
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition version.h.in:121
#define OPENVDB_USE_VERSION_NAMESPACE
Definition version.h.in:218