Smooth Subtraction and Intersection of SDFs in GLSL
This article provides the mathematical formulations and ready-to-use
GLSL implementations for smooth subtraction and smooth intersection of
Signed Distance Functions (SDFs). Standard Constructive Solid Geometry
(CSG) operations produce sharp transitions between intersecting
geometries; smooth variants replace the standard non-differentiable
min and max functions with continuous
polynomial blending functions, enabling organic, seamless transitions
controlled by a smoothing radius parameter.
The Foundation: Smooth Minimum and Maximum
Standard CSG operations rely on min(a, b) for union and
max(a, b) for intersection and subtraction. Smooth boolean
operations substitute these with smooth minimum (smin) and
smooth maximum (smax).
The standard polynomial smooth minimum (quadratic) formulated by Inigo Quilez is defined as:
float smin(float a, float b, float k) {
float h = clamp(0.5 + 0.5 * (b - a) / k, 0.0, 1.0);
return mix(b, a, h) - k * h * (1.0 - h);
}Because maximum operations can be expressed through minimum operations via the identity \(\max(a, b) = -\min(-a, -b)\), the smooth maximum is defined mathematically as:
\[\text{smax}(a, b, k) = -\text{smin}(-a, -b, k)\]
In GLSL, smax can be implemented directly to avoid
excessive negation:
float smax(float a, float b, float k) {
float h = clamp(0.5 + 0.5 * (b - a) / k, 0.0, 1.0);
return mix(a, b, h) + k * h * (1.0 - h);
}Smooth Intersection
Mathematical Formulation
The standard intersection between two distance fields \(d_1\) and \(d_2\) is the point-wise maximum:
\[\text{Intersection}(d_1, d_2) = \max(d_1, d_2)\]
The smooth intersection replaces the standard maximum with the smooth maximum parameterized by a blend factor \(k > 0\):
\[\text{SmoothIntersection}(d_1, d_2, k) = \text{smax}(d_1, d_2, k) = -\text{smin}(-d_1, -d_2, k)\]
GLSL Implementation
Using the direct polynomial expansion:
float opSmoothIntersection(float d1, float d2, float k) {
float h = clamp(0.5 - 0.5 * (d2 - d1) / k, 0.0, 1.0);
return mix(d2, d1, h) + k * h * (1.0 - h);
}Alternatively, utilizing an existing smin function:
float opSmoothIntersection(float d1, float d2, float k) {
return -smin(-d1, -d2, k);
}Smooth Subtraction (Difference)
Mathematical Formulation
Standard subtraction of shape \(d_1\) from shape \(d_2\) is defined by intersecting the inversion of \(d_1\) with \(d_2\):
\[\text{Subtraction}(d_1, d_2) = \max(-d_1, d_2)\]
Applying smooth maximum yields:
\[\text{SmoothSubtraction}(d_1, d_2, k) = \text{smax}(-d_1, d_2, k)\]
Substituting into the equivalence \(\text{smax}(a, b, k) = -\text{smin}(-a, -b, k)\):
\[\text{SmoothSubtraction}(d_1, d_2, k) = -\text{smin}(d_1, -d_2, k)\]
GLSL Implementation
Using direct formulation where shape d1 is carved out of
shape d2:
float opSmoothSubtraction(float d1, float d2, float k) {
float h = clamp(0.5 - 0.5 * (d2 + d1) / k, 0.0, 1.0);
return mix(d2, -d1, h) + k * h * (1.0 - h);
}Alternatively, calling smin directly:
float opSmoothSubtraction(float d1, float d2, float k) {
return -smin(d1, -d2, k);
}Behavior of the Smoothing Factor \(k\)
- When \(k \to 0\), both operations
strictly converge to their standard counterparts:
max(d1, d2)andmax(-d1, d2). - When \(|d_1 - d_2| \ge k\) (for
intersection) or \(|(-d_1) - d_2| \ge
k\) (for subtraction), the polynomial factor \(h\) clamps to
0.0or1.0, ensuring the operations remain strictly local without affecting distant geometry.