Skip to content

Instantly share code, notes, and snippets.

@mbostock
Last active February 26, 2023 06:42
Show Gist options
  • Select an option

  • Save mbostock/5440492 to your computer and use it in GitHub Desktop.

Select an option

Save mbostock/5440492 to your computer and use it in GitHub Desktop.
Hello WebGL

Every introductory WebGL tutorial I could find uses utility libraries (e.g., Sylvester) in efforts to make the examples easier to understand. While encapsulating common patterns is desirable when writing production code, I find this practice highly counterproductive to learning because it forces me to learn the utility library first (another layer of abstraction) before I can understand the underlying standard. Even worse when accompanying examples use minified JavaScript…

So here’s a simple Hello World in vanilla WebGL with no dependencies and linear control flow. Enjoy.

<!DOCTYPE html>
<meta charset="utf-8">
<canvas width="960" height="500"></canvas>
<script id="fragment-shader" type="x-shader/x-fragment">
void main(void) {
gl_FragColor = vec4(0, 1, 0, 1);
}
</script>
<script id="vertex-shader" type="x-shader/x-vertex">
attribute vec2 a_position;
uniform mat3 u_matrix;
void main(void) {
gl_Position = vec4((u_matrix * vec3(a_position, 1)).xy, 0, 1);
}
</script>
<script>
var canvas = document.querySelector("canvas"),
width = +canvas.getAttribute("width"),
height = +canvas.getAttribute("height"),
context = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
var fragmentShader = context.createShader(context.FRAGMENT_SHADER);
context.shaderSource(fragmentShader, document.querySelector("#fragment-shader").textContent);
context.compileShader(fragmentShader);
if (!context.getShaderParameter(fragmentShader, context.COMPILE_STATUS)) throw new Error(context.getShaderInfoLog(fragmentShader));
var vertexShader = context.createShader(context.VERTEX_SHADER);
context.shaderSource(vertexShader, document.querySelector("#vertex-shader").textContent);
context.compileShader(vertexShader);
if (!context.getShaderParameter(vertexShader, context.COMPILE_STATUS)) throw new Error(context.getShaderInfoLog(vertexShader));
var program = context.createProgram();
context.attachShader(program, fragmentShader);
context.attachShader(program, vertexShader);
context.linkProgram(program);
if (!context.getProgramParameter(program, context.LINK_STATUS)) throw new Error(context.getProgramInfoLog(program));
context.useProgram(program);
var positionBuffer = context.createBuffer();
context.bindBuffer(context.ARRAY_BUFFER, positionBuffer);
context.bufferData(context.ARRAY_BUFFER, new Float32Array([0, 0, width, 0, width, height, 0, height]), context.STATIC_DRAW);
var positionAttribute = context.getAttribLocation(program, "a_position");
context.enableVertexAttribArray(positionAttribute);
context.vertexAttribPointer(positionAttribute, 2, context.FLOAT, false, 0, 0);
var matrixUniform = context.getUniformLocation(program, "u_matrix");
context.uniformMatrix3fv(matrixUniform, false, [2 / width, 0, 0, 0, -2 / height, 0, -1, 1, 1]);
context.drawArrays(context.TRIANGLE_FAN, 0, 4);
</script>
@ddnn55
Copy link

ddnn55 commented Jun 13, 2018

🙏

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment