Missing triangle in BVH

Missing triangle in BVH

May 22, 2023

Recently I was applying Bounding Volume Hierachy to a Whitted-style Raytracing system. The idea of BVH and implementation are well described in Ray Tracing in the Next Week by Peter Shirly. It’s a really great book. And here’s the link https://raytracing.github.io/books/RayTracingTheNextWeek.html

One key component in BVH is AABB (Axis-Aligned-Bounding-Box) intersects with ray. People usually adopt Slab method to address this problem. To be more specific, computing the ray-AABB intersection along 3 different axis, if these intervals produces an overlapping region, then the ray intersects with AABB and vice versa.

1
2
3
4
compute (tx0, tx1)
compute (ty0, ty1)
compute (tz0, tz1)
return overlap?( (tx0, tx1), (ty0, ty1), (tz0, tz1))
image-20230522223149832

After applying this method to the scene rendering, I lost some of the triangles in the scene. However, all spheres are kept intact. For example, here’s what I got after applying BVH and the latter is before BVH.

image-20230522224231933 image-20230522224256173

After couple hours of step_into debugging, I found the reason to be as follows:

For spheres, the Bouding box will always have some length along 3 axis. However, this isn’t necessarily the case for AABB of triangles. ==Bounding Box of triangles can fall back to plane if the triangle is parallel to either xy, yz or xz plane== .

Let’s say a triangle is parallel to the xz plane, so the 3 vertices has the same y value. And this makes ty0 and ty1 to be the same in above computation, and thus resulting no overlapping region for other 2 axis. i.e. The bounding box doesn’t intersect with the triangle (which is a false statement)

To address this, simply add some thickness to each axis while building bounding box for triangles. In my case, I use 1e-3, and boom, problem solved!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//in triangle class  
AABB getAABB(float t0, float t1) override {
auto min_x = std::min(
{this->v0.position.x(), this->v1.position.x(), this->v2.position.x()});
auto min_y = std::min(
{this->v0.position.y(), this->v1.position.y(), this->v2.position.y()});
auto min_z = std::min(
{this->v0.position.z(), this->v1.position.z(), this->v2.position.z()});
auto max_x = std::max(
{this->v0.position.x(), this->v1.position.x(), this->v2.position.x()});
auto max_y = std::max(
{this->v0.position.y(), this->v1.position.y(), this->v2.position.y()});
auto max_z = std::max(
{this->v0.position.z(), this->v1.position.z(), this->v2.position.z()});
return AABB(gl::vec3(min_x-1e3, min_y-1e3, min_z-1e3), gl::vec3(max_x, max_y, max_z));
}