1 ex01-standalone

ex01-standalone.html executes the following WebgGL2 library calls:

  • Shader program setup
    • Create and compile a vertex shader and check for errors
      1. Shader#1 = gl.createShader(gl.VERTEX_SHADER)
      2. gl.shaderSource(Shader#1, str)
      3. gl.compileShader(Shader#1)
      4. gl.getShaderParameter(Shader#1, gl.COMPILE_STATUS)
    • Create and compile a fragment shader and check for errors
      1. Shader#2 = gl.createShader(gl.FRAGMENT_SHADER)
      2. gl.shaderSource(Shader#2, str)
      3. gl.compileShader(Shader#2)
      4. gl.getShaderParameter(Shader#2, gl.COMPILE_STATUS)
    • Create a shader program, link the two shaders together, and check for errors
      1. Program#1 = gl.createProgram()
      2. gl.attachShader(Program#1, Shader#1)
      3. gl.attachShader(Program#1, Shader#2)
      4. gl.linkProgram(Program#1)
      5. gl.getProgramParameter(Program#1, gl.LINK_STATUS)
  • Draw (called once only)
    1. gl.clear(gl.COLOR_BUFFER_BIT)

      Normally we’d expect the depth buffer too, but this file doesn’t use depth ​​15. gl.useProgram(Program#1)

    2. gl.drawArrays(gl.TRIANGLES, 0, 6)

      Note that we haven’t provided any attributes. There will be no in variables supplied to the vertex shader, so it will have to compute its own positions based on gl_VertexID instead.

2 ex04-motion

ex04-motion.html executes the following WebgGL2 library calls:

  • Shader program setup (see ex01-standalone for comments)
    1. Shader#1 = gl.createShader(gl.VERTEX_SHADER)
    2. gl.shaderSource(Shader#1, str)
    3. gl.compileShader(Shader#1)
    4. gl.getShaderParameter(Shader#1, gl.COMPILE_STATUS)
    5. Shader#2 = gl.createShader(gl.FRAGMENT_SHADER)
    6. gl.shaderSource(Shader#2, str)
    7. gl.compileShader(Shader#2)
    8. gl.getShaderParameter(Shader#2, gl.COMPILE_STATUS)
    9. Program#1 = gl.createProgram()
    10. gl.attachShader(Program#1, Shader#1)
    11. gl.attachShader(Program#1, Shader#2)
    12. gl.linkProgram(Program#1)
    13. gl.getProgramParameter(Program#1, gl.LINK_STATUS)
  • Geometry setup
    • Set up a VAO to stores the various buffer bindings (but not buffer content, that’s in GPU memory) for retrieval during drawing
      1. VertexArray#1 = gl.createVertexArray()
      2. gl.bindVertexArray(VertexArray#1)
    • Send data to the position attribute and enable it
      1. Buffer#1 = gl.createBuffer()

        Acts like a pointer to an array in GPU memory. Initially like a null pointer as we’ve not pointed it to anything.

      2. gl.bindBuffer(gl.ARRAY_BUFFER, Buffer#1)

        The gl.ARRAY_BUFFER is like an input port to which we can send attribute data. We’re specifying that data arriving through that port should end up pointed to by Buffer#1.

      3. gl.bufferData(gl.ARRAY_BUFFER, Float32Array[8], gl.STATIC_DRAW)

        And here we send in data, optimized for rare updates and frequent draws. Buffer#1 is now no longer a null pointer, instead pointing to a 24-byte blob in GPU memory.

        The Float32Array type is a JavaScript-specific type and is lost in transit to the GPU, which only gets a blob of bytes. The GPU learns to parse them as floats on line 21.

      4. Attrib#1 = gl.getAttribLocation(Program#1, "position")

        This is just an integer. If we’d used layout(location = 0) in vec4 position in the GLSL we could just use 0 directly instead of needing this call. Using explicit layout locations is preferable in code that has more than one shader program.

      5. gl.vertexAttribPointer(Attrib#1, 2, gl.FLOAT, false, 0, 0)

        The 2 means 2 floats per attribute; coupled with the 8-element array on line 19, that means 4 total vertices. We also have to tell the GPU how to parse bytes into numbers, which is what gl.FLOAT and the arguments after it do.

      6. gl.enableVertexAttribArray(Attrib#1)

        It may seem strange that after picking an attribute and giving it data we also have to enable it. Having this separate enabling step allows a few special-case tricks we won’t cover in this class.

    • Send data to the color attribute and enable it
      1. Buffer#2 = gl.createBuffer()

      2. gl.bindBuffer(gl.ARRAY_BUFFER, Buffer#2)

      3. gl.bufferData(gl.ARRAY_BUFFER, Float32Array[16], gl.STATIC_DRAW)

      4. Attrib#2 = gl.getAttribLocation(Program#1, "color")

      5. gl.vertexAttribPointer(Attrib#2, 4, gl.FLOAT, false, 0, 0)

        The 4 means 4 floats per attribute; couples with the 16-element array on line 25, that means 4 total vertices

      6. gl.enableVertexAttribArray(Attrib#2)

    • Send data to the element array, identifying which vertices are connected into primitives nad how
      1. Buffer#3 = gl.createBuffer()

      2. gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, Buffer#3)

      3. gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, Uint16Array[9], gl.STATIC_DRAW)

        Note the 9-entry index buffer, which is provided without saying how many vertices are used per primitive. We need to specify that per drawElements call, as we see in step 37 below.

  • Draw (called repeatedly)
    1. gl.clear(gl.COLOR_BUFFER_BIT)

      No depth buffer bit because this is a 2D animation

    2. gl.useProgram(Program#1)

      Because we only have one shader program, we could have done this once during setup. But generally we’ll have several shader programs so it’s good practice to specify which one we want every frame.

    3. Program#1seconds = gl.getUniformLocation(Program#1, "seconds")

      Note uniform locations are specific to a shader program, but don’t change over the course of the program. We could have done this in the setup instead and remembered the return value for slightly faster operation.

    4. gl.uniform1f(Program#1seconds, num)

    5. gl.bindVertexArray(VertexArray#1)

      Because we only have one VAO and already bound it during setup, we could remove this call. But generally we’ll have several VAO programs so it’s good practice to specify which one we want every frame.

    6. gl.drawElements(gl.TRIANGLES, 9, gl.UNSIGNED_SHORT, 0)

      A lot is going on here.

      Because we say drawElements, it’s going to look inside the currently-bound ELEMENT_ARRAY_BUFFER to find indices to connect into primitives; we bound that most recently in step 36: the VAO includes re-binding the ELEMENT_ARRAY_BUFFER it had during setup.

      Inside that buffer it will consider 3 indices at a time (that’s what gl.TRIANGLES means). It will look at at most 9 total indices, meaning 3 triangles get drawn.

      As part of the draw, vertices are sent through the vertex shader of the currently bound program. Which vertices to send is determined by the indices stored inside the ELEMENT_ARRAY_BUFFER. The attributes for each are pulled from the currently enabled attribute arrays (lines 22 and 28), which are also re-enabled with the VAO (line 36).

      Like line 21, we also have to indicate how to parse the buffer’s bytes into numbers.

3 5-scripted.html

5-scripted.html executes the following WebgGL2 library calls:

  • Shader program setup (see ex01-standalone for comments)
    1. Shader#1 = gl.createShader(gl.VERTEX_SHADER)
    2. gl.shaderSource(Shader#1, str)
    3. gl.compileShader(Shader#1)
    4. gl.getShaderParameter(Shader#1, gl.COMPILE_STATUS)
    5. Shader#2 = gl.createShader(gl.FRAGMENT_SHADER)
    6. gl.shaderSource(Shader#2, str)
    7. gl.compileShader(Shader#2)
    8. gl.getShaderParameter(Shader#2, gl.COMPILE_STATUS)
    9. Program#1 = gl.createProgram()
    10. gl.attachShader(Program#1, Shader#1)
    11. gl.attachShader(Program#1, Shader#2)
    12. gl.linkProgram(Program#1)
    13. gl.getProgramParameter(Program#1, gl.LINK_STATUS)
  • Render settings setup
    1. gl.enable(gl.DEPTH_TEST)
  • Geometry setup (see ex04-motion for comments)
    1. VertexArray#1 = gl.createVertexArray()
    2. gl.bindVertexArray(VertexArray#1)
    3. Buffer#1 = gl.createBuffer()
    4. gl.bindBuffer(gl.ARRAY_BUFFER, Buffer#1)
    5. gl.bufferData(gl.ARRAY_BUFFER, Float32Array[21], gl.STATIC_DRAW)
    6. gl.getAttribLocation(Program#1, "position")
    7. gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0)
    8. gl.enableVertexAttribArray(0)
    9. Buffer#2 = gl.createBuffer()
    10. gl.bindBuffer(gl.ARRAY_BUFFER, Buffer#2)
    11. gl.bufferData(gl.ARRAY_BUFFER, Float32Array[21], gl.STATIC_DRAW)
    12. gl.getAttribLocation(Program#1, "vcolor")
    13. gl.vertexAttribPointer(1, 3, gl.FLOAT, false, 0, 0)
    14. gl.enableVertexAttribArray(1)
    15. Buffer#3 = gl.createBuffer()
    16. gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, Buffer#3)
    17. gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, Uint16Array[12], gl.STATIC_DRAW)
  • Render settings setup
    1. gl.viewport(num, num, num, num)
  • Draw
    • Set up this frame
      1. gl.clearColor(num, num, num, num)

      2. gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)

      3. gl.useProgram(Program#1)

      4. gl.bindVertexArray(VertexArray#1)

      5. gl.getUniformLocation(Program#1, "color")

        This is in the code, but there’s no uniform of this name so it returns null. We should probably remove this.

      6. gl.uniform4fv(null, Float32Array[4])

        This tries to send data to a non-existant uniform, an error we should remove.

    • Draw first copy of tetrahedron, and also complete general setup of projection matrix:
      1. Program#1mv = gl.getUniformLocation(Program#1, "mv")
      2. gl.uniformMatrix4fv(Program#1mv, false, Float32Array[16])
      3. Program#1p = gl.getUniformLocation(Program#1, "p")
      4. gl.uniformMatrix4fv(Program#1p, false, Float32Array[16])
      5. gl.drawElements(gl.TRIANGLES, 12, gl.UNSIGNED_SHORT, 0)
    • Draw second copy of tetrahedron:
      1. Program#1mv = gl.getUniformLocation(Program#1, "mv")
      2. gl.uniformMatrix4fv(Program#1mv, false, Float32Array[16])
      3. gl.drawElements(gl.TRIANGLES, 12, gl.UNSIGNED_SHORT, 0)
    • Draw third copy of tetrahedron:
      1. Program#1mv = gl.getUniformLocation(Program#1, "mv")
      2. gl.uniformMatrix4fv(Program#1mv, false, Float32Array[16])
      3. gl.drawElements(gl.TRIANGLES, 12, gl.UNSIGNED_SHORT, 0)

4 6-skinning

6-skinning.html executes the following WebgGL2 library calls:

  • Shader program setup (see ex01-standalone for comments)
    1. Shader#1 = gl.createShader(gl.VERTEX_SHADER)
    2. gl.shaderSource(Shader#1, str)
    3. gl.compileShader(Shader#1)
    4. gl.getShaderParameter(Shader#1, gl.COMPILE_STATUS)
    5. Shader#2 = gl.createShader(gl.FRAGMENT_SHADER)
    6. gl.shaderSource(Shader#2, str)
    7. gl.compileShader(Shader#2)
    8. gl.getShaderParameter(Shader#2, gl.COMPILE_STATUS)
    9. Program#1 = gl.createProgram()
    10. gl.attachShader(Program#1, Shader#1)
    11. gl.attachShader(Program#1, Shader#2)
    12. gl.linkProgram(Program#1)
    13. gl.getProgramParameter(Program#1, gl.LINK_STATUS)
  • Render settings setup
    1. gl.enable(gl.DEPTH_TEST)
  • Geometry setup (see ex04-motion for comments)
    1. VertexArray#1 = gl.createVertexArray()
    2. gl.bindVertexArray(VertexArray#1)
    3. Buffer#1 = gl.createBuffer()
    4. gl.bindBuffer(gl.ARRAY_BUFFER, Buffer#1)
    5. gl.bufferData(gl.ARRAY_BUFFER, Float32Array[6012], gl.STATIC_DRAW)
    6. gl.getAttribLocation(Program#1, "position")
    7. gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0)
    8. gl.enableVertexAttribArray(0)
    9. Buffer#2 = gl.createBuffer()
    10. gl.bindBuffer(gl.ARRAY_BUFFER, Buffer#2)
    11. gl.bufferData(gl.ARRAY_BUFFER, Float32Array[6012], gl.STATIC_DRAW)
    12. gl.getAttribLocation(Program#1, "color")
    13. gl.vertexAttribPointer(1, 3, gl.FLOAT, false, 0, 0)
    14. gl.enableVertexAttribArray(1)
    15. Buffer#3 = gl.createBuffer()
    16. gl.bindBuffer(gl.ARRAY_BUFFER, Buffer#3)
    17. gl.bufferData(gl.ARRAY_BUFFER, Float32Array[6012], gl.STATIC_DRAW)
    18. gl.getAttribLocation(Program#1, "weight")
    19. gl.vertexAttribPointer(2, 3, gl.FLOAT, false, 0, 0)
    20. gl.enableVertexAttribArray(2)
    21. Buffer#4 = gl.createBuffer()
    22. gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, Buffer#4)
    23. gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, Uint16Array[11880], gl.STATIC_DRAW)
  • Render settings setup
    1. gl.viewport(num, num, num, num)
  • Draw
    1. gl.clearColor(num, num, num, num)
    2. gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
    3. gl.useProgram(Program#1)
    4. gl.bindVertexArray(VertexArray#1)
    5. gl.getUniformLocation(Program#1, "color")
    6. gl.uniform4fv(null, Float32Array[4])
    7. Program#1T = gl.getUniformLocation(Program#1, "T")
    8. gl.uniformMatrix4fv(Program#1T, false, Float32Array[16])
    9. Program#1C = gl.getUniformLocation(Program#1, "C")
    10. gl.uniformMatrix4fv(Program#1C, false, Float32Array[16])
    11. Program#1F = gl.getUniformLocation(Program#1, "F")
    12. gl.uniformMatrix4fv(Program#1F, false, Float32Array[16])
    13. Program#1p = gl.getUniformLocation(Program#1, "p")
    14. gl.uniformMatrix4fv(Program#1p, false, Float32Array[16])
    15. gl.drawElements(gl.TRIANGLES, 11880, gl.UNSIGNED_SHORT, 0)