Smith Geometry Function for Microfacet Shadowing in GLSL
The Smith geometry attenuation function models the physical occlusion of light by surface roughness within microfacet Bidirectional Reflectance Distribution Functions (BRDFs). In Physically Based Rendering (PBR), rough surfaces consist of microscopic valleys and peaks that obstruct light rays from reaching or escaping microfacets. This article explains the mechanics of microfacet shadowing and masking, details how the Smith formulation statistically resolves occlusion along both the incident and viewing vectors, and provides a production-ready implementation of the height-correlated Smith geometry function in GLSL.
The Physics of Masking and Shadowing
Microfacet theory models a macroscopic surface as a collection of microscopic, perfectly specular planar facets. When light interacts with a rough surface, two primary geometrical occlusions occur:
- Shadowing: Microfacets block incident light from reaching neighboring microfacets.
- Masking: Microfacets block reflected light from escaping along the view direction toward the camera.
Without accounting for these occlusions, a BRDF violates the conservation of energy by reflecting more light than physically possible, especially at grazing angles where the projected area of microfacets overlaps significantly. The geometry attenuation factor, denoted as \(G(\mathbf{l}, \mathbf{v}, \mathbf{h})\), calculates the proportion of active microfacets that are visible to both the light direction \(\mathbf{l}\) and the view direction \(\mathbf{v}\).
The Smith Formulation Approach
Evaluating the exact geometry of arbitrary microscopic roughness in real time is computationally impossible. In 1967, Bruce G. Smith proposed a statistical model assuming that surface heights and profile slopes are uncorrelated. Under this assumption, the total visibility factor splits into two independent one-directional shadowing functions (\(G_1\)):
\[G(\mathbf{l}, \mathbf{v}) = G_1(\mathbf{l}) \cdot G_1(\mathbf{v})\]
- \(G_1(\mathbf{l})\) represents the probability that a facet is illuminated without being shadowed.
- \(G_1(\mathbf{v})\) represents the probability that a facet is visible to the observer without being masked.
For the commonly used GGX (Trowbridge-Reitz) distribution, the standard one-directional Smith term is defined as:
\[G_1(\mathbf{n}, \mathbf{w}) = \frac{2(\mathbf{n} \cdot \mathbf{w})}{(\mathbf{n} \cdot \mathbf{w}) + \sqrt{\alpha^2 + (1 - \alpha^2)(\mathbf{n} \cdot \mathbf{w})^2}}\]
Where \(\mathbf{w}\) is either the view vector \(\mathbf{v}\) or light vector \(\mathbf{l}\), \(\mathbf{n}\) is the macroscopic surface normal, and \(\alpha\) is the surface roughness parameter (\(\alpha = \text{roughness}^2\)).
Height-Correlated Smith Model
Treating shadowing and masking as independent events overestimates occlusion at grazing angles, because microfacets elevated high enough to be seen by the viewer are also statistically more likely to be illuminated by the light.
To correct this, modern real-time rendering relies on Eric Heitz’s height-correlated Smith formulation. This model couples the shadowing and masking terms based on elevation, eliminating over-darkening and producing a more accurate physical response:
\[G(\mathbf{l}, \mathbf{v}) = \frac{2(\mathbf{n} \cdot \mathbf{l})(\mathbf{n} \cdot \mathbf{v})}{(\mathbf{n} \cdot \mathbf{v}) \sqrt{\alpha^2 + (1 - \alpha^2)(\mathbf{n} \cdot \mathbf{l})^2} + (\mathbf{n} \cdot \mathbf{l}) \sqrt{\alpha^2 + (1 - \alpha^2)(\mathbf{n} \cdot \mathbf{v})^2}}\]
In practice, the geometry factor \(G\) is combined with the Cook-Torrance denominator \(4(\mathbf{n} \cdot \mathbf{l})(\mathbf{n} \cdot \mathbf{v})\) into a single visibility function, \(V(\mathbf{l}, \mathbf{v})\), to save computational cycles:
\[V(\mathbf{l}, \mathbf{v}) = \frac{G(\mathbf{l}, \mathbf{v})}{4(\mathbf{n} \cdot \mathbf{l})(\mathbf{n} \cdot \mathbf{v})}\]
GLSL Implementation
The following GLSL function computes the height-correlated Smith visibility term for the GGX distribution. It eliminates the standard Cook-Torrance denominator by directly computing \(V(\mathbf{l}, \mathbf{v})\):
// Computes the height-correlated visibility term V = G / (4 * NdotL * NdotV)
// roughness: linear perceptual roughness [0.0, 1.0]
float Visibility_SmithGGXCorrelated(float NdotV, float NdotL, float roughness)
{
float a = roughness * roughness;
float a2 = a * a;
// Evaluate visibility components for light and view directions
float gv = NdotL * sqrt(NdotV * (NdotV - NdotV * a2) + a2);
float gl = NdotV * sqrt(NdotL * (NdotL - NdotL * a2) + a2);
float denominator = gv + gl;
if (denominator > 0.0) {
return 0.5 / denominator;
}
return 0.0;
}For performance-critical paths, Schlick’s rational approximation can be substituted. This approximation provides an efficient alternative while retaining smooth attenuation toward grazing angles:
// Fast Schlick approximation for the Smith-GGX geometry function
float Geometry_SchlickGGX(float NdotW, float k)
{
return NdotW / (NdotW * (1.0 - k) + k);
}
float Geometry_Smith(float NdotV, float NdotL, float roughness)
{
// Remap roughness for direct analytic lighting
float r = roughness + 1.0;
float k = (r * r) / 8.0;
float ggx1 = Geometry_SchlickGGX(NdotV, k);
float ggx2 = Geometry_SchlickGGX(NdotL, k);
return ggx1 * ggx2;
}By computing the shadowing and masking components along the surface normal, the Smith geometry attenuation function ensures that specular reflections fade realistically toward edge boundaries while preventing the surface from reflecting excess energy.