Kevin De Baerdemaeker

WebGL

Modified 2025-12-05

WebGL provides a bridge between javascript and the GPU using a the GLSL (OpenGL Shading Language). Here's a cheatsheet.

Rendering Pipeline

  1. The vertices holds the data points. These data points get converted by
  2. The vertex shader into locations on the screen.
  3. The primitive assembly converts the points on the screen to points, lines, or triangles. The primitives build into a model.
  4. The rasterization step creates pixels for the primitives, so the
  5. fragment shader creates colors for every point.
  6. The frame buffer is responsible for displaying it on the screen

Shaders & GLSL

Vertex Shaders

       Y = +1 (top)
                   ^
                   |
                   |
  X = -1 <---------+---------> X = +1
                   |
                   |
                   v
       Y = -1 (bottom)

Buffers & Attributes

Create a buffer and put data in them.

const buf = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buf);
gl.bufferData(gl.ARRAY_BUFFER, someData, gl.STATIC_DRAW);
const colorLocation = gl.getAttribLocation(program, "a_color");

On initialization time, look up the location of the attribute.

const colorLocation = gl.getAttribLocation(program, "a_color");

On render time, tell WebGL how to pull data out from the buffers and into the attributes.

gl.enableVertexAttribArray(colorLoc);
gl.vertexAttribPointer(colorLoc, 4, gl.UNSIGNED_BYTE, true, 0, 0);

Now it's available in the shader.

attribute vec4 a_position;
 
void main() {
   gl_Position = a_position;
}

Uniforms

Uniforms are values passed to the shader that stay the same for all vertices in a draw call. For example, screen offsets. Two shader programs are completely different environments, not shared.

Look up the location of the uniform at initialization time.

offsetLoc = gl.getUniformLocation(someProgram, "u_offset");

Then setting the uniform.

gl.uniform4fv(offsetLoc, [1, 0, 0, 0]); 

And then use it in the shader.

attribute vec4 a_position;
uniform vec4 u_offset;
 
void main() {
   gl_Position = a_position + u_offset;
}

Look up the location of the uniform at initialization time/

Fragment Shader

Varyings

Pass data from the vertex shader.

attribute vec4 a_position;
uniform vec4 u_offset;
varying vec4 v_positionWithOffset;
 
void main() {
  gl_Position = a_position + u_offset;
  v_positionWithOffset = a_position + u_offset;
}

To the fragment shader directly.

precision mediump float;
varying vec4 v_positionWithOffset;
 
void main() {
  vec4 color = v_positionWithOffset * 0.5 + 0.5;
  gl_FragColor = color;
}

Textures

Textures are passed to the shader via a sampler2D uniform, and use the GLSL texture2D function to extract a value out of it.

Create the texture and put data in it.

const tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);

var data = new Uint8Array([
   255, 0, 0, 255,   // a red pixel
   0, 255, 0, 255,   // a green pixel
]);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 2, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, data);

Set the texture's filtering.

gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);

At init time, look up the location in the shader program.

const someSamplerLoc = gl.getUniformLocation(someProgram, "u_texture");

Bind the texture to a texture unit, and tell the shader which unit you bound it to.

const unit = 5;
gl.activeTexture(gl.TEXTURE0 + unit);
gl.bindTexture(gl.TEXTURE_2D, tex);
  
gl.uniform1i(someSamplerLoc, unit);

References


Backlinks