<p>Here is how I found this can be solved.</p>

<p>(The below also happens at the start, just fyi)</p>

<pre><code>  float tmin = std::numeric_limits&lt;float&gt;::lowest();
  float tmax = std::numeric_limits&lt;float&gt;::max();
</code></pre>

<p>Add an additional check:</p>

<pre><code>if(rayDir.x == 0.0f)
{
  if (rayOrigin.x() &lt; box.min.x() || rayOrigin.x() &gt; box.max.x())
  {     
    return false;
  }
}
else 
{
  tx1 = (box.min.x - rayOrigin.x) * invRay.x;
  tx2 = (box.max.x - rayOrigin.x) * invRay.x;

  tmin = std::max(tmin, std::min(tx1, tx2));
  tmax = std::min(tmax, std::max(tx1, tx2));
}
</code></pre>

<p>This way the tx1/tx2 values never get calculated if the ray's direction vector is zero in that direction, aka if it's parallel to that plane.</p>

<p>It's not particularly compact or pretty, but it does neatly solve the issue.</p>

CC BY-SA 4.0
2020-02-03T21:09:26.303Z
@DanielMGessel Could you clarify what you mean by that?
Tyler Shellberg
CC BY-SA 4.0
2020-02-04T15:48:31.670Z
@DanielMGessel How is checking what type of ray, then choosing a function, rather than the function determining it any faster? Either way, the exact same checks need to happen on the ray. It doesn't seem like less work is being done.
Tyler Shellberg
CC BY-SA 4.0
2020-02-04T18:24:31.780Z
@DanielMGessel No, this is not part of a traversal for a BVH. Thank you in any case.
Tyler Shellberg
CC BY-SA 4.0
2020-02-03T19:24:32.273Z
2020-02-03T19:24:32.273Z
Tyler Shellberg
<p>This is a C++ implementation. Slab is the space between a pair of parallel planes.Test if ray R(t) = p + t * d intersect against bounding box bb.</p>

<pre><code>bool IntersectRayBB( const double* p, const double* d, const BoundingBox&amp; bb, double&amp; tmin, double* q )
{
    double tolerance = 1e-9;
    tmin = 0.0;
    double tmax = FLOAT32_MAX; // Set to max distance ray can travel
    for( int i = 0; i &lt; 3; i++ )
    {
        if( Abs( d[i] ) &lt; tolerance )
        {
            // Ray is parallel to slab. No hit if origin not within slab.
            if( p[i] &lt; bb.min[i] || p[i] &gt; bb.max[i] )
                return false;
        }
        else
        {
            // Compute intersection t value of ray within near and far plane of slab
            double denom = 1.0 / d[i];
            double t1 = ( bb.min[i] - p[i] ) * denom;
            double t2 = ( bb.max[i] - p[i] ) * denom;
            // Make t1 be intersection with near plane, t2 with far plane
            if( t1 &gt; t2 )
                std::Swap( t1, t2 );
            // Compute the intersection of slab intersection intervals
            if( t1 &gt; tmin )
                tmin = t1;
            if( t2 &gt; tmax )
                tmax = t2;
            // Exit with no collision as soon as slab intersection becomes empty
            if( tmin &gt; tmax )
                return false;
        }
    }

    //Ray intersects all 3 slabs. Return point (q) and intersesction t value (tmin)
    q = p + d * tmin;
    return true;
}
</code></pre>

CC BY-SA 4.0
2020-02-24T07:30:47.797Z
2020-02-24T07:30:47.797Z
Lion King
<p>I've seen lots of spins on the ray-box intersection test, and a lot of them seem to boil down to this code: (omitting some details here)</p>

<pre><code>  invRay.x = 1.0 / ray.x;

  tx1 = (box.min.x - rayOrigin.x) * invRay.x;
  tx2 = (box.max.x - rayOrigin.x) * invRay.x;

  tmin = min(tx1, tx2);
  tmax = max(tx1, tx2);

  // Repeat for Y and Z
  // Then check to ensure tmin &lt; tmax
</code></pre>

