glTF Light Attenuation: Point and Spot Falloff
glTF manages point and spot light falloff primarily through the
KHR_lights_punctual extension, using physically based
inverse-square distance attenuation coupled with an optional range clamp
and angular cone factors. While point lights attenuate purely based on
distance, spot lights incorporate additional angular attenuation to
simulate a focused beam. This article outlines the mathematical
parameters, formulas, and cutoff behaviors that dictate how light
intensity decreases over space within the glTF standard.
Distance Attenuation (Point and Spot Lights)
In standard glTF, both point and spot lights behave as punctual
lights that emit light from a single dimensionless point in space. Their
light falloff across distance is governed by two main elements: the
physical inverse-square law and the optional range
property.
1. The Inverse-Square Law
By default, glTF follows the physically realistic inverse-square law, where the intensity of light diminishes inversely with the square of the distance from the source:
\[\text{Attenuation}_{\text{distance}} = \frac{1}{\max(d^2, \epsilon)}\]
Where:
- \(d\) is the Euclidean distance from the light position to the shaded surface.
- \(\epsilon\) is a small threshold (typically around \(0.0001\)) applied to prevent a division-by-zero anomaly when an object is at the exact center of the light.
2. Range Clamping and Smooth Windowing
Because physical light theoretically travels infinitely, real-time
rendering engines introduce a cutoff distance to discard negligible
light calculations. In glTF, this is configured via the
range property.
When range is defined and greater than zero, glTF
applies a smooth windowing function that scales the light smoothly to
zero at the specified boundary, preventing harsh visual seams:
\[\text{RangeFactor} = \max\left(0.0, \min\left(1.0, 1.0 - \left(\frac{d}{\text{range}}\right)^4\right)\right)\]
Combining this with distance falloff yields the full distance attenuation formula defined in the glTF specification:
\[\text{Attenuation}_{\text{distance}} = \frac{\text{RangeFactor}^2}{\max(d^2, \epsilon)}\]
If no range is defined, the light continues to fall off
infinitely according to the pure inverse-square law.
Angular Attenuation (Spot Lights Only)
Spot lights project light within a cone and introduce directional falloff alongside distance falloff. The shape and softness of the light cone are determined by two angles defined in radians:
innerConeAngle: The angle measured from the spotlight direction vector within which the light is at full, unmodified intensity. Defaults to \(0.0\).outerConeAngle: The angle beyond which the light completely attenuates to zero. Defaults to \(\pi / 4\) radians (\(45^\circ\)).
The region between innerConeAngle and
outerConeAngle defines the light's penumbra—a smooth
transition from peak brightness to complete darkness.
Angular Factor Calculation
To compute angular falloff, the cosine of the angle between the light’s central forward axis (\(L_{\text{dir}}\)) and the vector from the light to the surface (\(L\)) is compared against the cosines of the cone boundaries:
Calculate the scale and offset: \[\text{lightAngleScale} = \frac{1.0}{\max(0.001, \cos(\text{innerConeAngle}) - \cos(\text{outerConeAngle}))}\] \[\text{lightAngleOffset} = -\cos(\text{outerConeAngle}) \times \text{lightAngleScale}\]
Compute the angular attenuation factor: \[C_d = \max(0.0, L_{\text{dir}} \cdot L)\] \[\text{Attenuation}_{\text{angle}} = \text{clamp}(C_d \times \text{lightAngleScale} + \text{lightAngleOffset}, 0.0, 1.0)^2\]
Squaring the clamped linear transition produces a smooth, quadratic curve that avoids abrupt banding along the edge of the spotlight beam.
Summary of Falloff Execution
- Point Lights: Total attenuation is strictly a
function of distance:
\(\text{Total Attenuation} = \text{Attenuation}_{\text{distance}}\) - Spot Lights: Total attenuation is the product of
both distance and angular limits:
\(\text{Total Attenuation} = \text{Attenuation}_{\text{distance}} \times \text{Attenuation}_{\text{angle}}\)