user128511
user128511

Reputation:

How do you resize a canvas without flicker?

Many of the Three.js samples flicker when the window is resized or have a white border for a frame. For example: http://threejs.org/examples/webgl_animation_skinning.html

On the other hand the WebGL Aquarium does not flicker. How is this done?

Upvotes: 1

Views: 3732

Answers (3)

user128511
user128511

Reputation:

AFAICT most of the Three.JS samples set the size of the canvas manually by looking at the window size or a container's size and then setting canvas.width, canvas.height to match.

The TDL samples including the WebGL Aquarium on the other hand use CSS to let the browser scale the canvas and then update the size of the canvas backingstore in the requestAnimationFrame callback.

Here's an example

const gl = document.querySelector("#c").getContext("webgl");

function render() {
  resizeCanvasToDisplaySize(gl.canvas);

  gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
  
  // Draw a 2 pixel border around the edge using
  // the scissor test since it's easier than setting up
  // a lot of stuff
  gl.clearColor(1, 0, 0, 1);  // red
  gl.disable(gl.SCISSOR_TEST);
  gl.clear(gl.COLOR_BUFFER_BIT);

  gl.enable(gl.SCISSOR_TEST);
  gl.scissor(2, 2, gl.canvas.width - 4, gl.canvas.height - 4);
  gl.clearColor(0, 0, 1, 1);  // blue
  gl.clear(gl.COLOR_BUFFER_BIT);

  requestAnimationFrame(render);
}
requestAnimationFrame(render);

function resizeCanvasToDisplaySize(canvas) {
  const width  = canvas.clientWidth;
  const height = canvas.clientHeight;
  if (canvas.width !== width || canvas.height !== height) {
    canvas.width  = width;
    canvas.height = height;
  }
}
body {
  margin: 0;
}
#c {
  width: 100vw;
  height: 100vh;
  display: block;
}
<canvas id="c"></canvas>

or a fiddle http://jsfiddle.net/greggman/pfWS3/

Upvotes: 0

A.J.Bauer
A.J.Bauer

Reputation: 3001

function onWindowResize() {

        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();

        renderer.setSize(window.innerWidth, window.innerHeight);
        renderer.render(scene, camera);
    }

Upvotes: 3

moka
moka

Reputation: 23045

You need to call render straight away after resizing window size.

Even better you can have requestAnimationFrame and do resize and then render in one function call. It will make sure that reflow and render happens straight away in one reflow, rather separate that leads to flickering.

Upvotes: 2

Related Questions