Hello! Welcome to the next stage of building our ray tracer.
In the last lesson, you successfully implemented an OBJ loader, giving you the power to bring complex models into your scenes. If you tried rendering a model with even a few thousand triangles, you likely noticed a dramatic slowdown. A scene that was rendering in seconds might now take minutes. This isn't a bug in your code; it's a fundamental limitation of our current approach.
This lesson directly addresses that performance bottleneck and covers the learning outcome: Explain why acceleration structures are essential for rendering complex scenes. This is a conceptual lesson, focused on the "why" before we dive into the "how." Understanding this is crucial, as it forms the basis of performance in all modern renderers, including the Arnold and Karma renderers you're familiar with from your work in VFX.
By the end of this lesson, you'll understand the mathematical and practical reasons why a naive ray tracer is too slow for real work and how acceleration structures provide a solution that is not just an optimization, but a necessity.
1. The Performance Cliff: Quantifying the Problem
Our current ray tracing algorithm is simple and brute-force. For every pixel on our screen, we cast a ray and then loop through every single object (or triangle) in the scene to find the closest intersection.
Let's think about the computational cost:
- If we have
Ppixels in our image... - And
Ttriangles in our scene... - The total number of ray-triangle intersection tests is
P * T.
This is known as having a time complexity of O(P * T). The cost grows linearly with both the number of pixels and the number of triangles.
In the previous lesson, you might have loaded a model with, say, 10,000 triangles. Rendering it at a modest 800x600 resolution (480,000 pixels) requires:
480,000 * 10,000 = 4,800,000,000 (4.8 billion) intersection tests.
And that's for a single ray per pixel! If we add anti-aliasing with 100 samples per pixel, that number becomes 480 billion. The problem gets out of hand very quickly.
To see a fantastic visual and practical demonstration of this, let's watch a segment from a video by Sebastian Lague. He visualizes the number of intersection tests per pixel as a color, making the performance cost immediately obvious.
Coding Adventure: More Ray Tracing!
In 'Coding Adventure: More Ray Tracing!', Sebastian Lague brilliantly illustrates the inefficiency of the brute-force approach.
Watch from 00:23 to 03:44. Notice how quickly the number of tests (and the corresponding render time) explodes as he moves from a simple scene to a more complex dragon model, even one that has been heavily decimated.
This problem is precisely why rendering a complex shot in a VFX production can take hours, even on powerful hardware. The scenes you work with contain not thousands, but often millions or billions of effective triangles. The brute-force method is simply not an option.
2. The Core Idea: Don't Test What You Don't Have To
The key insight to solving this problem is that most of those billions of tests are useless. A ray traveling toward the top-right of the scene has no chance of hitting a triangle at the bottom-left. Yet, our current code tests it anyway.
The solution is to find a way to quickly discard large groups of objects.
Imagine looking for a name in a massive, unsorted list of people. You'd have to read every single name. Now, imagine the same list of names sorted alphabetically in a phone book. You can instantly jump to the right section, ignoring almost the entire book.
Acceleration structures apply this same principle to 3D space.
Acceleration Datastructures for Raytracing
The article 'Acceleration Datastructures for Raytracing' on geometrian.com provides a concise introduction to this core problem and its solution.
Please read the introduction, starting from the quote and ending just before the 'Practical Advice' section. It introduces the core idea: if a ray misses a broad region, we can skip testing all the primitives within it.
By intelligently partitioning the scene, we can change the search for an intersection from a linear scan, O(T), to a logarithmic one, O(log T). This means that for P pixels, the total complexity becomes O(P * log T).
What does this mean in practice?
- For 10,000 triangles:
log₂(10,000)is about 13. We've reduced the number of tests for each ray from 10,000 to roughly 13. - For 1,000,000 triangles:
log₂(1,000,000)is about 20. Doubling the number of intersection tests from 13 to 20 allows us to handle 100 times more geometry!
This logarithmic scaling is what makes rendering complex scenes feasible.
3. A Glimpse of the Solution: Bounding Volumes and Hierarchies
How do we "partition the scene"? The most common method, and the one we will implement, is a Bounding Volume Hierarchy (BVH).
The strategy involves two main concepts:
-
Bounding Volume: We enclose a complex object (or a group of objects) within a much simpler shape, like a box or a sphere. Testing for a ray intersection with a box is extremely fast compared to testing it against hundreds of triangles. If the ray misses the box, we know it can't possibly hit anything inside, so we can skip all those expensive triangle tests.
-
Hierarchy: We don't just put one big box around the whole scene. We organize the boxes into a tree structure. A large box contains two smaller boxes, each of which contains two even smaller boxes, and so on, until the smallest boxes (the "leaf nodes") contain just a few triangles.

