Fixing Three.js Shadow Artifacts with normalBias
This article explains the role of the normalBias
property in Three.js and how it is used to eliminate shadow artifacts,
such as shadow acne, without causing detached shadows. You will learn
the mechanical differences between standard bias and
normalBias, and how to apply this property to achieve
clean, realistic shadows in your 3D scenes.
In Three.js, shadows are generated using shadow maps, which are depth textures rendered from the perspective of the light source. Because of the discrete resolution of these shadow maps, surfaces can incorrectly cast shadows on themselves. This phenomenon is known as “shadow acne” and appears as distracting, Moire-like striped patterns across 3D meshes.
Traditionally, developers used the standard bias
property to solve this. The bias property slightly offsets
the depth values of the shadow map along the light’s direction. While
effective at removing shadow acne, a high bias value
introduces a new artifact called “peter-panning,” where shadows appear
detached from the objects casting them, making elements look like they
are floating.
The normalBias property addresses this limitation.
Instead of shifting the depth calculation along the view vector of the
light, normalBias offsets the shadow query position along
the geometry’s surface normals (the direction pointing directly outward
from each face).
By shifting the calculation along the surface normal,
normalBias prevents self-shadowing on curved and angled
surfaces without pushing the overall shadow away from the base of the
object. This makes it highly effective for organic shapes, rounded
meshes, and complex geometries where standard bias would fail.
To use normalBias in Three.js, you apply it directly to
a light’s shadow object:
const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
directionalLight.castShadow = true;
// Set normalBias to a small positive value
directionalLight.shadow.normalBias = 0.05; When fine-tuning shadows, the best practice is to keep both
bias and normalBias values as close to zero as
possible. Start by setting bias to 0, and gradually
increase normalBias in tiny increments (such as 0.01 to
0.05) until the shadow acne disappears. Combining a very small standard
bias with a targeted normalBias often yields
the most visually accurate results.