Glossary

WebGL

WebGL stands for Web Graphics Library, a JavaScript API that draws GPU-accelerated 2D and 3D graphics in a canvas element without plug-ins. WebGL 1.0 exposes the OpenGL ES 2.0 feature set and WebGL 2.0 exposes OpenGL ES 3.0. The Khronos Group publishes the specification, and Apple, Google, Microsoft and Mozilla are members of its WebGL Working Group. You get a context from a canvas with the context identifier webgl or webgl2.

How it works

WebGL is a low-level, shader-based API. You do not describe a scene. You upload data to GPU buffers and write small programs in GLSL (the OpenGL Shading Language) that the GPU runs.

  • Context: canvas.getContext("webgl") returns a WebGLRenderingContext, and canvas.getContext("webgl2") returns a WebGL2RenderingContext. It returns null if the identifier is unsupported or the canvas already has a different context type.
  • Vertex shader: runs once per vertex and sets gl_Position.
  • Fragment shader: runs once per fragment, roughly each covered pixel, and sets the color, gl_FragColor in WebGL 1.
  • Pipeline: drawArrays or drawElements sends buffered vertices through both shaders and rasterizes the result into the drawing buffer.
  • State: the context is a large state machine. Calls such as bindBuffer and useProgram change what the next draw call uses.

The example below compiles both shaders, draws one triangle that covers the whole 4 by 4 pixel surface, and reads the first pixel back. It ran in Node.js with the gl package, a headless WebGL 1.0 implementation, so the version string differs from a browser's. In a browser you would create the context with canvas.getContext("webgl") instead.

const gl = require('gl')(4, 4);
const vs = `attribute vec2 p; void main() { gl_Position = vec4(p, 0.0, 1.0); }`;
const fs = `precision mediump float; void main() { gl_FragColor = vec4(1.0, 0.5, 0.0, 1.0); }`;
function shader(type, src) {
  const s = gl.createShader(type);
  gl.shaderSource(s, src);
  gl.compileShader(s);
  return s;
}
const prog = gl.createProgram();
gl.attachShader(prog, shader(gl.VERTEX_SHADER, vs));
gl.attachShader(prog, shader(gl.FRAGMENT_SHADER, fs));
gl.linkProgram(prog);
gl.useProgram(prog);
const buf = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buf);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, -1, 3, -1, -1, 3]), gl.STATIC_DRAW);
const loc = gl.getAttribLocation(prog, 'p');
gl.enableVertexAttribArray(loc);
gl.vertexAttribPointer(loc, 2, gl.FLOAT, false, 0, 0);
gl.drawArrays(gl.TRIANGLES, 0, 3);
const px = new Uint8Array(4);
gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, px);
console.log(gl.getParameter(gl.VERSION));
console.log(Array.from(px));
console.log(gl.getError() === gl.NO_ERROR);
// WebGL 1.0 stack-gl 8.1.6
// [ 255, 128, 0, 255 ]
// true

What is the difference between WebGL and WebGL 2?

WebGL 2 is based on OpenGL ES 3.0 and WebGL 1 on OpenGL ES 2.0. WebGL 2 adds 3D textures, sampler objects, uniform buffer objects, sync objects, query objects and transform feedback objects. It also makes vertex array objects, instancing, multiple render targets and fragment depth part of the core API, where WebGL 1 needed extensions. Request it with getContext("webgl2") and fall back to "webgl" when that returns null.

Common pitfalls

  • Assuming a context is always returned: getContext gives null when WebGL is unavailable, and the user's device must also have hardware that supports it. Check the result before calling any method on it.
  • Silent shader failures: a bad shader does not throw. With the gl package, the example's fragment shader minus its last semicolon returned false from getShaderParameter(shader, gl.COMPILE_STATUS) and ERROR: 0:2: '}' : syntax error from getShaderInfoLog. Log wording and line numbers vary by implementation. Check both after every compile.
  • Calling getError or getParameter every frame: MDN's best-practices guide says these cause synchronous stalls on the calling thread, sometimes longer than 1 ms. Check errors during development, not in the render loop.
  • Ignoring context loss: the browser can report that the drawing buffer is lost and fires webglcontextlost on the canvas. Handle the event instead of assuming the canvas keeps drawing.
  • Switching context types on one canvas: once a canvas has handed out a 2D context, asking for webgl returns null. Use a separate canvas element.
  • Using the old identifier only: experimental-webgl was used by early or not yet conformant implementations. Request webgl and webgl2.

Related terms

  • Canvas — the element that hosts a WebGL context, and the 2D API that WebGL is the alternative to.
  • DOM — the canvas is a DOM element, and its events include webglcontextlost.
  • sRGB — the standard RGB color space; WebGL offers the EXT_sRGB extension for sRGB-encoded textures.

See also

  • Term: Canvas — the 2D drawing API on the same element.