next up previous contents
Next: 10 Lighting Techniques Up: 9 Antialiasing Previous: 9.4 Antialiasing With Textures   Contents


9.5 Antialiasing with Accumulation Buffer

Accumulation buffers can be used to antialias a scene without having to depth sort the primitives before rendering. A supersampling technique is used where the entire scene is offset by small, subpixel amounts in screen space, and accumulated. The jittering can be accomplished by modifying the transforms used to represent the scene.

One straightforward jittering method is to modify the projection matrix, adding small translations in $x$ and $y$. Care must be taken to compute the translations so that they shift the scene the appropriate amount in window coordinate space. Fortunately, computing these offsets is straightforward. To compute a jitter offset in terms of pixels, divide the jitter amount by the dimension of the object coordinate scene, then multiply by the appropriate viewport dimension. The example code fragment below shows how to calculate a jitter value for an orthographic projection; the results are applied to a translate call to modify the modelview matrix:

void ortho_jitter(GLfloat xoff, GLfloat yoff)
{
    GLint viewport[4];
    GLfloat ortho[16];
    GLfloat scalex, scaley;

    glGetIntegerv(GL_VIEWPORT, viewport);
    /* this assumes that only a glOrtho() call has been
    applied to the projection matrix */
    glGetFloatv(GL_PROJECTION_MATRIX, ortho);

    scalex = (2.f/ortho[0])/viewport[2];
    scaley = (2.f/ortho[5])/viewport[3];
    glTranslatef(xoff * scalex, yoff * scaley, 0.f);
}

If the projection matrix wasn't created by calling glOrtho() or gluOrtho2D(), then you will need to use the viewing volume extents (right, left, top, bottom) to compute scalex and scaley as follows:

    GLfloat right, left, top, bottom;

    scalex = ((right-left)/viewport[2];
    scaley = ((top-bottom)/viewport[3];

The code is very similar for jittering a perspective projection. In this example, we jitter the frustum itself:

void frustum_jitter(GLdouble left, GLdouble right,
                    GLdouble bottom, GLdouble top,
                    GLdouble near, GLdouble far,
                    GLdouble xoff, GLdouble yoff)
{
    GLfloat scalex, scaley;
    GLint viewport[4];

    glGetIntegerv(GL_VIEWPORT, viewport);
    scalex = (right - left)/viewport[2];
    scaley = (top - bottom)/viewport[3];

    glFrustum(left - xoff * scalex,
              right - xoff * scalex,
              top - yoff * scaley,
              bottom - yoff * scaley,
              near, far);
}

The jittering values you choose should fall in an irregular pattern. In other words, it is undesirable to have the sample points line up in any direction. This reduces aliasing artifacts by making them ``noisy''. Selected subpixel jitter values, organized by the number of samples needed, are taken from the OpenGL Programming Guide, and are shown in Table 6. (Note that some of these patterns are a little more regular horizontally and vertically than is optimal.)


Table 6: Sample Jittering Values
Count Values
2 {0.25, 0.75}, {0.75, 0.25}
3 {0.5033922635, 0.8317967229}, {0.7806016275, 0.2504380877},
  {0.2261828938, 0.4131553612}

4 {0.375, 0.25}, {0.125, 0.75}, {0.875, 0.25}, {0.625, 0.75}

5 {0.5, 0.5}, {0.3, 0.1}, {0.7, 0.9}, {0.9, 0.3}, {0.1, 0.7}

6 {0.4646464646, 0.4646464646}, {0.1313131313, 0.7979797979},
  {0.5353535353, 0.8686868686}, {0.8686868686, 0.5353535353},
  {0.7979797979, 0.1313131313}, {0.2020202020, 0.2020202020}

8 {0.5625, 0.4375}, {0.0625, 0.9375}, {0.3125, 0.6875}, {0.6875, 0.8125},
  {0.8125, 0.1875}, {0.9375, 0.5625}, {0.4375, 0.0625}, {0.1875, 0.3125}

9 {0.5, 0.5}, {0.1666666666, 0.9444444444}, {0.5, 0.1666666666},
  {0.5, 0.8333333333}, {0.1666666666, 0.2777777777},
  {0.8333333333, 0.3888888888}, {0.1666666666, 0.6111111111},
  {0.8333333333, 0.7222222222}, {0.8333333333, 0.0555555555}

12 {0.4166666666, 0.625}, {0.9166666666, 0.875}, {0.25, 0.375},
  {0.4166666666, 0.125}, {0.75, 0.125}, {0.0833333333, 0.125}, {0.75, 0.625},
  {0.25, 0.875}, {0.5833333333, 0.375}, {0.9166666666, 0.375},
  {0.0833333333, 0.625}, {0.583333333, 0.875}

16 {0.375, 0.4375}, {0.625, 0.0625}, {0.875, 0.1875}, {0.125, 0.0625},
  {0.375, 0.6875}, {0.875, 0.4375}, {0.625, 0.5625}, {0.375, 0.9375},
  {0.625, 0.3125}, {0.125, 0.5625}, {0.125, 0.8125}, {0.375, 0.1875},
  {0.875, 0.9375}, {0.875, 0.6875}, {0.125, 0.3125}, {0.625, 0.8125}


Using the accumulation buffer, you can easily trade off quality and speed. For higher quality images, simply increase the number of scenes that are accumulated. Although it is simple to antialias the scene using the accumulation buffer, it is much more computationally intensive and probably slower than the polygon antialiasing method described above.


next up previous contents
Next: 10 Lighting Techniques Up: 9 Antialiasing Previous: 9.4 Antialiasing With Textures   Contents
2001-01-10