-
Concept: Ray-Triangle Intersection
-
Möller–Trumbore Algorithm
- The standard algorithm — used in virtually all ray tracers
- Fast, numerically stable, returns barycentric coordinates
- Paper: “Fast, Minimum Storage Ray/Triangle Intersection” (1997)
-
Derivation
- A point on a triangle:
P = (1-u-v)*v0 + u*v1 + v*v2
u, v ≥ 0 and u + v ≤ 1 for points inside the triangle
u, v are barycentric coordinates
- Ray equation:
P = origin + t * direction
- Set equal:
origin + t*dir = (1-u-v)*v0 + u*v1 + v*v2
- Rearrange:
[-dir, v1-v0, v2-v0] * [t, u, v]^T = origin - v0
- Solve with Cramer’s rule
-
Back-Face Culling
det < 0 means ray hits the back face of the triangle
- For opaque geometry:
if (det < 1e-8) return false; (cull back faces)
- For double-sided materials: use
abs(det)
- In Vulkan:
VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR disables culling
-
Barycentric Coordinates
(1-u-v, u, v) — weights for vertices v0, v1, v2
- Interpolate any vertex attribute:
attr = (1-u-v)*a0 + u*a1 + v*a2
- Normal interpolation:
N = normalize((1-u-v)*n0 + u*n1 + v*n2)
- UV interpolation:
uv = (1-u-v)*uv0 + u*uv1 + v*uv2
- In Vulkan closest-hit shader:
hitAttributeEXT vec2 baryCoords;
baryCoords.x = u, baryCoords.y = v
w = 1 - u - v
-
Watertight Intersection
- Standard Möller–Trumbore can miss edges/vertices due to floating point
- Watertight algorithm (Woop et al. 2013) — no gaps at shared edges
- Important for production renderers — prevents light leaking through cracks
- Technique: transform ray to a coordinate system where it points along +Z