Displaying Points, Lines, and Polygons (State Management and Drawing Geometric Objects) (OpenGL Programming) Part 2

Polygons as Points, Outlines, or Solids

A polygon has two sides—front and back—and might be rendered differently depending on which side is facing the viewer. This allows you to have cutaway views of solid objects in which there is an obvious distinction between the parts that are inside and those that are outside. By default, both front and back faces are drawn in the same way. To change this, or to draw only outlines or vertices, use glPolygonMode().

void glPolygonMode(GLenum face, GLenum mode);

Controls the drawing mode for a polygon’s front and back faces. The parameter face can be GL_FRONT_AND_BACK, GL_FRONT, or GL_BACK; mode can be GL_POINT, GL_LINE, or GL_FILL to indicate whether the polygon should be drawn as points, outlined, or filled. By default, both the front and back faces are drawn filled.

For example, you can have the front faces filled and the back faces outlined with two calls to this routine:

tmp5324-72_thumb[2]

Reversing and Culling Polygon Faces

By convention, polygons whose vertices appear in counterclockwise order on the screen are called front-facing. You can construct the surface of any "reasonable" solid—a mathematician would call such a surface an orient-able manifold (spheres, donuts, and teapots are orientable; Klein bottles and Mobius strips aren’t)—from polygons of consistent orientation. In other words, you can use all clockwise polygons or all counterclockwise polygons. (This is essentially the mathematical definition of orientable.)


Suppose you’ve consistently described a model of an orientable surface but happen to have the clockwise orientation on the outside. You can swap what OpenGL considers the back face by using the function glFrontFace(), supplying the desired orientation for front-facing polygons.

void glFrontFace(GLenum mode)

Controls how front-facing polygons are determined. By default, mode is GL_CCW, which corresponds to a counterclockwise orientation of the ordered vertices of a projected polygon in window coordinates. If mode is GL_CW, faces with a clockwise orientation are considered front-facing.

Note: The orientation (clockwise or counterclockwise) of the vertices is also known as its winding.

In a completely enclosed surface constructed from opaque polygons with a consistent orientation, none of the back-facing polygons are ever visible— they’re always obscured by the front-facing polygons. If you are outside this surface, you might enable culling to discard polygons that OpenGL determines are back-facing. Similarly, if you are inside the object, only back-facing polygons are visible. To instruct OpenGL to discard front- or back-facing polygons, use the command glCullFace() and enable culling with glEnableQ.

void glCullFace(GLenum mode);

Indicates which polygons should be discarded (culled) before they’re converted to screen coordinates. The mode is either GL_FRONT, GL_ BACK, or GL_FRONT_AND _BACK to indicate front-facing, back-facing, or all polygons. To take effect, culling must be enabled using glEnable() with GL_CULL_FACE; it can be disabled with glDisable() and the same argument.

Advanced

In more technical terms, deciding whether a face of a polygon is front- or back-facing depends on the sign of the polygon’s area computed in window coordinates. One way to compute this area is

tmp5324-73_thumb[2]

where *,· and y,· are the x and y window coordinates of the z’th vertex of the «-vertex polygon and

tmp5324-74_thumb[2]

Assuming that GL_CCW has been specified, if a > 0, the polygon corresponding to that vertex is considered to be front-facing; otherwise, it’s back-facing. If GL_CW is specified and if a < 0, then the corresponding polygon is front-facing; otherwise, it’s back-facing.

Try This

Modify Example 2-5 by adding some filled polygons. Experiment with different colors. Try different polygon modes. Also, enable culling to see its effect.

Stippling Polygons

By default, filled polygons are drawn with a solid pattern. They can also be filled with a 32-bit by 32-bit window-aligned stipple pattern, which you specify with glPolygonStippleQ.

void glPolygonStipple(const GLubyte *mask);

Defines the current stipple pattern for filled polygons. The argument mask is a pointer to a 32 χ 32 bitmap that’s interpreted as a mask of Os and Is. Where a 1 appears, the corresponding pixel in the polygon is drawn, and where a 0 appears, nothing is drawn. Figure 2-10 snows how a stipple pattern is constructed from the characters in mask. Polygon stippling is enabled and disabled by using glEnableQ and glDisable() with GL_ POLYGON_STIPPLE as the argument. The interpretation of the mask data is affected by the glPixelStore*() GL_UNPACK* modes.

In addition to defining the current polygon stippling pattern, you must enable stippling:

tmp5324-75_thumb[2]

Use glDisable() with the same argument to disable polygon stippling.

Figure 2-11 shows the results of polygons drawn unstippled and then with two different stippling patterns. The program is shown in Example 2-6. The reversal of white to black (from Figure 2-10 to Figure 2-11) occurs because the program draws in white over a black background, using the pattern in Figure 2-10 as a stencil.

Constructing a Polygon Stipple Pattern

Figure 2-10 Constructing a Polygon Stipple Pattern

Stippled Polygons

Figure 2-11    Stippled Polygons

Example 2-6    Polygon Stipple Patterns: polys.c

Polygon Stipple Patterns: polys.c

 

 

 

Polygon Stipple Patterns: polys.c

You might want to use display lists to store polygon stipple patterns to maximize efficiency.

Marking Polygon Boundary Edges Advanced

OpenGL can render only convex polygons, but many nonconvex polygons arise in practice. To draw these nonconvex polygons, you typically subdivide them into convex polygons—usually triangles, as shown in Figure 2-12—and then draw the triangles. Unfortunately, if you decompose a general polygon into triangles and draw the triangles, you can’t really use glPolygonMode() to draw the polygon’s outline, as you get all the triangle outlines inside it. To solve this problem, you can tell OpenGL whether a particular vertex precedes a boundary edge; OpenGL keeps track of this information by passing along with each vertex a bit indicating whether that vertex is followed by a boundary edge. Then, when a polygon is drawn in GL_LINE mode, the nonboundary edges aren’t drawn. In Figure 2-12, the dashed lines represent added edges.

Subdividing a Nonconvex Polygon

Figure 2-12 Subdividing a Nonconvex Polygon

By default, all vertices are marked as preceding a boundary edge, but you can manually control the setting of the edge flag with the command glEdgeFlag*(). This command is used between glBegin() and glEnd() pairs, and it affects all the vertices specified after it until the next glEdgeFlagO call is made. It applies only to vertices specified for polygons, triangles, and quads, not to those specified for strips of triangles or quads.

void glEdgeFlag(GLboolean flag); void gl Edgel lagv( const GLboolean *flag);

Indicates whether a vertex should be considered as initializing a boundary edge of a polygon. If flag is GL_TRUE, the edge flag is set to TRUE (the default), and any’vertices created are considered to precede boundary edges until this function is called again with flag being GLJFALSE.

For instance, Example 2-7 draws the outline shown in Figure 2-13.

Outlined Polygon Drawn Using Edge Flags

Figure 2-13    Outlined Polygon Drawn Using Edge Flags

Example 2-7    Marking Polygon Boundary Edges

Marking Polygon Boundary Edges

Next post:

Previous post: