How to Configure Three.js WebGLRenderer for Screenshots
This article explains how to configure the Three.js
WebGLRenderer using the preserveDrawingBuffer
property so users can successfully capture and download screenshots of a
3D canvas. By default, WebGL clears the drawing buffer after presenting
the render, resulting in blank or black images when attempting to save
the canvas. Setting this property to true resolves this issue, allowing
for seamless image generation.
Why Three.js Screenshots Fail by Default
When you attempt to capture a screenshot of a standard Three.js
canvas using canvas.toDataURL(), you will often get a
completely blank or black image.
To optimize performance and save GPU memory, the WebGL context automatically clears its drawing buffer immediately after rendering the frame to the screen. By the time your JavaScript code attempts to read the canvas data, the buffer is already empty.
Enabling preserveDrawingBuffer
To prevent the browser from clearing the drawing buffer, you must
explicitly set the preserveDrawingBuffer option to
true when initializing your WebGLRenderer.
Here is how to configure the renderer:
import * as THREE from 'three';
// Create the renderer with preserveDrawingBuffer enabled
const renderer = new THREE.WebGLRenderer({
canvas: document.querySelector('#myCanvas'),
preserveDrawingBuffer: true
});
renderer.setSize(window.innerWidth, window.innerHeight);By enabling this setting, the browser retains the rendered pixels in the buffer, making them accessible to standard browser APIs at any time.
How to Capture and Download the Screenshot
Once the renderer is configured, you can extract the image data from
the canvas element using renderer.domElement.toDataURL()
and trigger a download.
function takeScreenshot() {
// 1. Force a render pass right before capturing to ensure the latest frame is captured
renderer.render(scene, camera);
// 2. Get the data URL from the canvas
const dataURL = renderer.domElement.toDataURL('image/png');
// 3. Create a temporary link element to trigger the download
const link = document.createElement('a');
link.download = 'threejs-screenshot.png';
link.href = dataURL;
// 4. Programmatically click the link to trigger the download dialog
link.click();
}
// Example: Trigger screenshot on button click
document.getElementById('screenshotButton').addEventListener('click', takeScreenshot);Performance Consideration
While setting preserveDrawingBuffer: true is the easiest
way to enable screenshots, it does come with a minor performance cost.
Because the browser cannot discard the drawing buffer after rendering,
it requires more GPU memory and can slightly decrease frame rates on
mobile or lower-end devices.
If absolute peak performance is critical for your application, keep
preserveDrawingBuffer: false and instead call your
screenshot capture logic inside the same execution frame as your
renderer.render() call, immediately after the render
function executes.