Indexed Geometry

In which you learn how all of computer graphics pivots around the triangle and extend your tools for rendering points to this new geometric primitive.

Explicit Connectivity

In the hello-triangles application, the scheme used to group vertices into triangles is implicit. The GPU connects vertices together based only their sequence in the VBOs. Sometimes you want more explicit control over how vertices connect together.

Consider this square:

function initialize() {
  const positions = [
    // Triangle 0
    0, 0, 0,
    1, 0, 0,
    1, 1, 0,

    // Triangle 1
    0, 0, 0,
    1, 1, 0,
    0, 1, 0,
  ];

  attributes = new VertexAttributes();
  attributes.addAttribute('position', 6, 3, positions);

  // ...
}

function render() {
  // ...

  vao.drawSequence(gl.TRIANGLES);

  // ...
}

Draw it on paper so you understand its structure before reading on.

Because the rectangle is being drawn with gl.TRIANGLES, both triangles must include the shared vertices \(\begin{bmatrix}0&0&0\end{bmatrix}\) and \(\begin{bmatrix}1&1&0\end{bmatrix}\). This redundancy could be fixed by switching to a triangle fan. However, triangle fans support only a very particular form of connectivity in which the triangles radiate out from the central vertex.

A more general solution is to use indexed geometry. With indexed geometry, each vertex appears exactly once in the VBO. But you must explicitly list how these triangles connect together with an array of indices. Consider how the square changes when using indexed geometry:

function initialize() {
  const positions = [
    0, 0, 0, // Vertex 0
    1, 0, 0, // Vertex 1
    0, 1, 0, // Vertex 2
    1, 1, 0, // Vertex 3
  ];

  const indices = [
    0, 1, 3, // Triangle 0
    0, 3, 2, // Triangle 1
  ];

  attributes = new VertexAttributes();
  attributes.addAttribute('position', 4, 3, positions);
  attributes.addIndices(indices);

  // ...
}

Draw this square on paper again. Label each vertex with both its Cartesian coordinates and its index. Then observe how the indices of these vertices are listed in indices to form triangles.

To draw a shape whose triangles are specified by indices, you replace the drawSequence call with drawIndexed:

function render() {
  // ...

  vao.drawIndexed(gl.TRIANGLES);

  // ...
}

The addIndices and drawIndexed calls do no error checking. You are responsible for making sure your indices are valid.

Exercises

Draw a blocky T on paper. Label its vertices with both Cartesian coordinates and vertex indices. How would you fill the T with triangles?
Adapt your hello-triangles application to render your blocky T-shape using indexed geometry.