<p>It does indeed do exactly what you described. Have a close look at how the bvh is constructed, it is a passed a list of concrete shapes that implement <code>hittable</code>, e.g. <code>xy_rect</code>, <code>sphere</code>, etc. The base cases for the recursive bvh construction create leaf nodes that directly reference the concrete shapes that make up the scene.</p>
<pre><code>bvh_node::bvh_node(
    const std::vector&lt;shared_ptr&lt;hittable&gt;&gt;&amp; src_objects,
    size_t start, size_t end, double time0, double time1
) {
    auto objects = src_objects; // Create a modifiable array of the source scene objects
    ...
    size_t object_span = end - start;

    // **create leaf nodes, concrete shapes referenced here**
    if (object_span == 1) {
        left = right = objects[start]; 
    } else if (object_span == 2) {
        if (comparator(objects[start], objects[start+1])) {
            left = objects[start];
            right = objects[start+1];
        } else {
            left = objects[start+1];
            right = objects[start];
        }
    } else {
       // create internal bvh_node
       ...
}
</code></pre>
<p>When <code>bvh_node::hit</code> is called and the ray/aabb test passes, the left and right child nodes have their hit functions called recursively. Eventually when this recursion bottoms out the concrete shapes referenced by the leaf nodes will have their hit functions called as you would expect.</p>
<pre><code>bool bvh_node::hit(const ray&amp; r, double t_min, double t_max, hit_record&amp; rec) const {
    if (!box.hit(r, t_min, t_max))
        return false;

    bool hit_left = left-&gt;hit(r, t_min, t_max, rec);
    bool hit_right = right-&gt;hit(r, t_min, hit_left ? rec.t : t_max, rec);

    return hit_left || hit_right;
}
</code></pre>

CC BY-SA 4.0
2020-11-16T07:21:39.847Z
2020-11-16T07:21:39.847Z
xasp
<p>I agree with <a href="https://computergraphics.stackexchange.com/a/10405/10615">@xasp's answer</a>, but to understand <em>why</em> you would do it like that:</p>
<p>Checking for ray-circle intersections is not the most expensive in terms of cpu-time required, but a ray-aabb intersection is frighteningly faster. Apparently Shirley found that in his scenes, checking the leaf's AABB first led to better results, because in a &quot;sparse bounding volume tree&quot;, you might recurse down to a leaf node, but still not hit it.</p>
<p>So why is the AABB faster than a sphere intersection? Well for spheres in 3d you need to square 3 numbers (will be compiled to a single vector instruction most likely) and you need to then take the square root, which is a traditionally expensive operation. See this answer: <a href="https://stackoverflow.com/a/12304868/11359454">https://stackoverflow.com/a/12304868/11359454</a></p>
<p>In AABB intersection you just need to do some larger/smaller than checks and divide your rays x y and z components to get the inverse (single vector divide instruction).</p>
<p>Infamously in quake, to get faster lighting, an approximation hack was used to get a fast root-ish. Nowadays that hack is actually slower than a call to <code>sqrtf</code>, because the floating point parts of processors have gotten faster and more advanced.</p>

CC BY-SA 4.0
2020-11-16T13:26:51.703Z
*"and you need to then take the square root,"*
Why do you need to take the sqrt? If you are comparing the perpendicular distance from centre to ray against the radius, surely one just compares against the square of both values?
Simon F
CC BY-SA 4.0
2020-11-16T20:02:00.837Z
@SimonF because of the math to work out an *intersection* between a line and a sphere, you need to solve a quadratic equation which involves a root. We're not just checking distance, we're generating intersection points. There is also another method but even that requires taking a root. I recommend reading this: https://www.scratchapixel.com/lessons/3d-basic-rendering/minimal-ray-tracer-rendering-simple-shapes/ray-sphere-intersection

You'll see there's even more math than I mentioned. Here is the math for a ray-AABB intersection: https://tavianator.com/2011/ray_box.html
AnnoyinC
CC BY-SA 4.0
2020-11-19T09:48:24.563Z
Perhaps I wasn't clear enough. Most of the scene testing is *rejecting* potential hits against geometry. You don't need the sqrt for that part. The OP was asking why use the AABB of the sphere for a reject test, rather than the sphere itself, and the reject test for a sphere, to my knowledge, doesn't need a sqrt.  (For example, see "An Introduction to Ray Tracing, 1989, Ed: Andrew Glassner).
Simon F
CC BY-SA 4.0
2020-11-16T08:53:49.303Z
2020-11-16T08:53:49.303Z
AnnoyinC
<p>While studying <a href="https://github.com/RayTracing/raytracing.github.io" rel="nofollow noreferrer">Peter Shirley's Ray Tracing:The Next Week</a>, I came across an issue that I cannot quite figure out:</p>
<p>Stepping through the <code>random_scene()</code> case of the code, found out that once a leaf of the BVH tree is reached, the aabb of the object is checked for a hit; even when the object is a sphere.</p>
<p>The check for a hit against the <code>bounding_box</code> of a sphere (aabb) is necessary but not sufficient; there are parts of the <code>bounding_box</code> which is not a part of a sphere.</p>
<p>Shouldn't it invoke the specific <code>hit()</code> function of the object when the leaf is reached?</p>
<p>Yet the code works somehow.</p>

<raytracing><debugging><bounding-volume-hierarchy>
BVH uses aabb for a sphere in Ray Tracing: The Next Week
Vectorizer
# BVH uses aabb for a sphere in Ray Tracing: The Next Week

(Asked by: username_0 on 2020-11-14)

While studying [Peter Shirley's Ray Tracing:The Next Week](https://github.com/RayTracing/raytracing.github.io), I came across an issue that I cannot quite figure out:

Stepping through the `random_scene()` case of the code, found out that once a leaf of the BVH tree is reached, the aabb of the object is checked for a hit; even when the object is a sphere.

The check for a hit against the `bounding_box` of a sphere (aabb) is necessary but not sufficient; there are parts of the `bounding_box` which is not a part of a sphere.

Shouldn't it invoke the specific `hit()` function of the object when the leaf is reached?

Yet the code works somehow.

**Tags:** raytracing, debugging, bounding-volume-hierarchy


---

## 2 answers

### Answer by username_1 on 2020-11-16. Score: 1 | Accepted answer

It does indeed do exactly what you described. Have a close look at how the bvh is constructed, it is a passed a list of concrete shapes that implement `hittable`, e.g. `xy_rect`, `sphere`, etc. The base cases for the recursive bvh construction create leaf nodes that directly reference the concrete shapes that make up the scene.

```
bvh_node::bvh_node(
    const std::vector<shared_ptr<hittable>>& src_objects,
    size_t start, size_t end, double time0, double time1
) {
    auto objects = src_objects; // Create a modifiable array of the source scene objects
    ...
    size_t object_span = end - start;

    // **create leaf nodes, concrete shapes referenced here**
    if (object_span == 1) {
        left = right = objects[start]; 
    } else if (object_span == 2) {
        if (comparator(objects[start], objects[start+1])) {
            left = objects[start];
            right = objects[start+1];
        } else {
            left = objects[start+1];
            right = objects[start];
        }
    } else {
       // create internal bvh_node
       ...
}

```

When `bvh_node::hit` is called and the ray/aabb test passes, the left and right child nodes have their hit functions called recursively. Eventually when this recursion bottoms out the concrete shapes referenced by the leaf nodes will have their hit functions called as you would expect.

```
bool bvh_node::hit(const ray& r, double t_min, double t_max, hit_record& rec) const {
    if (!box.hit(r, t_min, t_max))
        return false;

    bool hit_left = left->hit(r, t_min, t_max, rec);
    bool hit_right = right->hit(r, t_min, hit_left ? rec.t : t_max, rec);

    return hit_left || hit_right;
}

```


---

### Answer by username_2 on 2020-11-16. Score: 1

I agree with [@username_1's answer](https://computergraphics.stackexchange.com/a/10405/10615), but to understand *why* you would do it like that:

Checking for ray-circle intersections is not the most expensive in terms of cpu-time required, but a ray-aabb intersection is frighteningly faster. Apparently Shirley found that in his scenes, checking the leaf's AABB first led to better results, because in a "sparse bounding volume tree", you might recurse down to a leaf node, but still not hit it.

So why is the AABB faster than a sphere intersection? Well for spheres in 3d you need to square 3 numbers (will be compiled to a single vector instruction most likely) and you need to then take the square root, which is a traditionally expensive operation. See this answer: <https://stackoverflow.com/a/12304868/11359454>

In AABB intersection you just need to do some larger/smaller than checks and divide your rays x y and z components to get the inverse (single vector divide instruction).

Infamously in quake, to get faster lighting, an approximation hack was used to get a fast root-ish. Nowadays that hack is actually slower than a call to `sqrtf`, because the floating point parts of processors have gotten faster and more advanced.

> **Comments:**
> **username_3**: *"and you need to then take the square root,"* Why do you need to take the sqrt? If you are comparing the perpendicular distance from centre to ray against the radius, surely one just compares against the square of both values?  
> **username_2**: @username_3 because of the math to work out an *intersection* between a line and a sphere, you need to solve a quadratic equation which involves a root. We're not just checking distance, we're generating intersection points. There is also another method but even that requires taking a root. I recommend reading this: https://www.scratchapixel.com/lessons/3d-basic-rendering/minimal-ray-tracer-rendering-simple-shapes/ray-sphere-intersection  You'll see there's even more math than I mentioned. Here is the math for a ray-AABB intersection: https://tavianator.com/2011/ray_box.html  
> **username_3**: Perhaps I wasn't clear enough. Most of the scene testing is *rejecting* potential hits against geometry. You don't need the sqrt for that part. The OP was asking why use the AABB of the sphere for a reject test, rather than the sphere itself, and the reject test for a sphere, to my knowledge, doesn't need a sqrt.  (For example, see "An Introduction to Ray Tracing, 1989, Ed: Andrew Glassner).  

---

