📄 chapter07.html
字号:
fragment. For example, you can draw a polygon in the shape of a tree and
apply a texture map of foliage; the viewer can see through parts of the
rectangular texture that aren't part of the tree if you've assigned them
alpha values of 0. This method, sometimes called <I>billboarding</I>, is
much faster than creating the tree out of three-dimensional polygons. An
example of this technique is shown in Figure 7-1 : The tree is a single
rectangular polygon that can be rotated about the center of the trunk,
as shown by the outlines, so that it's always facing the viewer. See "Modulating
and Blending" for more information about blending textures.</OL>
<IMG SRC="figures/raster.gif" ALT="[IMAGE]" >
<P><B>Figure 7-1 : </B>Creating a Nonrectangular Raster Image
<BR>
<BR>
<H3>
A Blending Example</H3>
Example 7-1 draws four overlapping colored rectangles - each with an alpha
of 0.75 - so that the lower left and upper right quadrants of the window
are covered twice. In these two quadrants, the colors are blended in different
orders using source and destination blending factors of GL_SRC_ALPHA and
GL_ONE_MINUS_SRC_ALPHA: In the lower left quadrant, cyan is blended with
the original yellow; in the upper right quadrant, yellow is blended with
the original cyan. The other quadrants are drawn with unblended colors.
<P><B>Example 7-1 : </B>A Blending Example: alpha.c
<PRE>#include <GL/gl.h>
#include <GL/glu.h>
#include "aux.h"
void myinit(void)
{
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glShadeModel(GL_FLAT);
glClearColor(0.0, 0.0, 0.0, 0.0);
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glColor4f(1.0, 1.0, 0.0, 0.75);
glRectf(0.0, 0.0, 0.5, 1.0);
glColor4f(0.0, 1.0, 1.0, 0.75);
glRectf(0.0, 0.0, 1.0, 0.5);
/* draw colored polygons in reverse order in upper right */
glColor4f (0.0, 1.0, 1.0, 0.75);
glRectf (0.5, 0.5, 1.0, 1.0);
glColor4f (1.0, 1.0, 0.0, 0.75);
glRectf (0.5, 0.5, 1.0, 1.0);
glFlush();
}
void myReshape(GLsizei w, GLsizei h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (w <= h)
gluOrtho2D (0.0, 1.0, 0.0, 1.0*(GLfloat)h/(GLfloat)w);
else
gluOrtho2D (0.0, 1.0*(GLfloat)w/(GLfloat)h, 0.0, 1.0);
glMatrixMode(GL_MODELVIEW);
}
int main(int argc, char** argv)
{
auxInitDisplayMode (AUX_SINGLE | AUX_RGBA);
auxInitPosition (0, 0, 500, 500);
auxInitWindow (argv[0]);
myinit();
auxReshapeFunc (myReshape);
auxMainLoop(display);
}</PRE>
As you probably expected, the order in which the rectangles are drawn affects
the resulting colors. In the lower left quadrant, the cyan rectangle becomes
the source fragment that's blended with the yellow rectangle, which is
already in the framebuffer and thus is the destination. In the upper right
quadrant, the yellow rectangle is the source and the cyan one the destination.
Because the alpha values are all 0.75, the actual blending factors become
0.75 for the source and 1.0 - 0.75 = 0.25 for the destination. In other
words, the source rectangle is somewhat translucent, but it has more effect
on the final color than the destination rectangle. As a result, the lower
left quadrant is light cyan, and the upper left one is light yellow. If
you do the arithmetic, you'll find that the lower left RGB color is (0.25,
1.0, 0.75) and the upper right color is (0.75, 1.0, 0.25).
<H3>
Three-Dimensional Blending with the Depth Buffer</H3>
As you saw in the previous example, the order in which polygons are drawn
greatly affects the blended result. When drawing three-dimensional translucent
objects, you can get different appearances depending on whether you draw
the polygons from back to front or from front to back. You also need to
consider the effect of the depth buffer when determining the correct order.
The depth buffer (sometimes called the z-buffer) is usually used for hidden-surface
elimination. (See Chapter 10 for a detailed discussion of the depth buffer.)
It keeps track of the distance between the viewpoint and the portion of
the object occupying a given pixel in a window on the screen; when another
candidate color arrives for that pixel, it's drawn only if its object is
closer to the viewpoint, in which case its depth value is stored in the
depth buffer. With this method, obscured (or hidden) portions of surfaces
aren't necessarily drawn and therefore aren't used for blending.
<P>Typically, you want to render both opaque and translucent objects in
the same scene, and you want to use the depth buffer to perform hidden-surface
removal for objects that lie behind the opaque objects. If an opaque object
hides either a translucent object or another opaque object, you want the
depth buffer to eliminate the more distant object. If the translucent object
is closer, however, you want to blend it with the opaque object. You can
generally figure out the correct order to draw the polygons if everything
in the scene is stationary, but the problem can easily become too hard
if either the viewpoint or the object is moving.
<P>The solution is to enable depth-buffering but make the depth buffer
read-only while drawing the translucent objects. First you draw all the
opaque objects, with the depth buffer in normal operation. Then, you preserve
these depth values by making the depth buffer read-only. When the translucent
objects are drawn, their depth values are still compared to the values
established by the opaque objects, so they aren't drawn if they're behind
the opaque ones. If they're closer to the viewpoint, however, they don't
eliminate the opaque objects, since the depth-buffer values can't change.
Instead, they're blended with the opaque objects. To control whether the
depth buffer is writable, use <B>glDepthMask()</B>; if you pass GL_FALSE
as the argument, the buffer becomes read-only, whereas GL_TRUE restores
the normal, writable operation.
<P>Example 7-2 demonstrates how to use this method to draw opaque and translucent
three-dimensional objects. In the program, pressing the left mouse button
calls <B>toggleviewpoint()</B>, which changes the viewpoint position, and
thus the ordering of an opaque torus and a translucent cylinder. Keep in
mind that this solution is exact only when no pixel in the framebuffer
is drawn more than once by a transparent object. If transparent objects
overlap, resulting in multiple blended renderings to individual pixels,
this solution is only a useful approximation to the correct (sorted) result.
<P><B>Example 7-2 : </B>Three-Dimensional Blending: alpha3D.c
<PRE>#include <GL/gl.h>
#include <GL/glu.h>
#include "aux.h"
void myinit(void)
{
GLfloat mat_ambient[] = { 0.0, 0.0, 0.0, 0.15 };
GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 0.15 };
GLfloat mat_shininess[] = { 15.0 };
glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glDepthFunc(GL_LEQUAL);
glEnable(GL_DEPTH_TEST);
}
GLboolean eyePosition = GL_FALSE;
void toggleEye(AUX_EVENTREC *event)
{
if (eyePosition)
eyePosition = GL_FALSE;
else
eyePosition = GL_TRUE;
}
void display(void)
{
GLfloat position[] = { 0.0, 0.0, 1.0, 1.0 };
GLfloat mat_torus[] = { 0.75, 0.75, 0.0, 1.0 };
GLfloat mat_cylinder[] = { 0.0, 0.75, 0.75, 0.15 };
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLightfv(GL_LIGHT0, GL_POSITION, position);
glPushMatrix();
if (eyePosition)
gluLookAt(0.0, 0.0, 9.0, 0.0, 0.0, 0.0, 0.0,
1.0, 0.0);
else
gluLookAt(0.0, 0.0, -9.0, 0.0, 0.0, 0.0, 0.0,
1.0, 0.0);
glPushMatrix();
glTranslatef(0.0, 0.0, 1.0);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_torus);
auxSolidTorus(0.275, 0.85);
glPopMatrix();
glEnable(GL_BLEND);
glDepthMask(GL_FALSE);
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_cylinder);
glTranslatef(0.0, 0.0, -1.0);
auxSolidCylinder(1.0, 2.0);
glDepthMask(GL_TRUE);
glDisable(GL_BLEND);
glPopMatrix();
glFlush();
}
void myReshape(GLsizei w, GLsizei h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(30.0, (GLfloat) w/(GLfloat) h, 1.0, 20.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
int main(int argc, char** argv)
{
auxInitDisplayMode(AUX_SINGLE | AUX_RGBA | AUX_DEPTH);
auxInitPosition(0, 0, 500, 500);
auxInitWindow(argv[0]);
auxMouseFunc(AUX_LEFTBUTTON, AUX_MOUSEDOWN, toggleEye);
myinit();
auxReshapeFunc(myReshape);
auxMainLoop(display);
}</PRE>
<HR>
<H2>
Antialiasing</H2>
You might have noticed in some of your OpenGL pictures that lines, especially
nearly horizontal or nearly vertical ones, appear jagged. These jaggies
appear because the ideal line is approximated by a series of pixels that
must lie on the pixel grid. The jaggedness is called aliasing, and this
section describes antialiasing techniques to reduce it. Figure 7-2 shows
two intersecting lines, both aliased and antialiased. The pictures have
been magnified to show the effect
<P><IMG SRC="figures/Fig7-2.gif" ALT="[IMAGE]" >
<P><B>Figure 7-2 : </B>Aliased and Antialiased Lines
<BR>
<BR>
<P>Figure 7-2 shows how a diagonal line one pixel wide covers more of some
pixel squares than others. In fact, when performing antialiasing, OpenGL
calculates a <I>coverage</I> value for each fragment based on the fraction
of the pixel square on the screen that it would cover. The figure shows
these coverage values for the line. In RGBA mode, OpenGL multiplies the
fragment's alpha value by its coverage. You can then use the resulting
alpha value to blend the fragment with the corresponding pixel already
in the framebuffer. In color-index mode, OpenGL sets the least significant
4 bits of the color index based on the fragment's coverage (0000 for no
coverage and 1111 for complete coverage). It's up to you to load your color
map and apply it appropriately to take advantage of this coverage information.
<P><IMG SRC="figures/cover.gif" ALT="[IMAGE]" >
<P><B>Figure 7-3 : </B>Determining Coverage Values
<BR>
<BR>
<P>The details of calculating coverage values are complex, difficult to
specify in general, and in fact may vary slightly depending on your particular
implementation of OpenGL. You can use the <B>glHint()</B> command to exercise
some control over the trade-off between image quality and speed, but not
all implementations will take the hint. void <B>glHint</B>(GLenum <B>target</B>,
GLenum <B>hint</B>);
<P>Controls certain aspects of OpenGL behavior. The <B>target</B> parameter
indicates which behavior is to be controlled; its possible values are shown
in Table 7-2 . The <B>hint</B> parameter can be GL_FASTEST to indicate
that the most efficient option should be chosen, GL_NICEST to indicate
the highest-quality option, or GL_DONT_CARE to indicate no preference.
The interpretation of hints is implementation-dependent; an implementation
can ignore them entirely.
<P>For more information about the relevant topics, see "Antialiasing" for
the details on sampling and "Fog" for details on fog. The GL_PERSPECTIVE_CORRECTION_HINT
parameter refers to how color values and texture coordinates are interpolated
across a primitive: either linearly in screen space (a relatively simple
calculation) or in a perspective-correct manner (which requires more computation).
Often, systems perform linear color interpolation because the results,
while not technically correct, are visually acceptable; textures, however,
in most cases require perspective-correct interpolation to be visually
acceptable. Thus, an implementation can choose to use this parameter to
control the method used for interpolation. Perspective projection is discussed
in Chapter 3 , color is discussed in Chapter 5 , and texture mapping is
discussed in Chapter 9 .
<TABLE BORDER CELLPADDING=10 >
<CAPTION ALIGN=TOP><B>Table 7-2 : </B>Values for Use with glHint() and
Their Meaning</CAPTION>
<TR ALIGN=LEFT VALIGN=TOP>
<TH>Parameter</TH>
<TH>Meaning</TH>
</TR>
<TR ALIGN=LEFT VALIGN=TOP>
<TD>GL_POINT_SMOOTH_HINT, GL_LINE_SMOOTH_HINT, GL_POLYGON_SMOOTH_HINT</TD>
<TD>Specify the desired sampling quality of points, lines, or polygons
during antialiasing operations</TD>
</TR>
<TR ALIGN=LEFT VALIGN=TOP>
<TD>GL_FOG_HINT</TD>
<TD>Specifies whether fog calculations are done per pixel (GL_NICEST) or
per vertex (GL_FASTEST)</TD>
</TR>
<TR ALIGN=LEFT VALIGN=TOP>
<TD>GL_PERSPECTIVE_CORRECTION_HINT</TD>
<TD>Specifies the desired quality of color and texture-coordinate interpolation</TD>
</TR>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -