Optimizing Three.js Shadow Map Properties
This article provides a practical guide on optimizing Three.js
shadows by configuring crucial shadow map properties like
mapSize, camera frustum boundaries, and bias. Learning how
to adjust these settings allows you to strike the perfect balance
between high-fidelity visual rendering and smooth frame rates in your
WebGL applications.
Understanding shadow.mapSize
The mapSize property (specifically
shadow.mapSize.width and
shadow.mapSize.height) defines the resolution of the depth
map texture used to calculate shadows. By default, Three.js initialized
lights use a 512x512 pixel texture.
- Performance Impact: Increasing this value (e.g., to 1024, 2048, or 4096) creates sharper, highly detailed shadows but heavily consumes GPU memory and fill rate. Decreasing it (e.g., to 256) drastically improves performance at the cost of pixelated, blocky shadow edges.
- Best Practice: Always use powers of two for map dimensions. For mobile optimization, keep map sizes at 512 or lower, while desktop applications can typically handle 1024 or 2048.
Tightening the Shadow Camera Frustum
Shadows in Three.js are rendered from the perspective of a hidden
camera attached to the light source
(light.shadow.camera).
- The Problem: If the shadow camera’s frustum
(defined by
top,bottom,left,right,near, andfarproperties) is set too wide, the shadow map resolution is stretched over an unnecessarily large area. This results in blurry, low-quality shadows even with a highmapSize. - The Optimization: Shrink the shadow camera’s boundaries so they tightly enclose only the objects in your scene that actually cast and receive shadows. Maximizing the coverage of the frustum ensures that every pixel of your shadow map is utilized efficiently.
Eliminating Artifacts with bias and normalBias
When depth calculations are slightly imprecise, virtual scenes suffer from “shadow acne”—an unwanted pattern of dark lines or pixel grids appearing across surfaces.
- shadow.bias: This property offsets the depth query
slightly. A very small positive value (e.g.,
0.0001) can eliminate shadow acne. However, setting it too high causes “peter-panning,” where shadows appear detached and float away from the base of the objects. - shadow.normalBias: This property offsets the shadow position along the surface normals of the geometry. It is highly effective at resolving shadow acne on curved surfaces without causing the floating effect associated with standard bias.
Softening Shadows with shadow.radius
If you are utilizing shadow map types that support custom filtering,
such as PCFShadowMap or PCFSoftShadowMap on
the WebGLRenderer, you can utilize the
shadow.radius property.
- How it works: Increasing the
radius(default is1) blurs the edges of the shadow map. This allows you to simulate realistic, soft shadows. - Optimization Benefit: Using a low
mapSizecombined with a slightly highershadow.radiuscan simulate smooth, expensive-looking shadows at a fraction of the performance cost of rendering a high-resolution shadow map.