Three.js Tracking Shot: Parent Camera to Moving Mesh
Creating a dynamic tracking shot in Three.js is highly efficient when
you leverage the 3D scene graph by parenting a
PerspectiveCamera directly to a moving mesh. This article
explains how to establish this parent-child relationship so the camera
automatically inherits the position, rotation, and scale of the target
object. By using this native Three.js behavior, you eliminate the need
to manually calculate and update the camera’s coordinates in your
animation loop, resulting in a smooth, cinematic follow-cam effect.
Understanding the Scene Graph Parent-Child Relationship
In Three.js, every object (including meshes and cameras) inherits
from Object3D. When you add one Object3D as a
child of another, the child enters the local coordinate system of the
parent.
By default, a camera is added directly to the Scene.
However, if you add the PerspectiveCamera as a child of a
moving Mesh, any translation or rotation applied to the
mesh automatically applies to the camera.
Step-by-Step Implementation
1. Create the Mesh and the Camera
First, instantiate your moving mesh and the perspective camera.
import * as THREE from 'three';
// Create the scene
const scene = new THREE.Scene();
// Create the target mesh (e.g., a car or player character)
const geometry = new THREE.BoxGeometry(2, 1, 4);
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
const playerMesh = new THREE.Mesh(geometry, material);
scene.add(playerMesh);
// Create the PerspectiveCamera
const camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
);2. Parent the Camera to the Mesh
Instead of adding the camera to the scene, add it
directly to the playerMesh.
// Add the camera as a child of the mesh
playerMesh.add(camera);3. Position the Camera in Local Space
Because the camera is now a child of the mesh, its
position property defines its offset relative to the
mesh’s center, rather than the center of the world.
To place the camera behind and slightly above the mesh to create a classic third-person tracking perspective:
// Position the camera 5 units behind (Z) and 3 units up (Y) relative to the mesh
camera.position.set(0, 3, -5);
// Point the camera to look at the center of its parent mesh
camera.lookAt(playerMesh.position);Note: Because the camera’s local coordinate system is now
relative to the parent, camera.lookAt(0, 0, 0) also works
to point the camera directly at the center of the parent mesh.
4. Move the Mesh in the Animation Loop
In your render loop, apply movement or rotation to the mesh. The camera will automatically track with it without any additional camera updates.
const renderer = new THREE.WebGLRenderer();
document.body.appendChild(renderer.domElement);
function animate() {
requestAnimationFrame(animate);
// Move the mesh forward along its local Z-axis
playerMesh.translateZ(0.1);
// Rotate the mesh to see the camera follow the turn
playerMesh.rotation.y += 0.01;
renderer.render(scene, camera);
}
animate();Key Considerations
- Rotational Inertia: Because the camera is a hard-parented child, any sudden rotation of the mesh will result in an instantaneous, rigid camera turn. For a physics-based, lagged, or smoothed tracking shot, you would instead need to manually calculate lerped (linearly interpolated) coordinates in the animation loop rather than parenting the camera directly.
- Scale Inheritance: If you scale your parent mesh,
the camera’s local space will scale as well, which can distort the
camera’s aspect ratio and field of view. Keep the parent mesh’s scale at
(1, 1, 1)and scale the geometry instead if you encounter rendering distortions.