Ray-OBB Intersection Using the Slab Method in GLSL
This article demonstrates how to implement ray intersections against an Oriented Bounding Box (OBB) in GLSL using the slab method. By transforming the incoming ray into the box's local coordinate space, the problem simplifies into a standard Axis-Aligned Bounding Box (AABB) slab test, allowing efficient computation directly within vertex, fragment, or compute shaders.
Concept Overview
An OBB is defined by a center position, half-extents (size along each local axis), and an orientation represented by an orthonormal \(3 \times 3\) rotation matrix (or three local basis axes).
The slab method tests a ray against three pairs of parallel planes
defined by the bounding box faces. Because checking an arbitrary
orientation in world space requires projecting the ray along each axis,
the most efficient approach in GLSL is to transform the ray's origin and
direction into the OBB's local coordinate space. In local space, the box
is an AABB centered at the origin with bounds from -extents
to +extents.
GLSL Implementation
Below is a complete, self-contained GLSL function to perform the intersection test.
struct Ray {
vec3 origin;
vec3 direction;
};
struct OBB {
vec3 center;
vec3 extents; // Half-widths along each local axis
mat3 orientation; // Columns are the orthonormal local axes (X, Y, Z)
};
// Returns true if the ray intersects the OBB.
// tNear and tFar output the entry and exit intersection distances.
bool intersectRayOBB(Ray ray, OBB obb, out float tNear, out float tFar) {
// 1. Transform ray to OBB local space
// Since orientation is orthonormal, transpose is equivalent to inverse.
mat3 invRotation = transpose(obb.orientation);
vec3 localOrigin = invRotation * (ray.origin - obb.center);
vec3 localDir = invRotation * ray.direction;
// 2. Compute intersection distances for all three slabs
vec3 invDir = 1.0 / localDir;
vec3 t0 = (-obb.extents - localOrigin) * invDir;
vec3 t1 = ( obb.extents - localOrigin) * invDir;
// Handle negative direction components
vec3 tMinVec = min(t0, t1);
vec3 tMaxVec = max(t0, t1);
// 3. Find largest entry t and smallest exit t
tNear = max(max(tMinVec.x, tMinVec.y), tMinVec.z);
tFar = min(min(tMaxVec.x, tMaxVec.y), tMaxVec.z);
// 4. Validate intersection
// The ray hits if entry occurs before exit and the box is not entirely behind the ray
return (tNear <= tFar) && (tFar >= 0.0);
}Step-by-Step Breakdown
1. Ray Transformation
The OBB's orientation matrix consists of three normalized, mutually
perpendicular vectors representing its local \(X\), \(Y\), and \(Z\) axes. Because this matrix is
orthogonal, its inverse equals its transpose
(transpose(obb.orientation)). Multiplying the centered ray
origin and direction by this transposed matrix rotates the ray into the
OBB's local coordinate system.
2. Computing Slab Intervals
Once in local space, the box boundaries are defined by \([-extents, +extents]\). For each axis:
- Calculate the distance from the origin to the near and far slab planes.
- Using
1.0 / localDirleverages vectorization and avoids multiple separate division operations. In GLSL, division by zero produces+infinityor-infinity, which works consistently withminandmaxunder IEEE 754 floating-point standards.
3. Interval Reduction
min(t0, t1) and max(t0, t1) ensure that
tMinVec contains the entry distances and
tMaxVec contains the exit distances regardless of ray
direction. The overall ray entry distance tNear is the
maximum of all three entry distances, while the exit distance
tFar is the minimum of all three exit distances.
4. Hit Evaluation
An intersection occurs if:
tNear <= tFar: The ray overlaps the intersection of all three slabs simultaneously.tFar >= 0.0: The intersection volume is in front of the ray's origin, not behind it. IftNear < 0.0, the ray origin is located inside the box.