The 3D shape of an object is known as its
*geometry*. In OpenGL, the geometry of an object
constitutes a set of *primitives* that are either
triangles, points, or lines. These primitives are defined using an array
of vertices, and the vertices are connected according to the primitive’s
*topology*. OpenGL ES supports seven topologies, as
depicted in Figure 2-2.

Recall the one line of code in HelloArrow from Chapter 1 that tells OpenGL to render the triangles to the backbuffer:

glDrawArrays(GL_TRIANGLES, 0, vertexCount);

The first argument to this function specifies
the *primitive topology*:
`GL_TRIANGLES`

tells OpenGL to interpret the vertex
buffer such that the first three vertices compose the first triangle, the
second three vertices compose the second triangle, and so on.

In many situations you need to specify a
sequence of adjoining triangles, in which case several vertices would be
duplicated in the vertex array. That’s when `GL_TRIANGLE_STRIP`

comes in. It allows a
much smaller set of vertices to expand to the same number of triangles, as
shown in Table 2-1. In the table,
*v* is the number of vertices, and
*p* is the number of primitives. For example, to draw
three triangles using `GL_TRIANGLES`

, you’d need nine vertices
(3p). To draw them using `GL_TRIANGLE_STRIP`

, you’d need
only five (p + 2).

Table 2-1. Primitive counts

Topology | Number of primitives | Number of vertices |
---|---|---|

GL_POINTS | v | p |

GL_LINES | v / 2 | 2p |

GL_LINE_LOOP | v | p |

GL_LINE_STRIP | v - 1 | p + 1 |

GL_TRIANGLES | v / 3 | 3p |

GL_TRIANGLE_STRIP | n - 2 | p + 2 |

GL_TRIANGLE_FAN | n - 1 | p + 1 |

Another way of specifying triangles is
`GL_TRIANGLE_FAN`

, which is useful for drawing a polygon,
a circle, or the top of a 3D dome. The first vertex specifies the apex
while the remaining vertices form the rim. For many of these shapes, it’s
possible to use `GL_TRIANGLE_STRIP`

,
but doing so would result in degenerate triangles (triangles with zero
area).

For example, suppose you wanted to draw a
square shape using two triangles, as shown in Figure 2-3. (Incidentally, full-blown OpenGL has a
`GL_QUADS`

primitive that would come in handy for this,
but quads are not supported in OpenGL ES.) The following code snippet
draws the same square three times, using a different primitive topology
each time:

const int stride = 2 * sizeof(float); float triangles[][2] = { {0, 0}, {0, 1}, {1, 1}, {1, 1}, {1, 0}, {0, 0} }; glVertexPointer(2, GL_FLOAT, stride, triangles); glDrawArrays(GL_TRIANGLES, 0, sizeof(triangles) / stride); float triangleStrip[][2] = { {0, 1}, {0, 0}, {1, 1}, {1, 0} }; glVertexPointer(2, GL_FLOAT, stride, triangleStrip); glDrawArrays(GL_TRIANGLE_STRIP, 0, sizeof(triangleStrip) / stride); float triangleFan[][2] = { {0, 0}, {0, 1}, {1, 1}, {1, 0} }; glVertexPointer(2, GL_FLOAT, stride, triangleFan); glDrawArrays(GL_TRIANGLE_FAN, 0, sizeof(triangleFan) / stride);

Triangles aren’t the only primitive type
supported in OpenGL ES. Individual points can be rendered using
`GL_POINTS`

. The size of each point can be specified
individually, and large points are rendered as squares. Optionally, a
small bitmap can be applied to each point; these are called
*point sprite*s, and we’ll learn more about them in
Chapter 7.

OpenGL supports line primitives using three different topologies: separate lines, strips, and loops. With strips and loops, the endpoint of each line serves as the starting point for the following line. With loops, the starting point of the first line also serves as the endpoint of the last line. Suppose you wanted to draw the border of the square shown in Figure 2-3; here’s how you could do so using the three different line topologies:

const int stride = 2 * sizeof(float); float lines[][2] = { {0, 0}, {0, 1}, {0, 1}, {1, 1}, {1, 1}, {1, 0}, {1, 0}, {0, 0} }; glVertexPointer(2, GL_FLOAT, stride, lines); glDrawArrays(GL_LINES, 0, sizeof(lines) / stride); float lineStrip[][2] = { {0, 0}, {0, 1}, {1, 1}, {1, 0}, {0, 0} }; glVertexPointer(2, GL_FLOAT, stride, lineStrip); glDrawArrays(GL_LINE_STRIP, 0, sizeof(lineStrip) / stride); float lineLoop[][2] = { {0, 0}, {0, 1}, {1, 1}, {1, 0} }; glVertexPointer(2, GL_FLOAT, stride, lineLoop); glDrawArrays(GL_LINE_LOOP, 0, sizeof(lineLoop) / stride);

Start Free Trial

No credit card required