I want my webgl app viewport and canvas to react to browser window size changes (that includes F11 button). I.e. I want the canvas to be always 100% width and height and I want the viewport size and aspect ratio to be appropriate. The former I achieve with simple:
<canvas style="width: 100%; height:100%;">
although I'm not sure if that's the way to go. The latter I was trying to achieve with some information I found here: Webgl gl.viewport change but obviously I'm doing something wrong. I do realize:
canvas.onresize = resizeViewport;
is wrong as canvas's size doesn't change very often (it's always 100% width and height) but I don't know how I should do it.
Here's an online version of the app: http://nps.netarteria.pl/gallery.
Resizing the canvas on the fly is quite easy. To do it, simply set the width and height properties of the Canvas object, and then redraw the canvas contents: Canvas . width = 600 ; Canvas .
Resize it using CSS every time you resize with canvas. width, canvas. height the canvas is fully cleared. if you're building a drawing app you have probably defined a function to redraw the canvas every time a change is applied so use the same function to redraw the canvas after it changed.
I think this works:
var canvas;
var gl;
function render() {
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
// Draw a 1 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(1, 1, gl.canvas.width - 2, gl.canvas.height - 2);
gl.clearColor(0, 0, 1, 1); // blue
gl.clear(gl.COLOR_BUFFER_BIT);
};
function resizeCanvas() {
var width = canvas.clientWidth;
var height = canvas.clientHeight;
if (canvas.width != width ||
canvas.height != height) {
canvas.width = width;
canvas.height = height;
// in this case just render when the window is resized.
render();
}
}
function main() {
canvas = document.getElementById("c");
gl = canvas.getContext("webgl");
resizeCanvas();
}
window.addEventListener('resize', resizeCanvas);
main();
body {
margin: 0;
}
#c {
width: 100vw;
height: 100vh;
display: block;
}
<canvas id="c"></canvas>
As far as I know, resize only works on the window. The HTML5 spec has unfortunately not added resize events to other elements.
Note: If you are always rendering (like a game for example) then you don't need to listen for the resize event. Just call resizeCanvas at the beginning of your render loop. If the browser has resized the canvas, regardless of its container, the code will see the size no longer matches and update the size of the canvas's drawingbuffer.
The proper viewport size for rendering the the canvas is almost always:
// Set the viewport to be the size of the canvas's drawingBuffer.
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
Whereas if you are using a typical 3D math library, you also have a projection matrix and a function—usually called perspective
which takes a fieidOfView, aspect, zNear and zFar parameters. The correct aspect for nearly all WebGL programs is:
// Set the aspect of our perspective matrix to match the size
// the canvas is displayed at.
var aspect = gl.canvas.clientWidth / gl.canvas.clientHeight
???.perspective(fieldOfView, aspect, zNear, zFar);
Apparently you need to cache the clientWidth and clientHeight. The reason is setting canvas.width
will change the CSS layout which can change clientHeight
Updated the code above.
Switched from using 100%
to 100vw
and 100vw
as these are arguably more correct. They describe what you want which is to make the canvas the size of the viewport where as the previous solution made the canvas the size of the document and then tried for force the document to be the size of the window. Since the content of the document could potentially be larger than the window that was arguably the wrong solution.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With