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: