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.

Revisions

  1. mbostock revised this gist Feb 9, 2016. 1 changed file with 1 addition and 0 deletions.
    1 change: 1 addition & 0 deletions .block
    Original file line number Diff line number Diff line change
    @@ -0,0 +1 @@
    license: gpl-3.0
  2. mbostock revised this gist Apr 23, 2013. 1 changed file with 9 additions and 21 deletions.
    30 changes: 9 additions & 21 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -5,26 +5,22 @@

    attribute vec2 a_position;

    uniform mat3 u_matrix;

    void main(void) {
    gl_Position = vec4((u_matrix * vec3(a_position, 1)).xy, 0, 1);
    gl_Position = vec4(a_position, 0.0, 1.0);
    }

    </script>
    <script id="fragment-shader" type="x-shader/x-fragment">

    void main(void) {
    gl_FragColor = vec4(0, 1, 0, 1);
    gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);
    }

    </script>
    <script>

    // Select the canvas from the document and extract its dimensions.
    var canvas = document.querySelector("canvas"),
    width = +canvas.getAttribute("width"),
    height = +canvas.getAttribute("height");
    // Select the canvas from the document.
    var canvas = document.querySelector("canvas");

    // Create the WebGL context, with fallback for experimental support.
    var context = canvas.getContext("webgl")
    @@ -50,22 +46,14 @@
    if (!context.getProgramParameter(program, context.LINK_STATUS)) throw new Error(context.getProgramInfoLog(program));
    context.useProgram(program);

    // Define the matrix transformation from normalized [±1,±1] to screen coordinates.
    var matrixUniform = context.getUniformLocation(program, "u_matrix");
    context.uniformMatrix3fv(matrixUniform, false, [
    2 / width, 0, 0,
    0, -2 / height, 0,
    -1, 1, 1
    ]);

    // Define the positions (as vec2) of the square that covers the canvas.
    // Define the positions (as vec2, in normalized coordinates) of the square that covers the canvas.
    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
    -1.0, -1.0,
    +1.0, -1.0,
    +1.0, +1.0,
    -1.0, +1.0
    ]), context.STATIC_DRAW);

    // Bind the position buffer to the position attribute.
  3. mbostock revised this gist Apr 23, 2013. 1 changed file with 2 additions and 0 deletions.
    2 changes: 2 additions & 0 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,5 @@
    Every introductory WebGL tutorial I could find uses utility libraries (*e.g.*, [Sylvester](http://sylvester.jcoglan.com/)) 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 vanilla Hello World with no dependencies and no branching. Enjoy.

    Next: [Part II](/mbostock/5445238)
  4. mbostock revised this gist Apr 23, 2013. 1 changed file with 5 additions and 1 deletion.
    6 changes: 5 additions & 1 deletion index.html
    Original file line number Diff line number Diff line change
    @@ -52,7 +52,11 @@

    // Define the matrix transformation from normalized [±1,±1] to screen coordinates.
    var matrixUniform = context.getUniformLocation(program, "u_matrix");
    context.uniformMatrix3fv(matrixUniform, false, [2 / width, 0, 0, 0, -2 / height, 0, -1, 1, 1]);
    context.uniformMatrix3fv(matrixUniform, false, [
    2 / width, 0, 0,
    0, -2 / height, 0,
    -1, 1, 1
    ]);

    // Define the positions (as vec2) of the square that covers the canvas.
    var positionBuffer = context.createBuffer();
  5. mbostock revised this gist Apr 23, 2013. 1 changed file with 0 additions and 0 deletions.
    Binary file added thumbnail.png
    Loading
    Sorry, something went wrong. Reload?
    Sorry, we cannot display this file.
    Sorry, this file is invalid so it cannot be displayed.
  6. mbostock revised this gist Apr 23, 2013. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion README.md
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,3 @@
    Every introductory WebGL tutorial I could find uses utility libraries (*e.g.*, [Sylvester](http://sylvester.jcoglan.com/)) 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.
    So here’s a vanilla Hello World with no dependencies and no branching. Enjoy.
  7. mbostock revised this gist Apr 23, 2013. 1 changed file with 35 additions and 20 deletions.
    55 changes: 35 additions & 20 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -1,13 +1,6 @@
    <!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;
    @@ -18,43 +11,65 @@
    gl_Position = vec4((u_matrix * vec3(a_position, 1)).xy, 0, 1);
    }

    </script>
    <script id="fragment-shader" type="x-shader/x-fragment">

    void main(void) {
    gl_FragColor = vec4(0, 1, 0, 1);
    }

    </script>
    <script>

    // Select the canvas from the document and extract its dimensions.
    var canvas = document.querySelector("canvas"),
    width = +canvas.getAttribute("width"),
    height = +canvas.getAttribute("height"),
    context = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
    height = +canvas.getAttribute("height");

    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));
    // Create the WebGL context, with fallback for experimental support.
    var context = canvas.getContext("webgl")
    || canvas.getContext("experimental-webgl");

    // Compile the vertex shader.
    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));

    // Compile the fragment shader.
    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));

    // Link and use the program.
    var program = context.createProgram();
    context.attachShader(program, fragmentShader);
    context.attachShader(program, vertexShader);
    context.attachShader(program, fragmentShader);
    context.linkProgram(program);
    if (!context.getProgramParameter(program, context.LINK_STATUS)) throw new Error(context.getProgramInfoLog(program));

    context.useProgram(program);

    // Define the matrix transformation from normalized [±1,±1] to screen coordinates.
    var matrixUniform = context.getUniformLocation(program, "u_matrix");
    context.uniformMatrix3fv(matrixUniform, false, [2 / width, 0, 0, 0, -2 / height, 0, -1, 1, 1]);

    // Define the positions (as vec2) of the square that covers the canvas.
    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);

    context.bufferData(context.ARRAY_BUFFER, new Float32Array([
    0, 0,
    width, 0,
    width, height,
    0, height
    ]), context.STATIC_DRAW);

    // Bind the position buffer to the position attribute.
    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]);

    // Draw the square!
    context.drawArrays(context.TRIANGLE_FAN, 0, 4);

    </script>
  8. mbostock revised this gist Apr 23, 2013. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -44,8 +44,8 @@

    context.useProgram(program);

    var vertexBuffer = context.createBuffer();
    context.bindBuffer(context.ARRAY_BUFFER, vertexBuffer);
    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");
  9. mbostock revised this gist Apr 23, 2013. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,3 @@
    All the introductory tutorials to WebGL I could find use utility libraries in efforts to make the hello-world examples easier to understand. I find this has the opposite effect, because it stymies my desire is to learn WebGL by forcing me to learn the utility library first; a tutorial shouldn’t encapsulate the thing I want to learn behind a library! So here’s a simple Hello World in vanilla WebGL with no dependencies and linear control flow.
    Every introductory WebGL tutorial I could find uses utility libraries (*e.g.*, [Sylvester](http://sylvester.jcoglan.com/)) 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…

    (It’s even more frustrating when live examples accompanying tutorials use *minified* JavaScript… What’s up with that?)
    So here’s a simple Hello World in vanilla WebGL with no dependencies and linear control flow. Enjoy.
  10. mbostock revised this gist Apr 23, 2013. 1 changed file with 3 additions and 1 deletion.
    4 changes: 3 additions & 1 deletion README.md
    Original file line number Diff line number Diff line change
    @@ -1 +1,3 @@
    All the introductory tutorials to WebGL I could find use utility libraries in efforts to make the hello-world examples easier to understand. I find this has the opposite effect, because my desire is to understand the WebGL interface itself, not the utility library’s interface; a tutorial shouldn’t encapsulate and abstract away the thing I want to learn! (It’s even more frustrating when the live examples accompanying the tutorial use *minified* JavaScript. What gives?) So here’s a simple Hello World in vanilla WebGL with no dependencies and linear control flow.
    All the introductory tutorials to WebGL I could find use utility libraries in efforts to make the hello-world examples easier to understand. I find this has the opposite effect, because it stymies my desire is to learn WebGL by forcing me to learn the utility library first; a tutorial shouldn’t encapsulate the thing I want to learn behind a library! So here’s a simple Hello World in vanilla WebGL with no dependencies and linear control flow.

    (It’s even more frustrating when live examples accompanying tutorials use *minified* JavaScript… What’s up with that?)
  11. mbostock revised this gist Apr 23, 2013. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion README.md
    Original file line number Diff line number Diff line change
    @@ -1 +1 @@
    All the introductory tutorials to WebGL I could find use utility libraries in efforts to make the hello-world examples easier to understand. I find this has the opposite effect, because my desire is to understand the WebGL interface itself, not abstracted away by a utility library. (It’s even more frustrating when the live examples accompanying the tutorial use *minified* JavaScript. What gives?) So here’s a simple Hello World in vanilla WebGL with no dependencies and linear control flow.
    All the introductory tutorials to WebGL I could find use utility libraries in efforts to make the hello-world examples easier to understand. I find this has the opposite effect, because my desire is to understand the WebGL interface itself, not the utility library’s interface; a tutorial shouldn’t encapsulate and abstract away the thing I want to learn! (It’s even more frustrating when the live examples accompanying the tutorial use *minified* JavaScript. What gives?) So here’s a simple Hello World in vanilla WebGL with no dependencies and linear control flow.
  12. mbostock created this gist Apr 23, 2013.
    1 change: 1 addition & 0 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1 @@
    All the introductory tutorials to WebGL I could find use utility libraries in efforts to make the hello-world examples easier to understand. I find this has the opposite effect, because my desire is to understand the WebGL interface itself, not abstracted away by a utility library. (It’s even more frustrating when the live examples accompanying the tutorial use *minified* JavaScript. What gives?) So here’s a simple Hello World in vanilla WebGL with no dependencies and linear control flow.
    60 changes: 60 additions & 0 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,60 @@
    <!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 vertexBuffer = context.createBuffer();
    context.bindBuffer(context.ARRAY_BUFFER, vertexBuffer);
    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>