Introduction to WebGL

What is WebGL?

  • A browser feature that lets you execute code on the GPU
  • The coolest thing to happen to the web since the GIF

GPUs are Parallel Processors

  • CPUs execute in serial, each instruction one after the other
  • GPUs execute in parallel, multitudes of instructions executed simultaneously

GPUs are Parallel Processors

  • Modern GPUs can offer ~5 trillion FLOPS!
  • Modern CPUs can offer ~100 billion FLOPS
  • GPUs are very well suited to certain types of problems but completely useless at others

GPUs are Parallel Processors

  • If your problem can be divided up into many independent but similar tasks, it'll run faster on a GPU
  • For example
    • Tracing the path of light as it bounces around a scene
    • Fluid physics simulation
    • Video processing

Are they only for graphics?

  • WebGL was designed for handling graphics but it can be coerced into general purpose computation
  • The upcoming WebCL, however, was designed for general purpose computation

Demos

WebGL Water - Evan Wallace
WebGL Fluid Simulation
Seascape - Alexander Alekseev
Hypercomplex - Alexander Alekseev

Getting Started

(* in brief)

  • Take a
    <canvas>
    element and grab a WebGL context
    var gl = canvas.getContext("webgl");

Getting Started

(* in brief)

  • Compile and upload your GPU code
    //gradient pixel shader glsl
    varying vec2 uv;
    void main(){
    	gl_FragColor = vec4(uv.x, uv.y, 0.0, 1.0);
    }
    var pixelShader = gl.createShader(gl.FRAGMENT_SHADER);
    gl.shaderSource(pixelShader, pixelShaderSrc);
    gl.compileShader(pixelShader);
    
    var program = gl.createProgram();
    gl.attachShader(program, geometryShader);
    gl.attachShader(program, pixelShader);
    gl.linkProgram(program);

Getting Started

(* in brief)

  • Upload geometry
    var vertices = [
    	 0.0,  1.0,
    	-1.0, -1.0,
    	 1.0, -1.0
    ];
    
    vertices.elementsPerVertex = 2;
    
    var vertexBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
    
    //tell the GPU about the format of the vertices
    var attribPositionLoc = gl.getAttribLocation(program, "position");
    gl.enableVertexAttribArray(attribPositionLoc);
    gl.vertexAttribPointer(attribPositionLoc, vertices.elementsPerVertex, gl.FLOAT, false, 0, 0);

Getting Started

(* in brief)

  • Draw!
    gl.drawArrays(gl.TRIANGLES, 0, vertices.length / vertices.elementsPerVertex);

Getting Started

(* in brief)

A little dull, let's add time into our GPU pixel shader
uniform float time;
uniform vec2 resolution;
varying vec2 uv;
void main(){
	vec3 col = vec3(0);
        float r = distance(uv, vec2(.5));
	col.r = pow(sin(time + r), 4.);
	col.g = cos(time + uv.y + r)*.5 + .5;
	col.b = sin(time * 2.0)*.5 + .5;
	gl_FragColor = vec4(col, 1.0);
}
edit me

Getting Started

(* in brief)

Getting Started

(* in brief)

  • We can transform the shape in the geometry shader
  • Rotation $$\begin{bmatrix} x^\prime\\y^\prime \end{bmatrix} = \begin{bmatrix} cos(\theta) & -sin(\theta) \\ sin(\theta) & cos(\theta) \end{bmatrix} \begin{bmatrix} x\\y \end{bmatrix}$$
  • Scale $$\begin{bmatrix} x^\prime\\y^\prime \end{bmatrix} = S \begin{bmatrix} x\\y \end{bmatrix}$$

Getting Started

(* in brief)

Rotating and scaling geometry in a shader
attribute vec2 position;
uniform float time;
uniform vec2 resolution;
varying vec2 uv;
void main(){
	vec2 p = position.xy;
	uv = (p + vec2(1.0))*.5; //converts from clip space to graph space
	mat2 transformationMatrix = mat2(
		cos(time), -sin(time),
		sin(time), cos(time)
	);
	float invAspect = resolution.y / resolution.x;
	vec2 scale = vec2(invAspect, 1.0) * .7;
	p = transformationMatrix * p * scale;
	gl_Position = vec4(p, 0.0, 1.0);
}
edit me

Getting Started

(* in brief)

That's The Basics

With WebGL you can

  • Draw triangles
  • Execute programs to color the pixels within the triangles
  • Execute programs to alter the geometry of the triangles
#define t iGlobalTime
#define r iResolution.xy
void mainImage( out vec4 fragColor, in vec2 fragCoord ){
	vec3 c;
	float l,z=t;
	for(int i=0;i<3;i++) {
		vec2 uv,p=fragCoord.xy/r;
		uv=p;
		p-=.5;
		p.x*=r.x/r.y;
		z+=.07;
		l=length(p);
		uv+=p/l*(sin(z)+1.)*abs(sin(l*9.-z*2.));
		c[i]=.01/length(abs(mod(uv,1.)-.5));
	}
	fragColor=vec4(c/l,t);
}
Creation - Silexars

3D in WebGL

  • Camera Projection Matrix
    $$\mathbf{P} = \begin{bmatrix} \frac{1}{\tan(\frac{1}{2} F_x)} & 0 & 0 & 0 \\ 0 & \frac{1}{\tan(\frac{1}{2} F_y)} & 0 & 0 \\ 0 & 0 & \frac{Z_f + Z_n}{Z_n - Z_f} & \frac{2 Z_f Z_n}{Z_n - Z_f} \\ 0 & 0 & -1 & 0 \end{bmatrix}$$
    $F = \text{field of view}$
    $Z_f = \text{maximum view distance}$
    $Z_n = \text{minimum view distance}$

3D in WebGL

  • Rotate Around Y
    $$\begin{bmatrix}x^\prime\\y^\prime\\z^\prime\end{bmatrix} = \begin{bmatrix} \cos(\theta) & 0 & sin(\theta) \\ 0 & 1 & 0 \\ -sin(\theta) & 0 & \cos(\theta) \end{bmatrix} \begin{bmatrix}x\\y\\z\end{bmatrix}$$
  • To go from 3D coordinates to 2D screen coordinates
    $$\mathbf{P} \mathbf{R}_y \vec{X}$$

3D in WebGL

More Triangles!

3D in WebGL

1 Cube = 445 lines of Javascript and GLSL

Use a library

Libraries make WebGL much easier to work with

3D

2D

Wrap Up

  • WebGL recently became supported in all major browser
  • Access to a parallel processor expands the limit of what's possible in a web application
  • Better to use libraries rather than raw WebGL

Questions?

Code for the slides and demos is on github

github.com/haxiomic

@haxiomic