Does three.js automatically update the WebGLRenderer drawing buffer when devicePixelRatio changes, or must the app re-apply setPixelRatio and setSize?
0 reputation · 12 Sept 2021, 11:30 UTC
0 reputation · 12 Sept 2021, 11:30 UTC
When a browser window moves between displays with different devicePixelRatio values, a three.js canvas can render at the wrong resolution if the renderer's drawing buffer is not updated. The goal is to clarify whether WebGLRenderer detects the display change and recomputes its backing store automatically, or whether the application must detect the change and re-apply the pixel ratio and size itself.
WebGLRenderer caches the pixel ratio supplied to setPixelRatio and only recomputes the drawing buffer inside setSize or setPixelRatio, without subscribing to resolution media-query changes. Because this behavior is version-sensitive and can differ across renderer back ends, the exact boundary between automatic and manual handling remains unclear.
Does the current stable WebGLRenderer update the drawing buffer on its own after a devicePixelRatio change, or must the application call setPixelRatio and setSize again? If manual updates are required, which change event provides the most reliable trigger across browsers, and should the pixel ratio be clamped before re-applying it?
35275 reputation · 12 Sept 2021, 17:55 UTC
Three.js does not automatically update the WebGL drawing buffer when the devicePixelRatio changes. You must manually detect the change and re-apply both setPixelRatio and setSize to ensure the rendering remains crisp.
The WebGLRenderer caches the pixel ratio provided to setPixelRatio. It only recomputes the internal drawing buffer (the backing store) when setSize or setPixelRatio is explicitly called. Because it does not subscribe to browser-level media query changes or window movements between displays with different scaling factors (e.g., moving from a standard monitor to a 4K laptop display), the canvas will often appear blurry or incorrectly scaled unless the application triggers a manual update.
To handle these transitions reliably, follow these steps:
resize event for layout changes. However, for DPR-only changes (like moving between screens), use a matchMedia listener on window.devicePixelRatio.const mediaQuery = window.matchMedia(`(device-pixel-ratio: ${window.devicePixelRatio})dppx)`);
function onResize() {
const dpr = Math.min(window.devicePixelRatio, 2);
renderer.setPixelRatio(dpr);
renderer.setSize(window.innerWidth, window.innerHeight);
}
window.addEventListener('resize', onResize);
mediaQuery.addEventListener('change', onResize);
// Initial call
onResize();
This explanation assumes you are using the standard WebGLRenderer. While the behavior of caching the pixel ratio is consistent across stable versions, the exact way browsers report a devicePixelRatio change during window dragging can vary slightly between OS and browser combinations. Using matchMedia is the most robust cross-browser method to catch these specific shifts without polling the value in the animation loop.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.