🌐

WebGL

CategoryPlatforms

Overview

WebGL (Web Graphics Library)

WebGL is a JavaScript API for rendering real-time 3D and 2D graphics in a web browser.

WebGL rendering is done inside an HTML canvas.

A WebGL program is made of JavaScript code and GLSL shader code executed on a GPU.

GLSL

GLSL (Graphics Library Shader Language)

Shader languages used by OpenGL and OpenGL ES to write vertex and fragment functions executed on a GPU.

Support

WebGL 1.0

https://caniuse.com/#feat=webgl

WebGL 2.0

https://caniuse.com/#feat=webgl2

Loading

When running a local HTML file (file:///), loading files from the file system will fail with a security exception.

This is caused by the same origin policy security restrictions in the browsers.

http://en.wikipedia.org/wiki/Same_origin_policy

There are several solutions:

Browser

Windows

chrome.exe --allow-file-access-from-files

macOS

"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" --allow-file-access-from-files

Local web server

NPM

The easiest way to run a local web server is to install Node.js using the npm package manager.

npm install http-server -g

Then run http-server in a local directory.

http-server . -p 8000

Chrome

An alternative is to install a browser extension that hosts a local web server.

https://chrome.google.com/webstore/detail/web-server-for-chrome/ofhbbkphhbklhfoeikjpcbhemlocgigb

Shaders

Clip Space

In OpenGL ES, the clip space for the Z axis is in the range [-1, 1].

Attributes

Attributes are vertex data provided as input to the vertex shader function.

vec4 attributes default to [0, 0, 0, 1], which is a valid zero positions (w is set to 1).

A position attribute passed as a vec2 or vec3 will still be a valid position.

However, normals must ensure that w is set to 0.

Varyings

Varyings are variables that are declared by the vertex shader and used to pass interpolated data from the vertex shader to the fragment shader.

Uniforms

Uniforms are variables set by the JavaScript code and are available to both the vertex and fragment shaders.

Data Types

Vertex Shader

The responsibility of the vertex shader is to transform input vertices.

gl_Position is a special variable that must be set by the vertex shader with the transformed vertex position.

Fragment Shader

The responsibility of the fragment shader is to determine the color of the pixels.

gl_FragColor is a special variable that must be set by the fragment shader with the pixel's color.

Memory

Hardware memory needs to be released explicitly.

Tutorial

Initialization

Create an empty HTML page with an empty body tag.

<!DOCTYPE html>
<html>
    <body>
    </body>
</html>

Add a canvas tag inside the body tag with a an ID.

Add an empty script tag for the JavaScript code.

<!DOCTYPE html>
<html>
    <body>
        <canvas id="canvas"></canvas>
        <script>
				</script>
    </body>
</html>

In the script tag, initialize WebGL by getting the canvas from its ID in the document using getElementById(id). Alternatively, look up the canvas with querySelector(selectors).

const canvas = document.getElementById("canvas");

Get the drawing context for WebGL from the canvas by calling the getContext(contextType) function with the "webgl" or "experimental-webgl" identifier.

https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/getContext

const gl = canvas.getContext("webgl");

Validate that the drawing context implements the WebGLRenderingContext interface for WebGL 1.0.

if (!gl || !(gl instanceof WebGLRenderingContext)) {
  alert("Unable to initialize WebGL.");
  return;
}

After the WebGL initialization, we define a custom function, that registers itself as a callback with WebGL to render the next frame.

To render the following frame, the callback function calls requestAnimationFrame(callback) on the window with a reference to itself to setup a render loop.

function render() {
	requestAnimationFrame(render);
}

requestAnimationFrame(render);

Shader

The shader code can be written directly in JavaScript code as a string literal.

The back-tick character (`) can be used to write multiline string literals.

WebGLProgram represents a shader program made of a vertex and a fragment shader function.

WebGLShader represents a vertex or a fragment shader function.

Create a shader function

For both the vertex shader and fragment shader sources, we create a corresponding shader function.

Create a shader program

Get the location of shader attributes

The input data for the vertex function is stored in attributes. The location of attributes in a shader program is represents as an int number.

The constant data for the vertex and fragment functions is stored in uniforms. The location of a uniform variable in a shader program is represented by WebGLUniformLocation.

Buffers

A memory buffer on the GPU is represented by WebGLBuffer.

A buffer can store vertices, indices, textures and other data.

Create a vertex buffer

Create an index buffer

Render the scene

Before rendering a scene, we resize the canvas if necessary

To render a scene, we set the render states and draw the primitives.

Whether an index buffer is set in the render states, primitives are drawn using a different function.

Draw primitives

Draw indexed primitives

Validation

To check if the browser supports WebGL, create a canvas and try to obtain a drawing context with the getContext function.

https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/getContext

isWebGLAvailable: function () {
  var canvas = document.createElement("canvas");
	var gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
  return (gl && gl instanceof WebGLRenderingContext);
}
isWebGL2Available: function () {
  var canvas = document.createElement("canvas");
	var gl = canvas.getContext("webgl2");
  return (gl && gl instanceof WebGLRenderingContext);
}

Reference

Best Practices

Resources

Rendering