Drawing Triangles in 3D
You've seen how to draw points and lines and even how to draw some enclosed polygons with GL_LINE_LOOP. With just these primitives, you could easily draw any shape possible in three dimensions. You could, for example, draw six squares and arrange them so they form the sides of a cube.
You might have noticed, however, that any shapes you create with these primitives are not filled with any color; after all, you are drawing only lines. In fact, all that arranging six squares produces is a wireframe cube, not a solid cube. To draw a solid surface, you need more than just points and lines; you need polygons. A polygon is a closed shape that may or may not be filled with the currently selected color, and it is the basis of all solid-object composition in OpenGL.
Triangles: Your First Polygon
The simplest polygon possible is the triangle, with only three sides. The GL_TRIANGLES primitive draws triangles by connecting three vertices together. The following code draws two triangles using three vertices each, as shown in Figure 3.14:
glBegin(GL_TRIANGLES); glVertex2f(0.0f, 0.0f); // V0 glVertex2f(25.0f, 25.0f); // V1 glVertex2f(50.0f, 0.0f); // V2 glVertex2f(-50.0f, 0.0f); // V3 glVertex2f(-75.0f, 50.0f); // V4 glVertex2f(-25.0f, 0.0f); // V5 glEnd();
Figure 3.14 Two triangles drawn using GL_TRIANGLES.
The triangles will be filled with the currently selected drawing color. If you don't specify a drawing color at some point, you can't be certain of the result.
An important characteristic of any polygonal primitive is illustrated in Figure 3.14. Notice the arrows on the lines that connect the vertices. When the first triangle is drawn, the lines are drawn from V0 to V1, then to V2, and finally back to V0 to close the triangle. This path is in the order that the vertices are specified, and for this example, that order is clockwise from your point of view. The same directional characteristic is present for the second triangle as well.
The combination of order and direction in which the vertices are specified is called winding. The triangles in Figure 3.14 are said to have clockwise winding because they are literally wound in the clockwise direction. If we reverse the positions of V4 and V5 on the triangle on the left, we get counterclockwise winding. Figure 3.15 shows two triangles, each with opposite windings.
Figure 3.15 Two triangles with different windings.
OpenGL, by default, considers polygons that have counterclockwise winding to be front facing. This means that the triangle on the left in Figure 3.15 shows the front of the triangle, and the one on the right shows the back side of the triangle.
Why is this issue important? As you will soon see, you will often want to give the front and back of a polygon different physical characteristics. You can hide the back of a polygon altogether or give it a different color and reflective property (see Chapter 5, "Color, Materials, and Lighting: The Basics"). It's important to keep the winding of all polygons in a scene consistent, using front-facing polygons to draw the outside surface of any solid objects. In the upcoming section on solid objects, we demonstrate this principle using some models that are more complex.
If you need to reverse the default behavior of OpenGL, you can do so by calling the following function:
The GL_CW parameter tells OpenGL that clockwise-wound polygons are to be considered front facing. To change back to counterclockwise winding for the front face, use GL_CCW.
For many surfaces and shapes, you need to draw several connected triangles. You can save a lot of time by drawing a strip of connected triangles with the GL_TRIANGLE_STRIP primitive. Figure 3.16 shows the progression of a strip of three triangles specified by a set of five vertices numbered V0 through V4. Here, you see the vertices are not necessarily traversed in the same order they were specified. The reason for this is to preserve the winding (counterclockwise) of each triangle. The pattern is V0, V1, V2; then V2, V1, V3; then V2, V3, V4; and so on.
Figure 3.16 The progression of a GL_TRIANGLE_STRIP.
For the rest of the discussion of polygonal primitives, we don't show any more code fragments to demonstrate the vertices and the glBegin statements. You should have the swing of things by now. Later, when we have a real sample program to work with, we resume the examples.
There are two advantages to using a strip of triangles instead of specifying each triangle separately. First, after specifying the first three vertices for the initial triangle, you need to specify only a single point for each additional triangle. This saves a lot of program or data storage space when you have many triangles to draw. The second advantage is mathematical performance and bandwidth savings. Fewer vertices mean a faster transfer from your computer's memory to your graphics card and fewer vertex transformations (see Chapters 2 and 4).
Another advantage to composing large flat surfaces out of several smaller triangles is that when lighting effects are applied to the scene, OpenGL can better reproduce the simulated effects. You'll learn more about lighting in Chapter 5.
In addition to triangle strips, you can use GL_TRIANGLE_FAN to produce a group of connected triangles that fan around a central point. Figure 3.17 shows a fan of three triangles produced by specifying four vertices. The first vertex, V0, forms the origin of the fan. After the first three vertices are used to draw the initial triangle, all subsequent vertices are used with the origin (V0) and the vertex immediately preceding it (Vn1) to form the next triangle.
Figure 3.17 The progression of GL_TRIANGLE_FAN.