Three.js CubeCamera Reflections Guide
In Three.js, creating realistic environment reflections on 3D objects
requires specialized tools, and the CubeCamera is the
primary object used to achieve this effect. This article explains what a
CubeCamera is, how it works to capture dynamic 360-degree
surroundings, and how to implement it to build real-time, high-quality
reflections in your WebGL scenes.
What is a CubeCamera?
A CubeCamera is a specialized camera helper in Three.js
designed to capture a 360-degree view of a scene from a specific point
in 3D space. It consists of six individual cameras pointed in six
different directions (forward, backward, left, right, up, and down).
The images captured by these six cameras are rendered onto a specialized texture called a Cube Texture (or Cubemap). This texture can then be applied to the material of a reflective object, allowing it to reflect its surrounding environment dynamically.
Dynamic vs. Static Reflections
While static reflections can be achieved using pre-rendered cubemap
images (like skyboxes), they cannot reflect moving objects within the
scene. The CubeCamera solves this by rendering the
environment in real-time. If an object moves past a shiny sphere, the
CubeCamera captures that movement, making the sphere
reflect the moving object dynamically.
How to Implement CubeCamera for Reflections
To build dynamic reflections using a CubeCamera, you
need to set up a render target, initialize the camera, assign the
texture to a material, and update the camera in your render loop.
1. Create the Cube Render Target and CubeCamera
First, you must define a WebGLCubeRenderTarget which
acts as the WebGL memory space where the six camera views are saved.
Then, instantiate the CubeCamera.
// Define the resolution of the reflection texture (e.g., 256x256 or 512x512)
const cubeRenderTarget = new THREE.WebGLCubeRenderTarget(256, {
generateMipmaps: true,
minFilter: THREE.LinearMipmapLinearFilter
});
// Create the CubeCamera (near plane, far plane, render target)
const cubeCamera = new THREE.CubeCamera(1, 1000, cubeRenderTarget);
scene.add(cubeCamera);2. Apply the Reflection Texture to a Material
To make an object reflective, assign the texture generated by the
WebGLCubeRenderTarget to the envMap
(environment map) property of the object’s material.
const shinyMaterial = new THREE.MeshStandardMaterial({
color: 0xffffff,
roughness: 0.0, // Low roughness for a mirror-like finish
metalness: 1.0, // High metalness to enhance reflectivity
envMap: cubeRenderTarget.texture // Apply the dynamic texture
});
const reflectiveSphere = new THREE.Mesh(new THREE.SphereGeometry(5, 32, 32), shinyMaterial);
scene.add(reflectiveSphere);
// Keep the CubeCamera at the center of the reflective object
cubeCamera.position.copy(reflectiveSphere.position);3. Update the Reflection in the Animation Loop
To ensure the reflection updates as things move in the scene, you
must update the CubeCamera inside your animation loop.
To prevent the reflective object from rendering its own interior, you should hide the object before updating the camera, and make it visible again afterward.
function animate() {
requestAnimationFrame(animate);
// 1. Hide the reflective object so it doesn't reflect itself
reflectiveSphere.visible = false;
// 2. Update the CubeCamera with the current renderer and scene
cubeCamera.update(renderer, scene);
// 3. Bring the reflective object back
reflectiveSphere.visible = true;
// 4. Render the main scene with the default camera
renderer.render(scene, camera);
}
animate();Performance Considerations
Because a CubeCamera renders the entire 3D scene six
times per update (once for each face of the cube), it is highly
resource-intensive. To maintain a smooth frame rate:
- Reduce Resolution: Keep the render target resolution as low as possible (e.g., 128x128 or 256x256). Highly detailed reflections are rarely necessary for realistic visuals.
- Throttled Updates: Instead of updating the
CubeCameraevery frame, update it every second or third frame, or only when objects in the environment move. - Layer Filtering: Use layers to exclude complex,
non-essential background objects from being rendered by the
CubeCamera.