Dynamic CubeCamera Reflections in Three.js
Creating realistic, real-time reflections in Three.js can
significantly enhance the visual fidelity of a 3D scene. This article
explains how to implement a dynamic reflection probe using
CubeCamera and WebGLCubeRenderTarget to
capture the surrounding environment and update a mesh’s reflection map
on every frame. You will learn how to set up the camera, apply the
texture to a reflective material, and optimize the rendering loop to
avoid self-reflection artifacts.
1. Create the Cube Render Target and CubeCamera
To capture a 360-degree view of the scene, you need a helper object
that renders the scene from six different directions into a cube map.
This is achieved using WebGLCubeRenderTarget and
CubeCamera.
// Define the resolution of the cube map (must be a power of 2, e.g., 256, 512)
const cubeMapSize = 512;
// Create the cube render target
const cubeRenderTarget = new THREE.WebGLCubeRenderTarget(cubeMapSize, {
generateMipmaps: true,
minFilter: THREE.LinearMipmapLinearFilter
});
// Create the CubeCamera (near plane, far plane, render target)
const cubeCamera = new THREE.CubeCamera(0.1, 1000, cubeRenderTarget);
scene.add(cubeCamera);2. Apply the Reflection Map to a Material
To make an object reflective, assign the texture from the cube render
target to the envMap property of the object’s material. Use
MeshStandardMaterial or MeshPhysicalMaterial
with low roughness and high metalness for a mirror-like finish.
const mirrorMaterial = new THREE.MeshStandardMaterial({
metalness: 1.0,
roughness: 0.0,
envMap: cubeRenderTarget.texture
});
const mirrorGeometry = new THREE.SphereGeometry(2, 32, 32);
const mirrorMesh = new THREE.Mesh(mirrorGeometry, mirrorMaterial);
scene.add(mirrorMesh);
// Position the CubeCamera at the center of the reflective object
cubeCamera.position.copy(mirrorMesh.position);3. Update the Reflection Every Frame
To make the reflection dynamic, you must update the
CubeCamera inside your animation loop. Because the camera
is inside the reflective object, you must temporarily hide the
reflective object before updating the CubeCamera to prevent
the object from rendering its own interior.
function animate() {
requestAnimationFrame(animate);
// 1. Animate your scene objects here (e.g., rotating meshes)
// 2. Hide the reflective object to avoid self-rendering artifacts
mirrorMesh.visible = false;
// 3. Keep the CubeCamera synced with the mesh position if it moves
cubeCamera.position.copy(mirrorMesh.position);
// 4. Update the CubeCamera
cubeCamera.update(renderer, scene);
// 5. Make the reflective object visible again
mirrorMesh.visible = true;
// 6. Render the main scene with the default perspective camera
renderer.render(scene, camera);
}
animate();Performance Considerations
Updating a CubeCamera every frame requires rendering the
scene six additional times per frame (once for each face of the cube).
To maintain high performance: * Reduce Resolution: Keep
the WebGLCubeRenderTarget resolution as low as acceptable
(e.g., 256 or 512). * Selective Layers: Use Three.js
layers to exclude complex background geometry or particle systems from
being rendered by the CubeCamera. * Throttle
Updates: If real-time reflections are not critical, update the
CubeCamera every few frames instead of every single
frame.