KHR_materials_volume: Absorption and Thickness in glTF
The KHR_materials_volume extension in glTF enables
realistic rendering of transparent and translucent objects by turning a
polygonal shell into a virtual solid volume. This article examines how
the extension defines physical thickness and light absorption, detailing
the parameters used to calculate ray travel distance and the exponential
decay of light through tinted media such as colored glass, liquids, and
gems.
Thickness in KHR_materials_volume
In traditional real-time rendering, transmissive surfaces (enabled
via KHR_materials_transmission) are treated as infinitely
thin planes. The KHR_materials_volume extension addresses
this by assigning physical depth to surfaces using two key
properties:
thicknessFactor: A scalar floating-point value that defines the thickness of the volume in the mesh's local coordinate space (measured in meters). A value of0.0represents an infinitely thin boundary, which disables volumetric calculations.thicknessTexture: A 2D texture map where thickness variations are stored (typically in the green channel). When provided, the sampled texture value is multiplied by thethicknessFactorto allow localized variations across the surface, such as the thin rim and thick base of a wine glass.
During rendering, this thickness parameter approximates the distance
a refracted light ray travels through the object along the surface
normal. When combined with the index of refraction (defined in
KHR_materials_ior), shaders can calculate the actual path
length of light through the interior without requiring multi-pass
depth-peeling or complex ray marching.
Absorption and Attenuation Properties
Once light enters a volume, its intensity and spectrum change
depending on the interior medium. KHR_materials_volume
models this behavior via the Beer-Lambert law, which dictates that light
absorbs exponentially relative to the distance traveled. The absorption
profile is parameterized through two attributes:
attenuationColor: An RGB vector representing the linear color of light after it has traveled a specific distance through the volume. The default value is[1.0, 1.0, 1.0], indicating no color tint or selective wavelength absorption.attenuationDistance: A positive floating-point value indicating the distance (in meters) light must travel through the material for its color to reach the exact value defined byattenuationColor. If set to infinity (or left unspecified as+Infinity), light passes through without any absorption.
From these parameters, renderers compute the volumetric absorption coefficient (\(\sigma_a\)) per color channel:
\[\sigma_a = -\frac{\ln(\text{attenuationColor})}{\text{attenuationDistance}}\]
Combining Thickness and Absorption
To render the final transmitted color, the engine determines the path length (\(d\)) of the light ray through the volume, scaled by the surface thickness and refracted angle. The transmitted light intensity (\(I\)) is then derived exponentially:
\[I = I_0 \cdot e^{-\sigma_a \cdot d}\]
Thicker regions of a mesh naturally absorb more light and exhibit a
deeper, more saturated tint, while thinner edges appear clearer and
closer to the original light source color. By decoupling the absolute
color (attenuationColor) from the scale of the object
(attenuationDistance), the extension ensures physically
accurate and scale-consistent results across different lighting
environments.