Bump Map vs Displacement Map in Three.js
This article explains the specific visual and structural differences between bump maps and displacement maps in Three.js. While both textures are used to add depth and detail to 3D surfaces, they do so using entirely different rendering techniques. Understanding these differences will help you choose the right approach for your WebGL projects to balance visual fidelity and performance.
The Core Visual Differences
The fundamental visual difference between a bump map and a displacement map lies in how they affect the silhouette of a 3D object and how they interact with light.
1. Silhouette and Edge Profile
- Bump Map: A bump map is a visual illusion. It does not alter the actual geometry of the mesh. If you look at the edge of a sphere using a bump map, the silhouette remains a perfectly smooth circle. The “depth” is only visible on the faces pointing toward the camera.
- Displacement Map: A displacement map physically alters the geometry. It moves the vertices of the mesh outward or inward based on the grayscale values of the texture. If you look at the edge of a sphere using a displacement map, the silhouette will be realistically bumpy, jagged, or deformed.
2. Shadows and Self-Shadowing
- Bump Map: Because the surface remains flat, a bump-mapped object cannot cast real shadows onto itself. It simulates depth by manipulating how light reflects off the surface (altering surface normals), but it cannot block light to create true geometric shadows.
- Displacement Map: Since the geometry is physically deformed, the displaced peaks will cast real, accurate shadows onto the troughs of the same mesh when illuminated by a light source in Three.js.
3. Viewing Angles (The Grazing Angle Limit)
- Bump Map: The illusion of depth is lost when viewing the surface at an acute, glancing angle (grazing angle). The surface will suddenly appear completely flat.
- Displacement Map: The depth remains perfectly realistic from any viewing angle, including extreme grazing angles, because the physical geometry is actually there.
Technical Implementation in Three.js
The visual differences stem from how Three.js processes these maps in the shaders.
Bump Map
(MeshStandardMaterial.bumpMap)
Three.js uses the grayscale values of the bump map to perturb the
surface normals during the fragment shader step. * Geometry
Requirement: Works on low-polygon meshes. You do not need a
highly detailed mesh to achieve the effect. * Three.js
Properties: Controlled via bumpMap and
bumpScale (which dictates the perceived depth of the
bumps).
const material = new THREE.MeshStandardMaterial({
color: 0x888888,
bumpMap: bumpTexture,
bumpScale: 0.05
});Displacement
Map (MeshStandardMaterial.displacementMap)
Three.js uses the grayscale values of the displacement map to
physically reposition the vertices of the mesh during the vertex shader
step. * Geometry Requirement: Requires a highly
subdivided mesh. If your mesh only has a few vertices, there is nothing
for the displacement map to move, resulting in a distorted or blocky
appearance. * Three.js Properties: Controlled via
displacementMap, displacementScale (how far
the vertices are pushed), and displacementBias (the offset
of the displacement).
// High polygon count is required for displacement
const geometry = new THREE.PlaneGeometry(10, 10, 128, 128);
const material = new THREE.MeshStandardMaterial({
color: 0x888888,
displacementMap: displacementTexture,
displacementScale: 0.5,
displacementBias: 0
});Summary of When to Use Which
- Use a Bump Map for fine, subtle surface details like skin pores, orange peel textures, leather grain, or small scratches. This keeps your polygon count low and your Three.js application running at a high framerate.
- Use a Displacement Map for large, dramatic surface changes where the silhouette is highly visible, such as rocky terrains, brick walls, or deep wood carving. Ensure you budget your polygon count carefully, as highly subdivided meshes can severely impact WebGL performance.