Limit Three.js Pixel Ratio for Retina Performance
This article explains how to optimize Three.js application
performance on high-DPI (Retina) screens by capping the device pixel
ratio. You will learn why rendering at native high-resolution pixel
ratios causes performance bottlenecks and how to use the
renderer.setPixelRatio method with a mathematical cap to
achieve the perfect balance between visual crispness and smooth frame
rates.
The Problem with High-DPI Screens
Devices with Retina or high-DPI displays (like modern MacBooks,
iPhones, and high-end Android devices) often have device pixel ratios
(DPR) of 3 or higher. If you pass
window.devicePixelRatio directly to Three.js, the renderer
scales the canvas resolution accordingly:
// This can cause severe performance lag on 3x screens
renderer.setPixelRatio(window.devicePixelRatio);On a 3x screen, a full-screen canvas requires rendering nine times as many pixels as a standard 1x screen. This exponentially increases the workload on the GPU’s fragment shaders, leading to low frame rates, device overheating, and rapid battery drain.
The Solution: Capping the Pixel Ratio
To balance quality and performance, you should limit the maximum
pixel ratio to 2. To the human eye, the visual difference
between a pixel ratio of 2 and 3 on a mobile
or laptop screen is almost imperceptible, but the performance saving is
massive.
Use Math.min() to cap the value passed to
renderer.setPixelRatio() at 2:
// Cap the pixel ratio at a maximum of 2
const pixelRatio = Math.min(window.devicePixelRatio, 2);
renderer.setPixelRatio(pixelRatio);Implementing in a Basic Setup
Here is how to apply this logic when initializing your Three.js renderer:
import * as THREE from 'three';
const canvas = document.querySelector('canvas.webgl');
// Create the renderer
const renderer = new THREE.WebGLRenderer({
canvas: canvas,
antialias: true
});
// Set size
renderer.setSize(window.innerWidth, window.innerHeight);
// Set capped pixel ratio
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));Handling Window Resizing
Users may drag their browser windows between standard screens and high-DPI external monitors. To ensure your application adapts dynamically without degrading performance, apply the same pixel ratio limit inside your window resize event listener:
window.addEventListener('resize', () => {
// Update camera aspect ratio
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
// Update renderer size
renderer.setSize(window.innerWidth, window.innerHeight);
// Update and cap pixel ratio on resize
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
});By capping the pixel ratio at 2, you ensure that your
Three.js experiences remain fluid and performant across all modern
devices without sacrificing visual quality.