Kelemen-Szirmay-Kalos Specular BRDF in GLSL

The Kelemen-Szirmay-Kalos specular BRDF is an efficient, physically plausible microfacet model designed to simplify the evaluation of geometric attenuation and the radiometric denominator found in standard microfacet theory. By coupling the Cook-Torrance geometric shadowing-masking term with the projection factors into a single compact expression, it drastically reduces computational cost while preserving energy conservation. This article details the mathematical foundation of the Kelemen-Szirmay-Kalos formulation and demonstrates how to implement it directly in GLSL.

Mathematical Formulation

The standard Cook-Torrance microfacet specular BRDF is defined as:

\[f_s(L, V) = \frac{D(H) \cdot F(V, H) \cdot G(L, V, H)}{4 (N \cdot L)(N \cdot V)}\]

Where:

  • \(D(H)\) is the microfacet Normal Distribution Function (NDF).
  • \(F(V, H)\) is the Fresnel reflectance factor.
  • \(G(L, V, H)\) is the geometric attenuation (shadowing-masking) term.
  • \(4 (N \cdot L)(N \cdot V)\) is the geometric correction denominator.

Evaluating modern height-correlated geometric shadowing models (such as Smith-GGX) involves multiple square roots and division operations. Csaba Kelemen and László Szirmay-Kalos proposed an alternative formulation where the shadowing factor \(G\) is approximated by considering the correlation between incoming and outgoing directions:

\[G(L, V, H) \approx \frac{2 (N \cdot L)(N \cdot V)}{1 + L \cdot V}\]

When divided by the standard denominator \(4 (N \cdot L)(N \cdot V)\), the \((N \cdot L)\) and \((N \cdot V)\) terms cancel out:

\[\frac{G(L, V, H)}{4 (N \cdot L)(N \cdot V)} \approx \frac{1}{2 (1 + L \cdot V)}\]

Using the identity relating the incident and view vectors to the half-vector \(H = \frac{L + V}{\|L + V\|}\):

\[1 + L \cdot V = 2 (V \cdot H)^2 = 2 (L \cdot H)^2\]

Substituting this into the quotient produces the visibility factor:

\[V_{Kelemen} = \frac{1}{4 (V \cdot H)^2}\]

This reduces the entire geometric shadowing and denominator evaluation into a single reciprocal multiplication based on \((V \cdot H)\).


GLSL Implementation

The Kelemen-Szirmay-Kalos approximation is paired with an NDF (typically GGX/Trowbridge-Reitz) and the Fresnel-Schlick approximation.

// Normal Distribution Function: GGX / Trowbridge-Reitz
float D_GGX(float NdotH, float roughness) {
    float alpha = roughness * roughness;
    float alpha2 = alpha * alpha;
    float denom = (NdotH * NdotH * (alpha2 - 1.0) + 1.0);
    const float PI = 3.14159265359;
    return alpha2 / (PI * denom * denom);
}

// Fresnel Function: Schlick Approximation
vec3 F_Schlick(float VdotH, vec3 F0) {
    return F0 + (vec3(1.0) - F0) * pow(clamp(1.0 - VdotH, 0.0, 1.0), 5.0);
}

// Kelemen-Szirmay-Kalos Visibility Term: G / (4 * NdotL * NdotV)
float V_Kelemen(float VdotH) {
    // Clamping avoids division by zero at grazing angles
    float VdotH2 = max(VdotH * VdotH, 0.00001);
    return 0.25 / VdotH2;
}

// Complete Kelemen-Szirmay-Kalos Specular BRDF Evaluation
vec3 BRDF_Kelemen(vec3 N, vec3 V, vec3 L, float roughness, vec3 F0) {
    vec3 H = normalize(V + L);

    float NdotL = clamp(dot(N, L), 0.0, 1.0);
    float NdotH = clamp(dot(N, H), 0.0, 1.0);
    float VdotH = clamp(dot(V, H), 0.0, 1.0);

    if (NdotL <= 0.0) {
        return vec3(0.0);
    }

    float D = D_GGX(NdotH, roughness);
    vec3  F = F_Schlick(VdotH, F0);
    float Vis = V_Kelemen(VdotH);

    // Final specular contribution: D * F * Vis
    return D * F * Vis;
}

Usage in Light Calculations

To compute the final reflected radiance from a punctual light source, multiply the BRDF output by \((N \cdot L)\) and the incoming light radiance:

void main() {
    // Normalized input vectors
    vec3 N = normalize(vNormal);
    vec3 V = normalize(uCameraPosition - vWorldPos);
    vec3 L = normalize(uLightPosition - vWorldPos);

    vec3 F0 = vec3(0.04); // Default non-metal reflectance
    F0 = mix(F0, uAlbedo, uMetallic);

    float NdotL = clamp(dot(N, L), 0.0, 1.0);

    vec3 specular = BRDF_Kelemen(N, V, L, uRoughness, F0);
    vec3 finalColor = specular * uLightColor * NdotL;

    fragColor = vec4(finalColor, 1.0);
}

Performance and Trade-Offs

  • Arithmetic Efficiency: Eliminating \((N \cdot L)\) and \((N \cdot V)\) from the visibility term eliminates square roots and costly divisions required by separable Smith formulations.
  • Grazing Behavior: Because this approximation omits explicit dependence on surface orientation \(N\) in the visibility term, it does not darken as aggressively at grazing angles (\(N \cdot V \to 0\)) compared to correlated Smith-GGX.
  • Stability: The term \(0.25 / (V \cdot H)^2\) approaches infinity only when the light and view vectors are nearly opposite (\(V \cdot H \to 0\)), which is naturally mitigated by clamping \(V \cdot H\) and surface culling via \((N \cdot L)\).