Apply Depth Texture with Three.js MeshDepthMaterial
This article explains how to capture and apply a depth texture to a
scene in Three.js using MeshDepthMaterial. You will learn
how to use this material to visualize distance from the camera, set up a
render target with a depth texture, and apply that texture to objects or
post-processing shaders.
Understanding MeshDepthMaterial
MeshDepthMaterial is a built-in Three.js material that
renders white at the camera’s near plane and black at the far plane (or
vice versa, depending on configuration). It measures the distance of
geometry from the camera, making it ideal for rendering depth maps,
simulating fog, creating soft shadows, or applying post-processing
effects.
There are two primary ways to work with depth in Three.js: overriding the scene’s materials for a quick depth visualization, or rendering the scene depth to a texture for advanced shader usage.
Method 1: Visualizing Depth with Scene Override
The simplest way to apply MeshDepthMaterial to your
entire scene is by using the scene.overrideMaterial
property. This forces every object in the scene to render with the depth
material without changing their original materials permanently.
import * as THREE from 'three';
// 1. Create the depth material
const depthMaterial = new THREE.MeshDepthMaterial();
// 2. Assign it to the scene override
scene.overrideMaterial = depthMaterial;
// 3. Render loop (render as normal)
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
animate();By default, the depth rendering will look entirely white unless your
objects are close to the camera’s far clipping plane. To
make the depth gradient visible, adjust your camera’s near
and far properties:
camera.near = 1;
camera.far = 20;
camera.updateProjectionMatrix();Method 2: Creating and Applying a Depth Texture
For advanced effects like custom shaders, water rendering, or
depth-of-field, you need to store the depth data in a texture. This is
achieved using WebGLRenderTarget and
DepthTexture.
1. Set Up the Render Target and Depth Texture
Create a WebGLRenderTarget and assign a
DepthTexture to its .depthTexture
property.
const width = window.innerWidth;
const height = window.innerHeight;
// Create a depth texture
const depthTexture = new THREE.DepthTexture();
depthTexture.format = THREE.DepthFormat;
depthTexture.type = THREE.UnsignedIntType;
// Create a render target and attach the depth texture
const renderTarget = new THREE.WebGLRenderTarget(width, height, {
minFilter: THREE.NearestFilter,
magFilter: THREE.NearestFilter,
});
renderTarget.depthTexture = depthTexture;2. Render the Scene to the Texture
In your animation loop, render the scene to the render target first to populate the depth texture, then render your final output to the screen.
function animate() {
requestAnimationFrame(animate);
// Render the depth information into our render target
renderer.setRenderTarget(renderTarget);
renderer.render(scene, camera);
// Reset the render target to the screen
renderer.setRenderTarget(null);
// Now you can render your main scene or post-processing quad
renderer.render(postScene, postCamera);
}
animate();3. Use the Depth Texture in a Material
You can now pass the populated depthTexture as a uniform
into a custom ShaderMaterial to apply depth-based effects
to your scene.
const customShaderMaterial = new THREE.ShaderMaterial({
uniforms: {
tDepth: { value: renderTarget.depthTexture },
cameraNear: { value: camera.near },
cameraFar: { value: camera.far }
},
vertexShader: `
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`,
fragmentShader: `
#include <packing>
varying vec2 vUv;
uniform sampler2D tDepth;
uniform float cameraNear;
uniform float cameraFar;
float readDepth(sampler2D depthSampler, vec2 coord) {
float fragCoordZ = texture2D(depthSampler, coord).x;
float viewZ = perspectiveDepthToViewZ(fragCoordZ, cameraNear, cameraFar);
return viewZToOrthographicDepth(viewZ, cameraNear, cameraFar);
}
void main() {
float depth = readDepth(tDepth, vUv);
gl_FragColor = vec4(vec3(depth), 1.0);
}
`
});