|
@@ -8,6 +8,7 @@
|
|
|
#include "ray_box_intersect.h"
|
|
#include "ray_box_intersect.h"
|
|
|
#include <array>
|
|
#include <array>
|
|
|
#include <igl/matlab_format.h>
|
|
#include <igl/matlab_format.h>
|
|
|
|
|
+#include <igl/increment_ulp.h>
|
|
|
|
|
|
|
|
template <
|
|
template <
|
|
|
typename Derivedsource,
|
|
typename Derivedsource,
|
|
@@ -15,102 +16,26 @@ template <
|
|
|
typename Scalar>
|
|
typename Scalar>
|
|
|
IGL_INLINE bool igl::ray_box_intersect(
|
|
IGL_INLINE bool igl::ray_box_intersect(
|
|
|
const Eigen::MatrixBase<Derivedsource> & origin,
|
|
const Eigen::MatrixBase<Derivedsource> & origin,
|
|
|
- const Eigen::MatrixBase<Deriveddir> & dir,
|
|
|
|
|
|
|
+ const Eigen::MatrixBase<Deriveddir> & inv_dir,
|
|
|
|
|
+ const Eigen::MatrixBase<Deriveddir> & inv_dir_pad,
|
|
|
const Eigen::AlignedBox<Scalar,3> & box,
|
|
const Eigen::AlignedBox<Scalar,3> & box,
|
|
|
const Scalar & t0,
|
|
const Scalar & t0,
|
|
|
const Scalar & t1,
|
|
const Scalar & t1,
|
|
|
Scalar & tmin,
|
|
Scalar & tmin,
|
|
|
Scalar & tmax)
|
|
Scalar & tmax)
|
|
|
{
|
|
{
|
|
|
-#ifdef false
|
|
|
|
|
- // https://github.com/RMonica/basic_next_best_view/blob/master/src/RayTracer.cpp
|
|
|
|
|
- const auto & intersectRayBox = [](
|
|
|
|
|
- const Eigen::Vector3f& rayo,
|
|
|
|
|
- const Eigen::Vector3f& rayd,
|
|
|
|
|
- const Eigen::Vector3f& bmin,
|
|
|
|
|
- const Eigen::Vector3f& bmax,
|
|
|
|
|
- float & tnear,
|
|
|
|
|
- float & tfar
|
|
|
|
|
- )->bool
|
|
|
|
|
- {
|
|
|
|
|
- Eigen::Vector3f bnear;
|
|
|
|
|
- Eigen::Vector3f bfar;
|
|
|
|
|
- // Checks for intersection testing on each direction coordinate
|
|
|
|
|
- // Computes
|
|
|
|
|
- float t1, t2;
|
|
|
|
|
- tnear = -1e+6f, tfar = 1e+6f; //, tCube;
|
|
|
|
|
- bool intersectFlag = true;
|
|
|
|
|
- for (int i = 0; i < 3; ++i) {
|
|
|
|
|
- // std::cout << "coordinate " << i << ": bmin " << bmin(i) << ", bmax " << bmax(i) << std::endl;
|
|
|
|
|
- assert(bmin(i) <= bmax(i));
|
|
|
|
|
- if (::fabs(rayd(i)) < 1e-6) { // Ray parallel to axis i-th
|
|
|
|
|
- if (rayo(i) < bmin(i) || rayo(i) > bmax(i)) {
|
|
|
|
|
- intersectFlag = false;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- else {
|
|
|
|
|
- // Finds the nearest and the farthest vertices of the box from the ray origin
|
|
|
|
|
- if (::fabs(bmin(i) - rayo(i)) < ::fabs(bmax(i) - rayo(i))) {
|
|
|
|
|
- bnear(i) = bmin(i);
|
|
|
|
|
- bfar(i) = bmax(i);
|
|
|
|
|
- }
|
|
|
|
|
- else {
|
|
|
|
|
- bnear(i) = bmax(i);
|
|
|
|
|
- bfar(i) = bmin(i);
|
|
|
|
|
- }
|
|
|
|
|
- // std::cout << " bnear " << bnear(i) << ", bfar " << bfar(i) << std::endl;
|
|
|
|
|
- // Finds the distance parameters t1 and t2 of the two ray-box intersections:
|
|
|
|
|
- // t1 must be the closest to the ray origin rayo.
|
|
|
|
|
- t1 = (bnear(i) - rayo(i)) / rayd(i);
|
|
|
|
|
- t2 = (bfar(i) - rayo(i)) / rayd(i);
|
|
|
|
|
- if (t1 > t2) {
|
|
|
|
|
- std::swap(t1,t2);
|
|
|
|
|
- }
|
|
|
|
|
- // The two intersection values are used to saturate tnear and tfar
|
|
|
|
|
- if (t1 > tnear) {
|
|
|
|
|
- tnear = t1;
|
|
|
|
|
- }
|
|
|
|
|
- if (t2 < tfar) {
|
|
|
|
|
- tfar = t2;
|
|
|
|
|
- }
|
|
|
|
|
- // std::cout << " t1 " << t1 << ", t2 " << t2 << ", tnear " << tnear << ", tfar " << tfar
|
|
|
|
|
- // << " tnear > tfar? " << (tnear > tfar) << ", tfar < 0? " << (tfar < 0) << std::endl;
|
|
|
|
|
- if(tnear > tfar) {
|
|
|
|
|
- intersectFlag = false;
|
|
|
|
|
- }
|
|
|
|
|
- if(tfar < 0) {
|
|
|
|
|
- intersectFlag = false;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- // Checks whether intersection occurs or not
|
|
|
|
|
- return intersectFlag;
|
|
|
|
|
- };
|
|
|
|
|
- float tmin_f, tmax_f;
|
|
|
|
|
- bool ret = intersectRayBox(
|
|
|
|
|
- origin. template cast<float>(),
|
|
|
|
|
- dir. template cast<float>(),
|
|
|
|
|
- box.min().template cast<float>(),
|
|
|
|
|
- box.max().template cast<float>(),
|
|
|
|
|
- tmin_f,
|
|
|
|
|
- tmax_f);
|
|
|
|
|
- tmin = tmin_f;
|
|
|
|
|
- tmax = tmax_f;
|
|
|
|
|
- return ret;
|
|
|
|
|
-#else
|
|
|
|
|
using namespace Eigen;
|
|
using namespace Eigen;
|
|
|
- // This should be precomputed and provided as input
|
|
|
|
|
typedef Matrix<Scalar,1,3> RowVector3S;
|
|
typedef Matrix<Scalar,1,3> RowVector3S;
|
|
|
- const RowVector3S inv_dir( 1./dir(0),1./dir(1),1./dir(2));
|
|
|
|
|
const std::array<bool, 3> sign = { inv_dir(0)<0, inv_dir(1)<0, inv_dir(2)<0};
|
|
const std::array<bool, 3> sign = { inv_dir(0)<0, inv_dir(1)<0, inv_dir(2)<0};
|
|
|
// http://people.csail.mit.edu/amy/papers/box-jgt.pdf
|
|
// http://people.csail.mit.edu/amy/papers/box-jgt.pdf
|
|
|
// "An Efficient and Robust Ray–Box Intersection Algorithm"
|
|
// "An Efficient and Robust Ray–Box Intersection Algorithm"
|
|
|
|
|
+ // corrected in "Robust BVH Ray Traversal" by Thiago Ize, section 3:
|
|
|
Scalar tymin, tymax, tzmin, tzmax;
|
|
Scalar tymin, tymax, tzmin, tzmax;
|
|
|
std::array<RowVector3S, 2> bounds = {box.min().array(),box.max().array()};
|
|
std::array<RowVector3S, 2> bounds = {box.min().array(),box.max().array()};
|
|
|
tmin = ( bounds[sign[0]](0) - origin(0)) * inv_dir(0);
|
|
tmin = ( bounds[sign[0]](0) - origin(0)) * inv_dir(0);
|
|
|
- tmax = ( bounds[1-sign[0]](0) - origin(0)) * inv_dir(0);
|
|
|
|
|
|
|
+ tmax = ( bounds[1-sign[0]](0) - origin(0)) * inv_dir_pad(0);
|
|
|
tymin = (bounds[sign[1]](1) - origin(1)) * inv_dir(1);
|
|
tymin = (bounds[sign[1]](1) - origin(1)) * inv_dir(1);
|
|
|
- tymax = (bounds[1-sign[1]](1) - origin(1)) * inv_dir(1);
|
|
|
|
|
|
|
+ tymax = (bounds[1-sign[1]](1) - origin(1)) * inv_dir_pad(1);
|
|
|
// NaN-safe min and max
|
|
// NaN-safe min and max
|
|
|
const auto berger_perrin_min = [&](
|
|
const auto berger_perrin_min = [&](
|
|
|
const Scalar a,
|
|
const Scalar a,
|
|
@@ -124,32 +49,51 @@ IGL_INLINE bool igl::ray_box_intersect(
|
|
|
{
|
|
{
|
|
|
return (a > b) ? a : b;
|
|
return (a > b) ? a : b;
|
|
|
};
|
|
};
|
|
|
-
|
|
|
|
|
if ( (tmin > tymax) || (tymin > tmax) )
|
|
if ( (tmin > tymax) || (tymin > tmax) )
|
|
|
{
|
|
{
|
|
|
return false;
|
|
return false;
|
|
|
}
|
|
}
|
|
|
- tmin = berger_perrin_max(tmin,tymin);
|
|
|
|
|
- tmax = berger_perrin_min(tmax,tymax);
|
|
|
|
|
|
|
+ tmin = berger_perrin_max(tmin, tymin);
|
|
|
|
|
+ tmax = berger_perrin_min(tmax, tymax);
|
|
|
tzmin = (bounds[sign[2]](2) - origin(2)) * inv_dir(2);
|
|
tzmin = (bounds[sign[2]](2) - origin(2)) * inv_dir(2);
|
|
|
- tzmax = (bounds[1-sign[2]](2) - origin(2)) * inv_dir(2);
|
|
|
|
|
- if ( (tmin > tzmax) || (tzmin > tmax) )
|
|
|
|
|
- {
|
|
|
|
|
- return false;
|
|
|
|
|
- }
|
|
|
|
|
- tmin = berger_perrin_max(tmin,tzmin);
|
|
|
|
|
- tmax = berger_perrin_min(tmax,tzmax);
|
|
|
|
|
- if(!( (tmin < t1) && (tmax > t0) ))
|
|
|
|
|
|
|
+ tzmax = (bounds[1-sign[2]](2) - origin(2)) * inv_dir_pad(2);
|
|
|
|
|
+ if ((tmin > tzmax) || (tzmin > tmax))
|
|
|
{
|
|
{
|
|
|
return false;
|
|
return false;
|
|
|
}
|
|
}
|
|
|
- return true;
|
|
|
|
|
-#endif
|
|
|
|
|
|
|
+ tmin = berger_perrin_max(tmin, tzmin);
|
|
|
|
|
+ tmax = berger_perrin_min(tmax, tzmax);
|
|
|
|
|
+ return ((tmin < t1) && (tmax > t0));
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+template <
|
|
|
|
|
+ typename Derivedsource,
|
|
|
|
|
+ typename Deriveddir,
|
|
|
|
|
+ typename Scalar>
|
|
|
|
|
+IGL_INLINE bool igl::ray_box_intersect(
|
|
|
|
|
+ const Eigen::MatrixBase<Derivedsource> & origin,
|
|
|
|
|
+ const Eigen::MatrixBase<Deriveddir> & dir,
|
|
|
|
|
+ const Eigen::AlignedBox<Scalar,3> & box,
|
|
|
|
|
+ const Scalar & t0,
|
|
|
|
|
+ const Scalar & t1,
|
|
|
|
|
+ Scalar & tmin,
|
|
|
|
|
+ Scalar & tmax)
|
|
|
|
|
+{
|
|
|
|
|
+ // precompute the inv_dir
|
|
|
|
|
+ Eigen::Matrix<Scalar, 1, 3> inv_dir = dir.cwiseInverse();
|
|
|
|
|
+ // see "Robust BVH Ray Traversal" by Thiago Ize, section 3:
|
|
|
|
|
+ // for why we need this
|
|
|
|
|
+ Eigen::Matrix<Scalar, 1, 3> inv_dir_pad = inv_dir;
|
|
|
|
|
+ igl::increment_ulp(inv_dir_pad, 2);
|
|
|
|
|
+ return igl::ray_box_intersect(origin, inv_dir, inv_dir_pad, box, t0, t1, tmin, tmax);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
#ifdef IGL_STATIC_LIBRARY
|
|
#ifdef IGL_STATIC_LIBRARY
|
|
|
// Explicit template instantiation
|
|
// Explicit template instantiation
|
|
|
// generated by autoexplicit.sh
|
|
// generated by autoexplicit.sh
|
|
|
|
|
+template bool igl::ray_box_intersect<Eigen::Matrix<float, 1, 3, 1, 1, 3>, Eigen::Matrix<float, 1, 3, 1, 1, 3>, float>(Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, Eigen::AlignedBox<float, 3> const&, float const&, float const&, float&, float&);
|
|
|
|
|
+template bool igl::ray_box_intersect<Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, double>(Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::AlignedBox<double, 3> const&, double const&, double const&, double&, double&);
|
|
|
|
|
+template bool igl::ray_box_intersect<Eigen::Matrix<float, 3, 1, 0, 3, 1>, Eigen::Matrix<float, 3, 1, 0, 3, 1>, float>(Eigen::MatrixBase<Eigen::Matrix<float, 3, 1, 0, 3, 1>> const&, Eigen::MatrixBase<Eigen::Matrix<float, 3, 1, 0, 3, 1>> const&, Eigen::AlignedBox<float, 3> const&, float const&, float const&, float&, float&);
|
|
|
template bool igl::ray_box_intersect<Eigen::Matrix<float, 1, 3, 1, 1, 3>, Eigen::Matrix<float, 1, 3, 1, 1, 3>, float>(Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, Eigen::AlignedBox<float, 3> const&, float const&, float const&, float&, float&);
|
|
template bool igl::ray_box_intersect<Eigen::Matrix<float, 1, 3, 1, 1, 3>, Eigen::Matrix<float, 1, 3, 1, 1, 3>, float>(Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, Eigen::AlignedBox<float, 3> const&, float const&, float const&, float&, float&);
|
|
|
template bool igl::ray_box_intersect<Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, double>(Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::AlignedBox<double, 3> const&, double const&, double const&, double&, double&);
|
|
template bool igl::ray_box_intersect<Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, double>(Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::AlignedBox<double, 3> const&, double const&, double const&, double&, double&);
|
|
|
#endif
|
|
#endif
|