<p>(I got mine specifically from <a href="https://gamedev.stackexchange.com/questions/18436/most-efficient-aabb-vs-ray-collision-algorithms">this discussion</a> and <a href="https://tavianator.com/cgit/dimension.git/tree/libdimension/bvh/bvh.c#n196" rel="nofollow noreferrer">this source</a>. Also note that if you use std::min and std::max, it's far from branchless)</p>

<p>However, this raises a significant problem.</p>

<p>What if the ray's origin in one or more dimensions is equal to the min or max points?</p>

<p>What I found is that I get this situation on an example ray and box:</p>

<ul>
<li>Ray origin: (3.225, 0.243, 2.221)</li>
<li>Ray direction: (0, 0, -1)</li>
<li>Box min: (3.223, 0.241, 2.119)</li>
<li>Box max: (3.225, 0.243, 2.121)</li>
</ul>

<p>Is that when tx1 is calculated, it correctly gets -inf. However, when tx2 is calculated, it gets <code>(3.225 - 3.225) * inf</code> which is coming out to <code>-nan</code>. This means that later, when we do:</p>

<p><code>float tmax = std::max(tx1, tx2);</code></p>

<p>We get <code>max(-inf, -nan)</code> which comes out to <code>-inf</code> and from that point on in the tests, tmax will always be -inf, making the overall ray-box test fail.</p>

<p>This is confirmed by some comments on the page where I got the code:</p>

<blockquote>
  <p>Something to consider here is that 0 * inf =nan which occurs when the ray starts exactly on the edge of a box</p>
</blockquote>

<p>And</p>

<blockquote>
  <p>Having read both this and part 2, I'm unable to work out what changes I need to make in order to reliably detect intersections when a ray is exactly on the edge of an AABB.</p>
</blockquote>

<p>Does anyone know a fast method for ray-box intersection with edge and corner hits?</p>

<p>I should note <strong>this is not being used with a BVH</strong>. I need an <strong>exact</strong> intersection test, I cannot increase the size of the box at all.</p>

CC BY-SA 4.0
2020-02-02T00:30:22.097Z
I think the pragmatic fix for BVH use would be to inflate the boxes by 1 ulps. I suspect that would beat any fix I can think of as all of them involve several extra instructions. I will keep thinking about it though, it is an interesting problem.
Olivier
CC BY-SA 4.0
2020-02-03T02:50:16.907Z
Making the boxes physically larger in my case would make the results totally worthless. I can check if the result is NAN but that doesn't guarantee a hit, only that the origin started on one of those dimensions.Also, making them larger would just mean it would be the same problem, just at a different point in space, no? Or do you mean, if I detect a nan, extend the box and then try again?
Tyler Shellberg
CC BY-SA 4.0
2020-02-04T01:13:51.653Z
@TylerShellberg I meant always make them larger. This will give a tiny % of false positives, which for a BVH is of no importance. If you require an exact intersection test, you might want to edit your question to specify that and also if you care about fixing the problem on both the min/max side of each axis or only on one side.
Olivier
CC BY-SA 4.0
2020-02-04T18:25:33.103Z
@Oliver I am not using this for a BVH.
Tyler Shellberg
CC BY-SA 4.0
2020-02-05T20:42:34.040Z
This post may help you: https://tavianator.com/fast-branchless-raybounding-box-intersections-part-2-nans/. It presents this specific issue and a workaround for it.
Razakhel
CC BY-SA 4.0
2020-02-05T21:39:30.547Z
@Razakhel Sadly, that post details a solution where plane-hits like I describe are *ignored*, rather than treated as hits. I actually need them in my case. They specify this, with: *"Since this is an edge case, you might wonder why we don't choose to return true instead of false for rays on the boundary. **It turns out to be much harder to get this behavior with efficient code.**"*
Tyler Shellberg
CC BY-SA 4.0
2022-09-19T19:11:27.590Z
@TylerShellberg I did say that, but it's actually not that hard at all: https://tavianator.com/2022/ray_box_boundary.html#boundaries
Tavian Barnes
<raytracing>
Need a fast ray-box intersection that handles if a ray is parallel and in line with a plane of the box
Tyler Shellberg
# Need a fast ray-box intersection that handles if a ray is parallel and in line with a plane of the box

(Asked by: username_0 on 2020-01-31)

I've seen lots of spins on the ray-box intersection test, and a lot of them seem to boil down to this code: (omitting some details here)

```
  invRay.x = 1.0 / ray.x;

  tx1 = (box.min.x - rayOrigin.x) * invRay.x;
  tx2 = (box.max.x - rayOrigin.x) * invRay.x;

  tmin = min(tx1, tx2);
  tmax = max(tx1, tx2);

  // Repeat for Y and Z
  // Then check to ensure tmin < tmax

```

(I got mine specifically from [this discussion](https://gamedev.stackexchange.com/questions/18436/most-efficient-aabb-vs-ray-collision-algorithms) and [this source](https://tavianator.com/cgit/dimension.git/tree/libdimension/bvh/bvh.c#n196). Also note that if you use std::min and std::max, it's far from branchless)

However, this raises a significant problem.

What if the ray's origin in one or more dimensions is equal to the min or max points?

What I found is that I get this situation on an example ray and box:

* Ray origin: (3.225, 0.243, 2.221)
* Ray direction: (0, 0, -1)
* Box min: (3.223, 0.241, 2.119)
* Box max: (3.225, 0.243, 2.121)

Is that when tx1 is calculated, it correctly gets -inf. However, when tx2 is calculated, it gets `(3.225 - 3.225) * inf` which is coming out to `-nan`. This means that later, when we do:

`float tmax = std::max(tx1, tx2);`

We get `max(-inf, -nan)` which comes out to `-inf` and from that point on in the tests, tmax will always be -inf, making the overall ray-box test fail.

This is confirmed by some comments on the page where I got the code:

> Something to consider here is that 0 \* inf =nan which occurs when the ray starts exactly on the edge of a box

And

> Having read both this and part 2, I'm unable to work out what changes I need to make in order to reliably detect intersections when a ray is exactly on the edge of an AABB.

Does anyone know a fast method for ray-box intersection with edge and corner hits?

I should note **this is not being used with a BVH**. I need an **exact** intersection test, I cannot increase the size of the box at all.

**Tags:** raytracing

> **Comments:**
> **username_1**: I think the pragmatic fix for BVH use would be to inflate the boxes by 1 ulps. I suspect that would beat any fix I can think of as all of them involve several extra instructions. I will keep thinking about it though, it is an interesting problem.  
> **username_0**: Making the boxes physically larger in my case would make the results totally worthless. I can check if the result is NAN but that doesn't guarantee a hit, only that the origin started on one of those dimensions.Also, making them larger would just mean it would be the same problem, just at a different point in space, no? Or do you mean, if I detect a nan, extend the box and then try again?  
> **username_1**: @username_0 I meant always make them larger. This will give a tiny % of false positives, which for a BVH is of no importance. If you require an exact intersection test, you might want to edit your question to specify that and also if you care about fixing the problem on both the min/max side of each axis or only on one side.  
> **username_0**: @Oliver I am not using this for a BVH.  
> **username_2**: This post may help you: https://tavianator.com/fast-branchless-raybounding-box-intersections-part-2-nans/. It presents this specific issue and a workaround for it.  
> **username_0**: @username_2 Sadly, that post details a solution where plane-hits like I describe are *ignored*, rather than treated as hits. I actually need them in my case. They specify this, with: *"Since this is an edge case, you might wonder why we don't choose to return true instead of false for rays on the boundary. **It turns out to be much harder to get this behavior with efficient code.**"*  
> **username_3**: @username_0 I did say that, but it's actually not that hard at all: https://tavianator.com/2022/ray_box_boundary.html#boundaries  

---

## 2 answers

### Answer by username_0 on 2020-02-03. Score: 2 | Accepted answer

Here is how I found this can be solved.

(The below also happens at the start, just fyi)

```
  float tmin = std::numeric_limits<float>::lowest();
  float tmax = std::numeric_limits<float>::max();

```

Add an additional check:

```
if(rayDir.x == 0.0f)
{
  if (rayOrigin.x() < box.min.x() || rayOrigin.x() > box.max.x())
  {     
    return false;
  }
}
else 
{
  tx1 = (box.min.x - rayOrigin.x) * invRay.x;
  tx2 = (box.max.x - rayOrigin.x) * invRay.x;

  tmin = std::max(tmin, std::min(tx1, tx2));
  tmax = std::min(tmax, std::max(tx1, tx2));
}

```

This way the tx1/tx2 values never get calculated if the ray's direction vector is zero in that direction, aka if it's parallel to that plane.

It's not particularly compact or pretty, but it does neatly solve the issue.

> **Comments:**
> **username_0**: @DanielMGessel Could you clarify what you mean by that?  
> **username_0**: @DanielMGessel How is checking what type of ray, then choosing a function, rather than the function determining it any faster? Either way, the exact same checks need to happen on the ray. It doesn't seem like less work is being done.  
> **username_0**: @DanielMGessel No, this is not part of a traversal for a BVH. Thank you in any case.  

---

### Answer by username_4 on 2020-02-24. Score: 0

This is a C++ implementation. Slab is the space between a pair of parallel planes.Test if ray R(t) = p + t \* d intersect against bounding box bb.

```
bool IntersectRayBB( const double* p, const double* d, const BoundingBox& bb, double& tmin, double* q )
{
    double tolerance = 1e-9;
    tmin = 0.0;
    double tmax = FLOAT32_MAX; // Set to max distance ray can travel
    for( int i = 0; i < 3; i++ )
    {
        if( Abs( d[i] ) < tolerance )
        {
            // Ray is parallel to slab. No hit if origin not within slab.
            if( p[i] < bb.min[i] || p[i] > bb.max[i] )
                return false;
        }
        else
        {
            // Compute intersection t value of ray within near and far plane of slab
            double denom = 1.0 / d[i];
            double t1 = ( bb.min[i] - p[i] ) * denom;
            double t2 = ( bb.max[i] - p[i] ) * denom;
            // Make t1 be intersection with near plane, t2 with far plane
            if( t1 > t2 )
                std::Swap( t1, t2 );
            // Compute the intersection of slab intersection intervals
            if( t1 > tmin )
                tmin = t1;
            if( t2 > tmax )
                tmax = t2;
            // Exit with no collision as soon as slab intersection becomes empty
            if( tmin > tmax )
                return false;
        }
    }

    //Ray intersects all 3 slabs. Return point (q) and intersesction t value (tmin)
    q = p + d * tmin;
    return true;
}

```


---

