Mastering Three.js Shadows: Performance Tips and Real‑World Optimizations
This article explains three.js shadow‑mapping mechanisms, compares shadow types, and provides concrete code‑level optimizations for global and ground shadows that improve visual quality while keeping performance suitable for mobile web applications.
Introduction
High‑quality shadows are essential for realistic 3D web experiences. three.js offers several shadow‑mapping techniques, but they can be costly on performance, especially on mobile devices. This article explains the shadow mechanisms in three.js and provides practical optimisation strategies.
Shadow Types in three.js
three.js supports four main shadow map types:
BasicShadowMap – fast, hard edges, low quality.
PCFShadowMap – default, soft edges via Percentage‑Closer Filtering, good balance.
PCFSoftShadowMap – further softening, higher cost.
VSMShadowMap – variance shadow map, high quality but can produce halo artifacts.
Global Shadow Optimisation
Rather than using the default settings, the article recommends using PCFShadowMap and adjusting the shadow camera to focus on the avatar’s head region. Increasing the shadow map resolution improves edge quality but adds cost, so the optimisation reduces the orthographic camera bounds and tweaks bias, radius, and light intensity.
const bias = 1.6; // y‑axis bias for the shadow camera
const mainLight = new THREE.DirectionalLight(0xf2f7ff);
mainLight.intensity = 1.8;
mainLight.position.set(0.3, 0.81 + bias, 2.71);
const target = new THREE.Object3D();
target.position.set(0, bias, 0); // light target
group.add(target);
mainLight.target = target;
mainLight.castShadow = true;
mainLight.shadow.radius = 2; // blur radius, tune as needed
const { camera } = mainLight.shadow;
camera.far = 5;
// shrink camera bounds from ±5 to ±0.5
camera.top = -0.5;
camera.bottom = 0.5;
camera.left = -0.5;
camera.right = 0.5;Ground Shadow Implementation
The ground shadow is created by rendering a depth map from an orthographic camera placed under the model, blurring it, and applying it as a texture on a plane. The approach follows Google’s model‑viewer implementation.
const size = 64;
const shadowTarget = new THREE.WebGLRenderTarget(size, size);
const shadowTargetBlur = new THREE.WebGLRenderTarget(size, size);
this.shadowTarget = shadowTarget;
this.shadowTargetBlur = shadowTargetBlur;
this.position.set(0, -0.05, 0);
this.rotateX(Math.PI / 2); // align plane with ground
const camera = new THREE.OrthographicCamera(-0.75, 0.75, 0.75, -0.75, 0, 0.5);
camera.rotateX(Math.PI / 6);
camera.rotateY(Math.PI / 6);
this.add(camera);
this.camera = camera;
const visionCamera = new THREE.OrthographicCamera(-0.75, 0.75, 0.75, -0.75, 0, 2);
this.add(visionCamera);
this.visionCamera = visionCamera;
this.depthMaterial.onBeforeCompile = function (shader) {
shader.fragmentShader = shader.fragmentShader.replace(
'gl_FragColor = vec4( vec3( 1.0 - fragCoordZ ), opacity );',
'gl_FragColor = vec4( vec3( 0.0 ), ( 1.0 - fragCoordZ ) * opacity );'
);
};
const planeGeometry = new THREE.PlaneGeometry(1.5, 1.5);
const material = new THREE.MeshBasicMaterial({
opacity: 0.3,
transparent: true,
map: shadowTarget.texture,
side: THREE.DoubleSide,
color: 0x666666
});
const plane = new THREE.Mesh(planeGeometry, material);
visionCamera.add(plane);
const blurPlane = new THREE.Mesh(planeGeometry);
blurPlane.visible = false;
visionCamera.add(blurPlane);
this.plane = plane;
this.blurPlane = blurPlane;Conclusion
By selecting PCFShadowMap, narrowing the shadow camera frustum, and using a low‑resolution blurred ground‑shadow texture (64×64), the article achieves noticeably better shadow quality without a noticeable performance hit. Further improvements could involve device‑specific rendering paths or multi‑camera shadow maps.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
vivo Internet Technology
Sharing practical vivo Internet technology insights and salon events, plus the latest industry news and hot conferences.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
