WebGL Canvas
Introduction
WebGL lets JavaScript talk to the GPU through an HTML <canvas>. If you have worked through some of the OpenGL tutorials, a lot of the ideas will feel familiar: clear colours, viewports, depth buffers, shaders and buffers are all still there. The browser just gives us a different way to get at them.
What are we actually doing?
The canvas itself is just an area on the page. Calling canvas.getContext("webgl2") asks the browser to give us a WebGL rendering context for that canvas. If WebGL 2 is unavailable, we try webgl instead. If both calls fail, we stop there rather than trying to call methods on a missing context.
For this first tutorial we are deliberately keeping the rendering boring: a nice blue clear colour and a depth buffer. That gives us a clean, modern starting point before we pile shaders and geometry on top of it.
The HTML
Our page only needs a canvas and a JavaScript file:
<canvas id="webgl-canvas" width="500" height="500">
Your browser does not support the HTML canvas element.
</canvas>
<script src="webgl-canvas.js"></script>
The JavaScript
We keep the rendering code in a separate file instead of stuffing a big script directly into the HTML. It is easier to read, easier to debug and much easier to reuse as the tutorials grow.
let gl = null;
let canvas = null;
function resizeCanvasToDisplaySize() {
const pixelRatio = window.devicePixelRatio || 1;
const displayWidth = Math.round(canvas.clientWidth * pixelRatio);
const displayHeight = Math.round(canvas.clientHeight * pixelRatio);
if (canvas.width !== displayWidth || canvas.height !== displayHeight) {
canvas.width = displayWidth;
canvas.height = displayHeight;
}
}
function initWebGL() {
canvas = document.getElementById("webgl-canvas");
gl = canvas.getContext("webgl2") || canvas.getContext("webgl");
if (!gl) {
canvas.insertAdjacentHTML(
"afterend",
"<p>WebGL could not be initialised in this browser/device.</p>"
);
return false;
}
gl.clearColor(0.4, 0.6, 0.9, 1.0);
gl.clearDepth(1.0);
gl.enable(gl.DEPTH_TEST);
gl.depthFunc(gl.LEQUAL);
return true;
}
function displayWebGL() {
resizeCanvasToDisplaySize();
gl.viewport(0, 0, canvas.width, canvas.height);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
}
function main() {
if (!initWebGL()) return;
displayWebGL();
}
window.addEventListener("DOMContentLoaded", main);
Why resize the drawing buffer?
A canvas has a CSS display size and a drawing-buffer size. On a high-DPI screen those are not necessarily the same thing. Matching the drawing buffer to the displayed size (including the device pixel ratio) avoids a blurry canvas and also means our viewport uses the real number of pixels we are drawing into.
Where do we go from here?
At this point we have a real WebGL context, sensible error handling, a correctly sized viewport and a frame that clears cleanly. The next interesting step is shaders and buffers — that is where the page stops being a blue rectangle and starts behaving like a graphics tutorial 🙂
Source & downloads
Questions or corrections? If something doesn’t work or you spot something I’ve got wrong, leave a comment below. These tutorials have been around a long time, so useful corrections are always welcome!
Found this sit while looking for webgl. +1 for more tutorials, from em as well.
Nice! I just heard about this, and saw it on your website while looking up an OpenGL thing. WebGL is completely awesome. Using this, the web will probably look completely different in a year! (different in a good way!)
Please make more tutorials!