glTF KHR_materials_dispersion Refraction Explained
The KHR_materials_dispersion extension enhances glTF’s
physically based rendering (PBR) pipeline by introducing chromatic
dispersion to transmissive surfaces. Chromatic dispersion occurs when
different wavelengths of light bend at varying angles as they pass
through a medium, producing a rainbow-like splitting effect known as
chromatic aberration. This article details how the extension defines
dispersion, derives wavelength-dependent indices of refraction (IOR),
and applies these values to calculate light paths in both real-time and
offline renderers.
The Mathematical Definition of Dispersion
The extension introduces a single non-negative floating-point
property, dispersion. Mathematically, this property is
defined as the reciprocal of the Abbe number (\(1 / V_d\)):
\[D = \frac{1}{V_d} = \frac{n_F - n_C}{n_d - 1}\]
In this formula:
- \(n_d\) is the standard refractive
index at the Fraunhofer \(d\)-line
(\(\approx 587.6\text{ nm}\),
yellow-green light), provided by the
KHR_materials_iorextension (defaulting to 1.5). - \(n_F\) is the refractive index at the Fraunhofer \(F\)-line (\(\approx 486.1\text{ nm}\), blue light).
- \(n_C\) is the refractive index at the Fraunhofer \(C\)-line (\(\approx 656.3\text{ nm}\), red light).
- \(V_d\) is the Abbe number, which inversely measures the dispersion of a transparent medium. Lower Abbe numbers denote higher dispersion.
By using \(D = 1 / V_d\), a value of
0.0 represents an ideal non-dispersive material, while
higher values correspond to greater spectral separation.
Deriving Refractive Indices per Channel
To compute refraction, a renderer must determine the distinct index
of refraction for different parts of the visible spectrum. The total
refractive spread \(\Delta n\) across
the visible range is calculated directly from the base index \(n\) and the dispersion value
\(D\):
\[\Delta n = n_F - n_C = (n - 1) \cdot D\]
Renderers operating in the standard RGB color space typically assign target wavelengths to the primary color channels (red, green, and blue):
- Green channel (\(n_G\)): Evaluated at the central base index: \(n_G = n\).
- Blue channel (\(n_B\)): Represents shorter wavelengths, which experience stronger refraction: \(n_B \approx n + 0.5 \cdot \Delta n\).
- Red channel (\(n_R\)): Represents longer wavelengths, which experience weaker refraction: \(n_R \approx n - 0.5 \cdot \Delta n\).
For spectral renderers requiring continuous index values across arbitrary wavelengths \(\lambda\), Cauchy’s empirical equation is commonly parameterized using \(n\) and \(D\):
\[n(\lambda) = A + \frac{B}{\lambda^2}\]
The coefficients \(A\) and \(B\) are resolved using the known values at \(\lambda_F\) and \(\lambda_C\).
Applying Snell's Law to Split Light Rays
Once the per-wavelength or per-channel indices are resolved, refraction directions are computed independently using Snell’s Law:
\[n_1 \sin(\theta_1) = n_2(\lambda) \sin(\theta_2(\lambda))\]
Given an incident vector \(I\), surface normal \(N\), and an initial medium index \(\eta_1\) (typically air, where \(\eta_1 \approx 1.0\)):
- The relative index of refraction \(\eta(\lambda) = \eta_1 / n_2(\lambda)\) is determined for each channel.
- The transmitted direction \(T(\lambda)\) is calculated: \[T(\lambda) = \eta(\lambda) I + \left( \eta(\lambda) \cos(\theta_1) - \sqrt{1 - \eta(\lambda)^2 (1 - \cos^2(\theta_1))} \right) N\]
- Because \(n_B > n_G > n_R\), the blue light direction bends more acutely toward the surface normal than the green or red light directions.
Engine Implementations
Rendering engines process these divergent paths using one of two primary methods:
- Real-Time Renderers: Rasterization-based engines approximate dispersion by tracing three separate transmission vectors (one for red, green, and blue) or by offsetting the UV coordinates of background transmission buffers according to the calculated angular deflection for each channel.
- Path Tracers: Spectral path tracers randomly assign a specific continuous wavelength to each spawned camera ray, evaluate the single exact \(n(\lambda)\) for that wavelength, and aggregate the monochromatic contributions across multiple samples to reconstruct accurate spectral dispersion without split paths.