Three.js LOD Tutorial: Optimize 3D Performance
In this article, you will learn how to implement a Level-of-Detail
(LOD) system in Three.js to automatically swap high-polygon models for
low-polygon ones based on their distance from the camera. We will cover
the core mechanics of the THREE.LOD class, provide a
practical step-by-step code implementation, and share key optimization
tips to keep your web-based 3D applications running smoothly.
Understanding the Three.js LOD Class
Rendering high-polygon models that are far away from the camera
wastes valuable GPU resources because the fine details are invisible at
a distance. The THREE.LOD (Level of Detail) class solves
this by holding multiple versions of a 3D object—each simplified to a
different degree—and automatically rendering the appropriate version
based on its distance from the active camera.
Step-by-Step Implementation
To implement LOD in Three.js, you need to create an instance of
THREE.LOD, define your meshes representing different detail
levels, register those meshes with specific distance thresholds, and add
the LOD object to your scene.
Here is the complete code implementation:
import * as THREE from 'three';
// 1. Initialize the LOD Object
const lod = new THREE.LOD();
// 2. Create Geometries of Varying Complexity
// High-detail version (Used when close to the camera)
const highGeometry = new THREE.IcosahedronGeometry(1, 6);
const highMaterial = new THREE.MeshStandardMaterial({ color: 0xff5555, flatShading: true });
const highMesh = new THREE.Mesh(highGeometry, highMaterial);
// Medium-detail version (Used at moderate distances)
const mediumGeometry = new THREE.IcosahedronGeometry(1, 3);
const mediumMaterial = new THREE.MeshStandardMaterial({ color: 0xff5555, flatShading: true });
const mediumMesh = new THREE.Mesh(mediumGeometry, mediumMaterial);
// Low-detail version (Used when far away)
const lowGeometry = new THREE.IcosahedronGeometry(1, 1);
const lowMaterial = new THREE.MeshStandardMaterial({ color: 0xff5555, flatShading: true });
const lowMesh = new THREE.Mesh(lowGeometry, lowMaterial);
// 3. Add Levels to the LOD Object
// The second parameter is the minimum distance from the camera at which this level displays.
lod.addLevel(highMesh, 0); // Display high-poly mesh from 0 to 15 units of distance
lod.addLevel(mediumMesh, 15); // Display mid-poly mesh from 15 to 30 units of distance
lod.addLevel(lowMesh, 30); // Display low-poly mesh beyond 30 units of distance
// 4. Add the LOD Object to the Scene
scene.add(lod);Updating the LOD in the Render Loop
By default, Three.js automatically updates the active LOD level for all LOD objects in the scene during the standard render call. You only need to ensure your camera and scene are passed to the renderer inside your animation loop:
function animate() {
requestAnimationFrame(animate);
// Optional: Rotate the LOD object to see the performance in action
lod.rotation.y += 0.01;
// The WebGLRenderer automatically calculates camera distance and updates LOD levels
renderer.render(scene, camera);
}
animate();Best Practices for Three.js LOD
To get the most out of your LOD setup, keep the following performance considerations in mind:
- Share Materials: Whenever possible, have your high, medium, and low-poly meshes share the exact same material instance. This reduces draw calls and prevents the GPU from needing to bind new shaders when the model swaps.
- Determine Distances Dynamically: Test your scene on various screen sizes. A distance threshold that looks good on a mobile screen might cause visible “popping” (the sudden transition between models) on a large desktop monitor.
- Use Automated Simplifiers: To generate your low-poly models, use external tools like Blender’s Decimate Modifier, or use automated glTF optimization tools before importing your assets into Three.js.