Capsule Signed Distance Function Formula in GLSL
This article provides the mathematical foundation and optimized GLSL implementation of a capsule Signed Distance Function (SDF). You will learn how vector projection is used to determine the distance from an arbitrary point in 3D space to a line segment with uniform thickness, making it ideal for raymarching and procedural geometry generation.
Mathematical Concept
A 3D capsule is defined by two endpoints, point \(A\) and point \(B\), along with a radius \(r\). Geometrically, a capsule is a line segment inflated into 3D space by sweeping a sphere of radius \(r\) along the segment.
To compute the signed distance from an arbitrary query point \(P\) to the capsule:
- Find the vector representing the segment: \(v = B - A\).
- Find the vector from endpoint \(A\) to the sample point: \(u = P - A\).
- Project \(u\) onto \(v\) using the dot product to find the normalized scalar projection \(t\): \[t = \frac{u \cdot v}{v \cdot v}\]
- Clamp \(t\) between
0.0and1.0to constrain the closest point strictly within the bounds of segment \(AB\): \[h = \text{clamp}(t, 0.0, 1.0)\] - The closest point on the segment to \(P\) is \(A + h \cdot v\). The vector from this closest point to \(P\) simplifies algebraically to \(u - h \cdot v\).
- Calculate the Euclidean length of this difference vector and subtract the radius \(r\): \[\text{distance} = \|u - h \cdot v\| - r\]
GLSL Implementation: Arbitrary Capsule
The following GLSL function implements the arbitrary orientation formula using standard vector operations:
float sdCapsule(vec3 p, vec3 a, vec3 b, float r) {
vec3 pa = p - a;
vec3 ba = b - a;
float h = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0);
return length(pa - ba * h) - r;
}p: The current sampling point in 3D space.a: The starting coordinate of the capsule's internal segment.b: The ending coordinate of the capsule's internal segment.r: The radius of the capsule.
GLSL Implementation: Vertical Axis-Aligned Capsule
When the capsule is aligned along the Y-axis starting at the origin
and extending upward to height h, the general formula can
be simplified to avoid vector subtractions and dot products:
float sdVerticalCapsule(vec3 p, float h, float r) {
p.y -= clamp(p.y, 0.0, h);
return length(p) - r;
}This simplified form clamps only the Y-component of the position vector, reducing the computational overhead while producing identical visual results for axis-aligned shapes.