How to Resize Three.js PerspectiveCamera
When building 3D applications with Three.js, handling browser window
resizing is crucial to prevent your scene from looking stretched or
squished. This article provides a quick, step-by-step guide on how to
dynamically calculate the correct aspect ratio for a
PerspectiveCamera and update the WebGLRenderer
whenever the user resizes their browser window.
The Problem with Window Resizing
A PerspectiveCamera relies on a fixed aspect ratio
(width divided by height) to project 3D coordinates onto a 2D screen. If
the browser window dimensions change and you do not update this ratio,
the rendered 3D scene will distort. To fix this, you must listen for the
window’s resize event, recalculate the aspect ratio, update
the camera’s projection matrix, and resize the renderer.
The Implementation Steps
To properly handle a window resize in Three.js, you need to implement a window event listener that performs three key actions:
- Recalculate the Aspect Ratio: Divide the new width
of the container (usually
window.innerWidth) by the new height (window.innerHeight). - Update the Projection Matrix: Assign the new aspect
ratio to the camera and call
camera.updateProjectionMatrix(). Three.js caches projection calculations, so this method is required to apply the changes. - Resize the Renderer: Update the size of the WebGL
canvas using
renderer.setSize()so that the output matches the new window dimensions.
Code Example
Here is the complete JavaScript code to implement this behavior:
// 1. Setup your standard Three.js variables (assumed to be initialized elsewhere)
const width = window.innerWidth;
const height = window.innerHeight;
const camera = new THREE.PerspectiveCamera(75, width / height, 0.1, 1000);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(width, height);
document.body.appendChild(renderer.domElement);
// 2. Create the resize event listener function
function onWindowResize() {
// Get the new dimensions of the window
const newWidth = window.innerWidth;
const newHeight = window.innerHeight;
// Update camera aspect ratio
camera.aspect = newWidth / newHeight;
// Recalculate the projection matrix
camera.updateProjectionMatrix();
// Update renderer size
renderer.setSize(newWidth, newHeight);
// Optional: Update device pixel ratio for High-DPI/Retina screens
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
}
// 3. Register the listener
window.addEventListener('resize', onWindowResize);Handling Custom Containers
If your Three.js canvas is inside a specific HTML
<div> rather than filling the entire window, replace
window.innerWidth and window.innerHeight with
the container’s client dimensions:
const container = document.getElementById('canvas-container');
function onContainerResize() {
const width = container.clientWidth;
const height = container.clientHeight;
camera.aspect = width / height;
camera.updateProjectionMatrix();
renderer.setSize(width, height);
}In this scenario, using a ResizeObserver on the
container element is often more reliable than listening to the window’s
resize event.