Time for Action: Rendering Modes

Let's revisit the signature of the drawElements function:

gl.drawElements(mode, count, type, offset)

The first parameter determines the type of primitives that we are rendering. In the following section, we will see the different rendering modes with examples.

Follow the given steps:

  1. Open the ch02_04_rendering-modes.html file in your browser. This example follows the same structure as in the previous section.
  2. Open ch02_04_rendering-modes.html in your editor and scroll down to the initBuffers function:
function initBuffers() {
const vertices = [
-0.5, -0.5, 0,
-0.25, 0.5, 0,
0.0, -0.5, 0,
0.25, 0.5, 0,
0.5, -0.5, 0
];

indices = [0, 1, 2, 0, 2, 3, 2, 3, 4];

// Create VAO
trapezoidVAO = gl.createVertexArray();

// Bind VAO
gl.bindVertexArray(trapezoidVAO);

const trapezoidVertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, trapezoidVertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices),
gl.STATIC_DRAW);
// Provide instructions to VAO
gl.vertexAttribPointer(program.aVertexPosition, 3, gl.FLOAT,
false, 0, 0);
gl.enableVertexAttribArray(program.aVertexPosition);

trapezoidIndexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, trapezoidIndexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices),
gl.STATIC_DRAW);

// Clean
gl.bindVertexArray(null);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
}
  1. Here, you will see that we are drawing a trapezoid. However, on screen, you will see two triangles! Later, we'll see how this happened.
  2. At the top of the page, there is a settings controller that allows you to select the different rendering modes that WebGL provides:

let gl,
canvas,
program,
indices,
trapezoidVAO,
trapezoidIndexBuffer,
// Global variable that captures the current rendering mode type
renderingMode = 'TRIANGLES';
  1. When you select any option from the settings, you are changing the value of the renderingMode variable defined at the top of the code (scroll up if you want to see where it is defined). The code that sets up the settings controller is inside the initControls function. We will cover this functionality later.
  2. To see how each option modifies the rendering, scroll to the draw function:
function draw() {
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);

// Bind VAO
gl.bindVertexArray(trapezoidVAO);

gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, trapezoidIndexBuffer);

// Depending on the rendering mode type, we will draw differently
switch (renderingMode) {
case 'TRIANGLES': {
indices = [0, 1, 2, 2, 3, 4];
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new
Uint16Array(indices), gl.STATIC_DRAW);
gl.drawElements(gl.TRIANGLES, indices.length,
gl.UNSIGNED_SHORT,
0);
break;
}
case 'LINES': {
indices = [1, 3, 0, 4, 1, 2, 2, 3];
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new
Uint16Array(indices), gl.STATIC_DRAW);
gl.drawElements(gl.LINES, indices.length, gl.UNSIGNED_SHORT,
0);
break;
}
case 'POINTS': {
indices = [1, 2, 3];
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new
Uint16Array(indices), gl.STATIC_DRAW);
gl.drawElements(gl.POINTS, indices.length, gl.UNSIGNED_SHORT,
0);
break;
}
case 'LINE_LOOP': {
indices = [2, 3, 4, 1, 0];
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new
Uint16Array(indices), gl.STATIC_DRAW);
gl.drawElements(gl.LINE_LOOP, indices.length,
gl.UNSIGNED_SHORT, 0);
break;
}
case 'LINE_STRIP': {
indices = [2, 3, 4, 1, 0];
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new
Uint16Array(indices), gl.STATIC_DRAW);
gl.drawElements(gl.LINE_STRIP, indices.length,
gl.UNSIGNED_SHORT, 0);
break;
}
case 'TRIANGLE_STRIP': {
indices = [0, 1, 2, 3, 4];
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new
Uint16Array(indices), gl.STATIC_DRAW);
gl.drawElements(gl.TRIANGLE_STRIP, indices.length,
gl.UNSIGNED_SHORT, 0);
break;
}
case 'TRIANGLE_FAN': {
indices = [0, 1, 2, 3, 4];
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new
Uint16Array(indices), gl.STATIC_DRAW);
gl.drawElements(gl.TRIANGLE_FAN, indices.length,
gl.UNSIGNED_SHORT, 0);
break;
}
}

// Clean
gl.bindVertexArray(null);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
}
  1. You will see that after binding the IBO trapezoidIndexBuffer with the following instruction:
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, trapezoidIndexBuffer);
  1. You also have a switch statement where there is some code that executes, depending on the value of the renderingMode variable.
  2. For each mode, we define the contents of the JavaScript array indices. Then, we pass this array to the currently-bound buffer, trapezoidIndexBuffer, by using the bufferData function. Finally, we call the drawElements function.
  3. Let's see what each mode does:
Mode Description
TRIANGLES

When you use the TRIANGLES mode, WebGL will use the first three indices defined in your IBO to construct the first triangle, the next three to construct the second triangle, and so on.

In this example, we are drawing two triangles, which can be verified by examining the JavaScript indices array that populates the IBO: indices = [0, 1, 2, 2, 3, 4];.

LINES

The LINES mode will instruct WebGL to take each consecutive pair of indices defined in the IBO and draw lines by taking the coordinates of the corresponding vertices.

For instance, indices = [1, 3, 0, 4, 1, 2, 2, 3]; will draw four lines: from vertex number 1 to vertex number 3, from vertex number 0 to vertex number 4, from vertex number 1 to vertex number 2, and from vertex number 2 to vertex number 3.

POINTS

When we use the POINTS mode, WebGL will not generate surfaces. Instead, it will render the vertices that we had defined using the index array.

In this example, we will only render vertices number 12, and 3 with indices = [1, 2, 3];.

LINE_LOOP

LINE_LOOP draws a closed loop connecting the vertices defined in the IBO to the next one.

In our case, it will be indices = [2, 3, 4, 1, 0];.

LINE_STRIP

LINE_STRIP is similar to LINE_LOOP. The difference is that WebGL does not connect the last vertex to the first one (not a closed loop).

The indices JavaScript array will be indices = [2, 3, 4, 1, 0];.

TRIANGLE_STRIP

TRIANGLE_STRIP draws connected triangles. Every vertex is specified after the first three.

In our example, vertices number 0, number 1, and number 2 create a new triangle. If we have indices = [0, 1, 2, 3, 4];, then we will generate the triangles (0, 1, 2)(1, 2, 3), and (2, 3, 4).

TRIANGLE_FAN

TRIANGLE_FAN creates triangles in a similar way to TRIANGLE_STRIP. However, the first vertex defined in the IBO is taken as the origin of the fan (the only shared vertex among consecutive triangles).

In our example, indices = [0, 1, 2, 3, 4]; will create the triangles (0, 1, 2) and (0, 3, 4).

  1. The following diagram can be useful in visualizing these various rendering modes. That being said, it's easiest to see these modes in action by changing the setting's drop-down values and seeing the various results:

  1. Let's make some changes by editing ch02_04_rendering-modes.html so that when you select the TRIANGLES option, you render the trapezoid instead of two triangles.
Hint

You need one extra triangle in the indices array.
  1. Save the file and test it in your browser.
  2. Edit the web page so that you draw the letter M using the LINES option.
Hint

You need to define four lines in the indices array.
  1. Just like before, save your changes and test them in your browser.
  2. Using the LINE_LOOP mode, draw only the boundary of the trapezoid.

What just happened?

This simple exercise helped us see the different rendering modes supported by WebGL. These different modes determine how to interpret vertex and index data to render an object.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.137.161.222