When we trace a ray, we don't test the triangles first. We test against these bounding boxes, starting from the biggest one (the "root").
- Does the ray hit the root box?
- If yes, we then test its child boxes.
- Does it hit the left child box? If yes, traverse down that branch.
- Does it hit the right child box? If no, we can completely ignore that box and everything inside it.
We continue this process, rapidly eliminating huge chunks of the scene, until we reach a leaf box. Only then do we perform the expensive intersection tests on the few triangles inside that leaf.
Let's watch a brief explanation that introduces these concepts.
Rendering Lecture 1 - Spatial Acceleration Structures
The 'Rendering Lecture 1' from TU Wien gives a clear, academic explanation of why the naive approach fails and how acceleration structures, specifically BVHs, are the solution.
First, watch from 06:24 to 08:20 to hear a formal analysis of the O(N*M) runtime problem. Then, skip ahead and watch from 23:57 to 26:01 to get a high-level overview of how a Bounding Volume Hierarchy is structured as a tree to solve this problem.
Test your understanding!
Imagine a scene with 1024 triangles. Without a BVH, a single ray must be tested against all 1024 triangles.
Now, imagine we build a perfect binary BVH, where each node splits the triangles into two equal halves. How many bounding box tests would a ray need to perform (approximately) to reach a leaf node containing a single triangle?
Show answer
A perfect binary tree with N leaves has a depth of log₂(N).
In this case, log₂(1024) is exactly 10.
The ray would need to perform about 10-11 bounding box intersection tests to traverse from the root to a leaf node. It would then perform one final triangle intersection test. This is a dramatic improvement over 1024 triangle tests.
4. The Real-World Impact
The difference in performance is not subtle; it's astonishing. It is the single most important factor for achieving reasonable render times in complex scenes.
To put a number on it, let's look at a case study from another developer who implemented a BVH.
Advanced Ray Tracer: Part 2. Acceleration Structure ...
This article from a fellow ray tracer developer provides a stunning before-and-after comparison.
Scroll down to the 'Linearization' subsection. You don't need to understand what 'linearization' means yet. Just focus on the render times reported for the Dragon scene with and without the BVH.
As you saw, a scene that took 113.63 minutes to render with the brute-force method was rendered in just 3.46 seconds with a BVH. This is a speedup of over 2000x. This is why acceleration structures are considered essential.
Conclusion
In this lesson, we took a step back from coding to understand a critical performance bottleneck. By loading complex models, we pushed our simple ray tracer to its limits and saw that the brute-force approach simply doesn't scale.
Key Takeaways:
- The Problem: Naive ray tracing has a computational cost of
O(P * T)(pixels * triangles), which is computationally infeasible for complex scenes or high resolutions. - The Principle: The solution is to avoid unnecessary work. By grouping objects, we can quickly dismiss large parts of the scene that a ray will not intersect.
- The Method: A Bounding Volume Hierarchy (BVH) is a tree of simple bounding boxes that encloses the scene's geometry. Traversing this tree is extremely fast.
- The Impact: Using an acceleration structure like a BVH changes the complexity to
O(P * log T), resulting in performance improvements of several orders of magnitude and making complex scenes renderable in seconds or minutes instead of hours or days.
Next Steps
Now that you understand why acceleration structures are so critical, we can begin to build one. In the next lesson, we will implement the fundamental building block of our BVH: an Axis-Aligned Bounding Box (AABB) primitive and a function for fast ray-AABB intersection testing.