GGX Trowbridge-Reitz NDF in GLSL Explained

The GGX (Trowbridge-Reitz) Normal Distribution Function (NDF) is a core component of modern Physically Based Rendering (PBR) specular models. It statistically calculates the concentration of microscopic surface facets—known as microfacets—oriented precisely toward the half-vector between the light and view directions. This article explains the underlying mathematical model of the GGX distribution, breaks down how it evaluates surface roughness to produce realistic specular highlights, and provides a direct, production-ready GLSL implementation.

The Microfacet Theory and the Half-Vector

Microfacet theory assumes that rough surfaces are composed of microscopic, perfectly reflective mirrors. A microfacet only reflects light from an incoming light direction (\(L\)) directly into the camera view direction (\(V\)) if its individual normal (\(m\)) aligns with the half-vector (\(H\)).

The half-vector is the normalized vector bisecting the view and light vectors:

\[H = \frac{L + V}{\|L + V\|}\]

The Normal Distribution Function, denoted as \(D(H)\), computes the statistical density of microfacets pointing in the direction of \(H\). Surfaces with higher alignment yield sharper, more intense specular highlights, while surfaces with scattered alignments yield broad, diffuse reflections.

The GGX / Trowbridge-Reitz Equation

The GGX distribution is widely preferred in computer graphics because of its heavy-tailed distribution, which creates a sharp peak with a soft, natural halo falloff. The mathematical formula is:

\[D_{GGX}(N, H, \alpha) = \frac{\alpha^2}{\pi \left( (N \cdot H)^2 (\alpha^2 - 1) + 1 \right)^2}\]

Where:

  • \(N\) is the macroscopic surface normal.
  • \(H\) is the normalized half-vector.
  • \(N \cdot H\) is the cosine of the angle between the macro normal and the half-vector.
  • \(\alpha\) is the roughness parameter. In modern PBR pipelines (such as Disney's principled model), \(\alpha\) is set to the square of the perceptual roughness (\(\alpha = \text{roughness}^2\)) to ensure a linear, intuitive visual progression.

Breaking Down the Math

  1. Roughness Squaring (\(\alpha^2\)): Squaring the roughness value shifts distribution scaling so that changes at lower roughness values feel uniform to the human eye. The numerator \(\alpha^2\) scales the peak intensity of the specular highlight.
  2. Alignment Factor (\((N \cdot H)^2\)): When the surface normal and half-vector are parallel, \(N \cdot H = 1\). As the microfacets deviate from the normal, this value approaches \(0\).
  3. Denominator Scaling (\(((N \cdot H)^2 (\alpha^2 - 1) + 1)^2\)):
    • When roughness is very low (\(\alpha \to 0\)) and alignment is high (\(N \cdot H \to 1\)), the denominator becomes extremely small, causing the function to spike into a sharp, tight reflection.
    • When \(N \cdot H\) decreases, the denominator expands rapidly, producing the characteristic GGX falloff.
  4. Energy Conservation (\(\pi\)): Multiplying the squared denominator by \(\pi\) normalizes the integral of the distribution over the hemisphere to ensure the microfacets do not reflect more light than they receive.

GLSL Implementation

Below is the standard, optimized GLSL implementation of the Trowbridge-Reitz NDF:

const float PI = 3.14159265359;

float DistributionGGX(vec3 N, vec3 H, float roughness)
{
    // Remap perceptual roughness to alpha
    float a = roughness * roughness;
    float a2 = a * a;
    
    // Calculate the dot product between normal and half-vector
    float NdotH = max(dot(N, H), 0.0);
    float NdotH2 = NdotH * NdotH;
    
    // Calculate the denominator
    float denom = (NdotH2 * (a2 - 1.0) + 1.0);
    denom = PI * denom * denom;
    
    // Prevent division by zero for completely smooth surfaces
    return a2 / max(denom, 0.0000001);
}

Numerical Stability Considerations

In real-time fragment shaders, very low roughness values (e.g., \(0.0\)) cause floating-point instability and division by zero. Clamping perceptual roughness to a minimum threshold (such as \(0.001\) or \(0.045\) depending on precision formats like FP16 or FP32) prevents visual artifacts, black spots, or NaNs during rendering.