Antialiasing the edges of filled polygons is similar to antialiasing points and lines. When different polygons have overlapping edges, you need to blend the color values appropriately. You can either use the method described in this section, or you can use the accumulation buffer to perform antialiasing for your entire scene. Using the accumulation buffer, which is described in Chapter 10 , is easier from your point of view, but it's much more computation-intensive and therefore slower. However, as you'll see, the method described here is rather cumbersome
If you draw your polygons as points at the vertices or as outlines - that is, by passing GL_POINT or GL_LINE to glPolygonMode() - point or line antialiasing is applied, if enabled as described earlier. The rest of this section addresses polygon antialiasing when you're using GL_FILL as the polygon mode.
In theory, you can antialias polygons in either RGBA or color-index mode. However, object intersections affect polygon antialiasing more than they affect point or line antialiasing, so rendering order and blending accuracy become more critical. In fact, they're so critical that if you're antialiasing more than one polygon, you need to order the polygons from front to back and then use glBlendFunc() with GL_SRC_ALPHA_SATURATE for the source factor and GL_ONE for the destination factor. Thus, antialiasing polygons in color-index mode normally isn't practical.
To antialias polygons in RGBA mode, you use the alpha value to represent coverage values of polygon edges. You need to enable polygon antialiasing by passing GL_POLYGON_SMOOTH to glEnable(). This causes pixels on the edges of the polygon to be assigned fractional alpha values based on their coverage, as though they were lines being antialiased. Also, if you desire, you can supply a value for GL_POLYGON_SMOOTH_HINT.
Now you need to blend overlapping edges appropriately. First, turn off the depth buffer so that you have control over how overlapping pixels are drawn. Then set the blending factors to GL_SRC_ALPHA_SATURATE (source) and GL_ONE (destination). With this specialized blending function, the final color is the sum of the destination color and the scaled source color; the scale factor is the smaller of either the incoming source alpha value or one minus the destination alpha value. This means that for a pixel with a large alpha value, successive incoming pixels have little effect on the final color because one minus the destination alpha is almost zero. With this method, a pixel on the edge of a polygon might be blended eventually with the colors from another polygon that's drawn later. Finally, you need to sort all the polygons in your scene so that they're ordered from front to back before drawing them.
Example 7-5 shows how to antialias filled polygons; clicking the left mouse button toggles the antialiasing on and off. Note that backward-facing polygons are culled and that the alpha values in the color buffer are cleared to zero before any drawing. (Your color buffer must store alpha values for this technique to work correctly.)
Example 7-5 : Antialiasing Filled Polygons: antipoly.c
#include <GL/gl.h>
#include <GL/glu.h>
#include "aux.h"
GLboolean polySmooth;
void myinit(void)
{
GLfloat mat_ambient[] = { 0.0, 0.0, 0.0, 1.00 };
GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.00 };
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);
glEnable (GL_BLEND);
glCullFace (GL_BACK);
glEnable (GL_CULL_FACE);
glEnable (GL_POLYGON_SMOOTH);
polySmooth = GL_TRUE;
glClearColor (0.0, 0.0, 0.0, 0.0);
}
void toggleSmooth (AUX_EVENTREC *event)
{
if (polySmooth) {
polySmooth = GL_FALSE;
glDisable (GL_BLEND);
glDisable (GL_POLYGON_SMOOTH);
glEnable (GL_DEPTH_TEST);
}
else {
polySmooth = GL_TRUE;
glEnable (GL_BLEND);
glEnable (GL_POLYGON_SMOOTH);
glDisable (GL_DEPTH_TEST);
}
}
void display(void)
{
GLfloat position[] = { 0.0, 0.0, 1.0, 0.0 };
GLfloat mat_cube1[] = { 0.75, 0.75, 0.0, 1.0 };
GLfloat mat_cube2[] = { 0.0, 0.75, 0.75, 1.0 };
if (polySmooth)
glClear (GL_COLOR_BUFFER_BIT);
else
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix ();
glTranslatef (0.0, 0.0, -8.0);
glLightfv (GL_LIGHT0, GL_POSITION, position);
glBlendFunc (GL_SRC_ALPHA_SATURATE, GL_ONE);
glPushMatrix ();
glRotatef (30.0, 1.0, 0.0, 0.0);
glRotatef (60.0, 0.0, 1.0, 0.0);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_cube1);
auxSolidCube (1.0, 1.0, 1.0);
glPopMatrix ();
glTranslatef (0.0, 0.0, -2.0);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_cube2);
glRotatef (30.0, 0.0, 1.0, 0.0);
glRotatef (60.0, 1.0, 0.0, 0.0);
auxSolidCube (1.0);
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);
}
int main(int argc, char** argv)
{
auxInitDisplayMode (AUX_SINGLE | AUX_RGBA | AUX_DEPTH);
auxInitPosition (0, 0, 200, 200);
auxInitWindow (argv[0]);
auxMouseFunc (AUX_LEFTBUTTON, AUX_MOUSEDOWN, toggleSmooth);
myinit();
auxReshapeFunc (myReshape);
auxMainLoop(display);
}
OpenGL Programming Guide