- Drawing Multiple Points
- Hello Triangle
- Moving, Rotating, and Scaling
- Summary
Hello Triangle
Now that you’ve learned the basic techniques to pass multiple vertex coordinates to a vertex shader, let’s try to draw other shapes using multiple vertex coordinates. This section uses a sample program HelloTriangle, which draws a single 2D triangle. Figure 3.12 shows a screenshot of HelloTriangle.
Figure 3.12 HelloTriangle
Sample Program (HelloTriangle.js)
Listing 3.3 shows HelloTriangle.js, which is almost identical to MultiPoint.js used in the previous section with two critical differences.
Listing 3.3 HelloTriangle.js
1 // HelloTriangle.js 2 // Vertex shader program 3 var VSHADER_SOURCE = 4 'attribute vec4 a_Position;\n' + 5 'void main() {\n' + 6 ' gl_Position = a_Position;\n' + 7 '}\n'; 8 9 // Fragment shader program 10 var FSHADER_SOURCE = 11 'void main() {\n' + 12 ' gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n' + 13 '}\n'; 14 15 function main() { ... 19 // Get the rendering context for WebGL 20 var gl = getWebGLContext(canvas); ... 26 // Initialize shaders 27 if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) { ... 30 } 31 32 // Set the positions of vertices 33 var n = initVertexBuffers(gl); ... 39 // Set the color for clearing <canvas> ... 45 // Draw a triangle 46 gl.drawArrays (gl.TRIANGLES, 0, n); 47 } 48 49 function initVertexBuffers(gl) { 50 var vertices = new Float32Array([ 51 0.0, 0.5, -0.5, -0.5, 0.5, -0.5 52 ]); 53 var n = 3; // The number of vertices ... 78 return n; 79 }
The two differences from MultiPoint.js are
- The line to specify the size of a point gl_PointSize = 10.0; has been removed from the vertex shader. This line only has an effect when you are drawing a point.
- The first parameter of gl.drawArrays() has been changed from gl.POINTS to gl.TRIANGLES at line 46.
The first parameter, mode, of gl.drawArrays() is powerful and provides the ability to draw various shapes. Let’s take a look.
Basic Shapes
By changing the argument we use for the first parameter, mode, of gl.drawArrays(), we can change the meaning of line 46 into “execute the vertex shader three times (n is 3), and draw a triangle using the three vertices in the buffer, starting from the first vertex coordinate”:
46 gl.drawArrays(gl.TRIANGLES, 0, n);
In this case, the three vertices in the buffer object are no longer individual points, but become three vertices of a triangle.
The WebGL method gl.drawArrays() is both powerful and flexible, allowing you to specify seven different types of basic shapes as the first argument. These are explained in more detail in Table 3.3. Note that v0, v1, v2 ... indicates the vertices specified in a buffer object. The order of vertices affects the drawing of the shape.
The shapes in the table are the only ones that WebGL can draw directly, but they are the basics needed to construct complex 3D graphics. (Remember the frog at the start of this chapter.)
Table 3.3 Basic Shapes Available in WebGL
Basic Shape |
Mode |
Description |
Points |
gl.POINTS |
A series of points. The points are drawn at v0, v1, v2 ... |
Line segments |
gl.LINES |
A series of unconnected line segments. The individual lines are drawn between vertices given by (v0, v1), (v2, v3), (v4, v5)... If the number of vertices is odd, the last one is ignored. |
Line strips |
gl.LINE_STRIP |
A series of connected line segments. The line segments are drawn between vertices given by (v0, v1), (v1, v2), (v2, v3), ... The first vertex becomes the start point of the first line, the second vertex becomes the end point of the first line and the start point of the second line, and so on. The i-th (i> 1) vertex becomes the start point of the i-th line and the end point of the i-1-th line. (The last vertex becomes the end point of the last line.) |
Line loops |
gl.LINE_LOOP |
A series of connected line segments. In addition to the lines drawn by gl.LINE_STRIP, the line between the last vertex and the first vertex is drawn. The line segments drawn are (v0, v1), (v1, v2), ..., and (v n, v0). v n is the last vertex. |
Triangles |
gl.TRIANGLES |
A series of separate triangles. The triangles given by vertices (v0, v1, v2), (v3, v4, v5), ... are drawn. If the number of vertices is not a multiple of 3, the remaining vertices are ignored. |
Triangle strips |
gl.TRIANGLE_STRIP |
A series of connected triangles in strip fashion. The first three vertices form the first triangle and the second triangle is formed from the next vertex and one of the sides of the first triangle. The triangles are drawn given by (v0, v1, v2), (v2, v1, v3), (v2, v3, v4) ... (Pay attention to the order of vertices.) |
Triangle fans |
gl.TRIANGLE_FAN |
A series of connected triangles sharing the first vertex in fanlike fashion. The first three vertices form the first triangle and the second triangle is formed from the next vertex, one of the sides of the first triangle, and the first vertex. The triangles are drawn given by (v0, v1, v2), (v0, v2, v3), (v0, v3, v4), ... |
Figure 3.13 shows these basic shapes.
Figure 3.13 Basic shapes available in WebGL
As you can see from the figure, WebGL can draw only three types of shapes: a point, a line, and a triangle. However, as explained at the beginning of this chapter, spheres to cubes to 3D monsters to humanoid characters in a game can be constructed from small triangles. Therefore, you can use these basic shapes to draw anything.
Experimenting with the Sample Program
To examine what will happen when using gl.LINES, gl.LINE_STRIP, and gl.LINE_LOOP, let’s change the first argument of gl.drawArrays() as shown next. The name of each sample program is HelloTriangle_LINES, HelloTriangle_LINE_STRIP, and HelloTriangle_LINE_LOOP, respectively:
46 gl.drawArrays (gl.LINES, 0, n); 46 gl.drawArrays (gl.LINE_STRIP, 0, n); 46 gl.drawArrays (gl.LINE_LOOP, 0, n);
Figure 3.14 shows a screenshot of each program.
Figure 3.14 gl.LINES, gl.LINE_STRIP, and gl.LINE_LOOP
As you can see, gl.LINES draws a line using the first two vertices and does not use the last vertex, whereas gl.LINE_STRIP draws two lines using the first three vertices. Finally, gl.LINE_LOOP draws the lines in the same manner as gl.LINE_STRIP but then “loops” between the last vertex and the first vertex and makes a triangle.
Hello Rectangle (HelloQuad)
Let’s use this basic way of drawing triangles to draw a rectangle. The name of the sample program is HelloQuad, and Figure 3.15 shows a screenshot when it’s loaded into your browser.
Figure 3.16 shows the vertices of the rectangle. Of course, the number of vertices is four because it is a rectangle. As explained in the previous section, WebGL cannot draw a rectangle directly, so you need to divide the rectangle into two triangles (v0, v1, v2) and (v2, v1, v3) and then draw each one using gl.TRIANGLES, gl.TRIANGLE_STRIP, or gl.TRIANGLE_FAN. In this example, you’ll use gl.TRIANGLE_STRIP because it only requires you to specify four vertices. If you were to use gl.TRIANGLES, you would need to specify a total of six.
Figure 3.15 HelloQuad
Figure 3.16 The four vertex coordinates of the rectangle
Basing the example on HelloTriangle.js, you need to add an extra vertex coordinate at line 50. Pay attention to the order of vertices; otherwise, the draw command will not execute correctly:
50 var vertices = new Float32Array([ 51 -0.5, 0.5, -0.5, -0.5, 0.5, 0.5, 0.5, -0.5 52 ]);
Because you’ve added a fourth vertex, you need to change the number of vertices from 3 to 4 at line 53:
53 var n = 4; // The number of vertices
Then, by modifying line 46 as follows, your program will draw a rectangle in the browser:
46 gl.drawArrays(gl.TRIANGLE_STRIP, 0, n);
Experimenting with the Sample Program
Now that you have a feel for how to use gl.TRIANGLE_STRIP, let’s change the first parameter of gl.drawArrays() to gl.TRIANGLE_FAN. The name of the sample program is HelloQuad_FAN:
46 gl.drawArrays(gl.TRIANGLE_FAN, 0, n);
Figure 3.17 show a screenshot of HelloQuad_FAN. In this case, we can see the ribbon-like shape on the screen.
Figure 3.17 HelloQuad_FAN
Looking at the order of vertices and the triangles drawn by gl.TRIANGLE_FAN shown on the right side of Figure 3.17, you can see why the result became a ribbon-like shape. Essentially, gl.TRIANGLE_FAN causes WebGL to draw a second triangle that shares the first vertex (v0), and this second triangle overlaps the first, creating the ribbon-like effect.