Simulating Real-World Light Decay in Three.js
This article explores how Three.js utilizes light attenuation to
mimic real-world physics, focusing on how light intensity diminishes
over distance. We will examine the mathematical principles behind the
inverse-square law, how Three.js implements these concepts through the
decay and distance properties of point and
spot lights, and how to configure your renderer to achieve physically
accurate lighting in your 3D scenes.
The Physics of Light Attenuation
In the physical world, light spreads out as it travels away from a localized source, such as a lightbulb or a candle. Because the same amount of light energy is distributed over an ever-increasing spherical surface area, the brightness decreases. This phenomenon is governed by the inverse-square law, which states that the intensity of light is inversely proportional to the square of the distance from the source (\(I \propto 1/d^2\)). If you double your distance from a light source, the light intensity drops to one-quarter of its original value.
Implementing Attenuation in Three.js
Three.js simulates this physical behavior primarily using two types
of lights: PointLight and SpotLight.
Directional lights (like simulated sunlight) do not experience
attenuation because their rays are parallel and represent a source
infinitely far away.
To control how light fades over distance in Three.js, developers rely on two key properties:
decay: This property defines how quickly the light dims.- A
decayvalue of2mathematically matches the real-world physics of the inverse-square law. - A
decayvalue of1results in a linear fade, which is less realistic but can be useful for stylized or low-performance rendering. - A
decayvalue of0means the light does not fade at all, maintaining its full intensity regardless of distance.
- A
distance: This property defines the maximum range of the light.- When set to
0, the light decays infinitely according to thedecayformula, meaning it never truly reaches zero intensity but becomes negligible at great distances. This is the most physically accurate setting. - When set to a value greater than
0, the light will attenuate normally until it hits that specific distance, at which point its intensity abruptly drops to zero.
- When set to
Achieving Physically Correct Lighting
To ensure that Three.js calculates light attenuation using true physical formulas, you must configure the renderer correctly.
In modern versions of Three.js, physically correct rendering is the default. However, to guarantee accurate real-world light behavior, you should ensure the legacy lighting mode is disabled:
renderer.useLegacyLights = false;(Note: In older versions of Three.js prior to r150, this was
enabled using
renderer.physicallyCorrectLights = true).
When physical rendering is active, light intensities are calculated
in lumens (for spot/point lights) or candelas, and the decay exponent of
2 behaves exactly like real-world physics.
Practical Configuration
For a realistic setup, instantiate a light with a decay
of 2, a distance of 0 (for
infinite physical decay), and a high intensity to
compensate for the rapid falloff:
const physicalLight = new THREE.PointLight(0xffffff, 100, 0, 2);
scene.add(physicalLight);By understanding and utilizing these properties, you can transform flat, computer-generated scenes into highly realistic environments with natural depth and atmospheric lighting.