State Management and Drawing Geometric Object
State Management and Drawing Geometric Object
By default,
A point is drawn as a single pixel on the
screen
A line is drawn solid and 1 pixel wide,
Polygons are drawn solidly filled in.
In this section we going discuss the details of
how to change these default display modes.
Point Details
To change the size of a rendered point, use
glPointSize() and supply the desired size in pixels as the
argument.
size must be greater than 0.0 and by default is 1.0.
Line Details
With OpenGL, you can specify lines with different widths
and lines that are stippled in various ways (i.e. dotted,
dashed, drawn with alternating dots and dashes and so on.)
void glLineWidth(GLfloat width); Sets the width, in pixels,
for rendered lines; width must be greater than 0.0 and by
default is 1.0
Stippled Lines
To make stippled (dotted or dashed) lines, you use
the command glLineStipple() to define the stipple
pattern, and then you enable line stippling with
glEnable().
glLineStipple(1, 0x3F07);
glEnable(GL_LINE_STIPPLE);
void glLineStipple(GLint factor, GLushort
pattern); Sets the current stippling pattern for lines.
o The pattern argument is a 16-bit series of 0s and
1s, and it’s repeated as necessary to stipple a given
line.
o A 1 indicates that drawing occurs, and a 0 that it
does not, on a pixel-by pixel basis, beginning with
the low-order bit of the pattern.
o The pattern can be stretched out by using factor,
which multiplies each subseries of consecutive 1s
and 0s.
o If three consecutive 1s appear in the pattern,
they’re stretched to six if factor is 2.
o Factor is clamped to lie between 1 and 256.
o Line stippling must be enabled by passing
GL_LINE_STIPPLE to glEnable(); it’s
disabled by passing the same argument to
glDisable()
Polygon Details
Polygons are typically drawn by filling in all
the pixels enclosed within the boundary, but
you can also draw them as outlined polygons
or simply as points at the vertices.
A filled polygon might be solidly filled
stippled with a certain pattern.
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:
glPolygonMode(GL_FRONT, GL_FILL);
glPolygonMode(GL_BACK, GL_LINE);
Reversing and Culling Polygon Faces
By convention, polygons whose vertices appear in
counterclockwise order on the screen are called front-facing; but
you can use all clockwise polygons, or all counterclockwise
polygons.
Suppose you've consistently described a model of an orientable
surface but that you 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.
To instruct OpenGL to discard front- or back-facing
polygons, use the command glCullFace() and enable
culling with glEnable().
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.
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
glPolygonStipple().
void glPolygonStipple(const GLubyte *mask);
The argument mask is a pointer to a 32 × 32 bitmap that's
interpreted as a mask of 0s and 1s. Where a 1 appears, the
corresponding pixel in the polygon is drawn, and where a 0
appears, nothing is drawn.
Polygon stippling is enabled and disabled by using
glEnable() and glDisable() with GL_POLYGON_STIPPLE
as the argument.
Marking Polygon Boundary Edges
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
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, since 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 non-boundary edges aren't drawn.
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
glEdgeFlag() 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 glEdgeFlagv(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 GL_FALSE.
Normal Vector
A normal vector is a vector that points in a direction that's
perpendicular to a surface.
For a flat surface, one perpendicular direction is the same
for every point on the surface.
but for a general curved surface, the normal direction might
be different at each point on the surface.
With OpenGL, you can specify a normal for each polygon
or for each vertex.
Vertices of the same polygon might share the same normal
(for a flat surface) or have different normal (for a curved
surface).
But you can't assign normal anywhere other than at the
vertices.
An object's normal vectors define the orientation
of its surface in space - in particular, its
orientation relative to light sources.
These vectors are used by OpenGL to determine
how much light the object receives at its vertices.
You use glNormal*() to set the current normal to
the value of the argument passed in.
Subsequent calls to glVertex*() cause the
specified vertices to be assigned the current
normal. Often, each vertex has a different normal,
which necessitates a series of alternating calls, as
in the following example
glBegin (GL_POLYGON);
glNormal3fv(n0);
glVertex3fv(v0);
glNormal3fv(n1);
glVertex3fv(v1);
glNormal3fv(n2);
glVertex3fv(v2);
glNormal3fv(n3);
glVertex3fv(v3);
glEnd();
By convention, the normal is the one that points to the
outside of the surface being modeled. (If you get inside and
outside reversed in your model, just change every normal
vector from (x, y, z) to (- &xgr; , -y, -z))
normal vectors indicate direction only, their length is
mostly irrelevant.
You can specify normals of any length, but eventually they
have to be converted to having a length of 1 before lighting
calculations are performed.
(A vector that has a length of 1 is said to be of unit length,
or normalized.)
In general, you should supply normalized normal vectors.
To make a normal vector of unit length, divide each of its
x, y, z components by the length of the normal:
Normal vectors remain normalized as long as your
model transformations include only rotations and
translations.
If you perform irregular transformations (such as scaling
or multiplying by a shear matrix), or if you specify non-
unit-length normal, then you should have OpenGL
automatically normalize your normal vectors after the
transformations.
To do this, call glEnable() with GL_NORMALIZE as its
argument.
By default, automatic normalization is disabled.
Note that automatic normalization typically requires
additional calculations that might reduce the
performance of your application.
Vertex array
For some systems, function calls have a great deal of
overhead and can hinder performance.
OpenGL has vertex array routines that allow you to
specify a lot of vertex-related data with just a few
arrays and to access that data with equally few
function calls.
Arranging data in vertex arrays may increase the
performance of your application.
Using vertex arrays reduces the number of function
calls, which improves performance.
Also, using vertex arrays may allow non-redundant
processing of shared vertices.
There are three steps to using vertex arrays
to render geometry
A. Enabling arrays
B. Specifying Data for the Arrays
C. Dereferencing and Rendering
A. Enabling arrays
Call glEnableClientState() with an enumerated parameter,
which activates the chosen array.
the acceptable parameters are
GL_VERTEX_ARRAY,
GL_COLOR_ARRAY,
GL_INDEX_ARRAY,
GL_NORMAL_ARRAY
GL_TEXTURE_COORD_ARRAY
GL_EDGE_FLAG_ARRAY
void glDisableClientState(GLenum array); Specifies the
array to disable. Accepts the same symbolic constants as
glEnableClientState().
B. Specifying Data for the Arrays
There are six different routines to specify arrays - one routine
for each kind of array.
There is also a command that can specify several client-space
arrays at once, all originating from a single interleaved array.
void glVertexPointer(GLint size, GLenum type, GLsizei stride,
const GLvoid *pointer); where
type specifies the data type (GL_SHORT, GL_INT,
GL_FLOAT, or GL_DOUBLE)
size is the number of coordinates per vertex , which must be 2,
3, or 4
Stride is the byte offset between consecutive vertexes. If stride
is 0, the vertices are understood to be tightly packed in the array.
pointer is the memory address of the first coordinate of the first
vertex in the array
To access the other five arrays, there are five
similar routines:
void glColorPointer(GLint size, GLenum type,
GLsizei stride, const GLvoid *pointer);
void glIndexPointer(GLenum type, GLsizei
stride, const GLvoid *pointer);
void glNormalPointer(GLenum type, GLsizei
stride, const GLvoid *pointer);
void glTexCoordPointer(GLint size, GLenum
type, GLsizei stride, const GLvoid *pointer);
void glEdgeFlagPointer(GLsizei stride, const
GLvoid *pointer);
The main differences among the routines are whether size and type are
unique or must be specified.
Example
glColorPointer (3, GL_FLOAT, 0, colors);
glVertexPointer (2, GL_INT, 0, vertices);
C. Dereferencing and Rendering
Until the contents of the vertex arrays are
dereferenced, the arrays remain on the client side,
and their contents are easily changed.
In this step contents of the arrays are obtained,
sent down to the server, and then sent down the
graphics processing pipeline for rendering.
There are three ways to obtain data:
from a single array element (indexed location)
from a sequence of array elements, and
from an ordered list of array elements.