-
Concept: BVH Construction
-
What is a BVH?
- Bounding Volume Hierarchy — a tree of bounding volumes
- Each node contains an AABB that bounds all geometry in its subtree
- Leaf nodes contain actual primitives (triangles)
- Internal nodes have exactly 2 children (binary tree)
- Purpose: reduce ray-scene intersection from O(N) to O(log N)
-
Naive Construction (Midpoint Split)
- Algorithm
-
- Compute AABB of all primitives in current node
-
- Find the longest axis (x, y, or z)
-
- Sort primitives by centroid along that axis
-
- Split at midpoint
-
- Recurse on left and right halves
-
- Stop when ≤ N_leaf primitives (e.g., N_leaf = 4)
- Simple but suboptimal — can create unbalanced trees
- Degenerate case: all centroids on a plane → one child has all primitives
-
SAH (Surface Area Heuristic)
- The standard for high-quality BVH construction
- Cost model
C(node) = C_traversal + (SA_left/SA_parent) * N_left * C_intersect + (SA_right/SA_parent) * N_right * C_intersect
C_traversal — cost of testing a node’s AABB (~1)
C_intersect — cost of testing a primitive (~2-4 for triangles)
SA_left/SA_parent — probability that a random ray hits the left child given it hits the parent
- Algorithm
- For each axis (x, y, z):
- Sort primitives by centroid
- Try all N-1 split positions
- Compute SAH cost for each split
- Choose the axis and split position with minimum cost
- If best split cost > cost of making a leaf: make a leaf
- Binned SAH (faster approximation)
- Instead of trying all N-1 splits, divide axis into K bins (e.g., K=32)
- Assign each primitive to a bin based on centroid
- Try K-1 split positions between bins
- O(N) per level instead of O(N log N)
- Quality is nearly identical to full SAH for K ≥ 16
-
BVH Build Strategies
- Top-down (most common)
- Start with all primitives, recursively split
- Good quality, O(N log N) with SAH
- Bottom-up (LBVH, HLBVH)
- Sort primitives by Morton code (space-filling curve)
- Build tree bottom-up from sorted order
- Very fast (GPU-friendly), slightly lower quality
- Used for real-time BLAS builds in Vulkan
- Morton code: interleave bits of (x, y, z) coordinates
- Locally Ordered Clustering (PLOC)
- Better quality than LBVH, still GPU-friendly
- Used in some production renderers
-
BVH Refitting
- For animated scenes: update AABBs without rebuilding the tree structure
- Bottom-up: update leaf AABBs from new vertex positions, propagate up
- Fast but BVH quality degrades as objects move far from original positions
- Use for small deformations (cloth, skinned meshes with small motion)
- Full rebuild needed for large topology changes
-
BVH Quality Metrics
- SAH cost — lower is better
- Average traversal steps per ray — measure empirically
- Tree depth — affects stack size for traversal
- Leaf size — 1-8 primitives per leaf is typical
-
Implementation Notes
- Store BVH as flat array (not pointer-based tree)
- Better cache performance
node[i].left_child = 2*i+1, node[i].right_child = 2*i+2 (for complete binary tree)
- Or store explicit child indices
- Compact node layout
- Primitive reordering
- After BVH build: reorder primitives to match BVH leaf order
- Improves cache coherence during traversal
- Triangles accessed together are stored together in memory
-
Wide BVH (BVH4, BVH8)
- Instead of binary tree: 4 or 8 children per node
- Better SIMD utilization — test 4/8 AABBs simultaneously
- Used in Embree (Intel’s CPU ray tracing library)
- Slightly more complex traversal but significantly faster on modern CPUs