Lazy Foo' Productions


Antialiasing and Multisampling

Antialiasing and Multisampling screenshot

Last Updated: Aug 9th, 2012

Using OpenGL's built antialiasing and multisampling functionality, you can smooth out the edges of your polygon when they rasterize.
From main.cpp
    //Create Double Buffered Window with multisampled buffer
    glutInitDisplayMode( GLUT_DOUBLE | GLUT_MULTISAMPLE );
    glutInitWindowSize( SCREEN_WIDTH, SCREEN_HEIGHT );
    glutCreateWindow( "OpenGL" );
In order to use multisampling, you have to request a multisampled buffer from your windowing API. For freeGLUT, that means passing in GLUT_MULTISAMPLE to glutInitDisplayMode(). For other windowing APIs, look in your documentation on how to request a multisampled buffer.
From LUtil.h
//Aliasing methods
enum AliasMode
{
    ALIAS_MODE_ALIASED,
    ALIAS_MODE_ANTIALIASED,
    ALIAS_MODE_MULTISAMPLE
};
In this tutorial there's 3 ways we're going to render the triangle on the screen. Aliased means we're going to render the triangle with plain rasterization which leads to aliasing (the technical term for jaggies). Antialiased means OpenGL will smooth out the edges of the triangle. Multisampling is another type of antialiasing where we render with multiple samples per pixel.
From LUtil.cpp
//Aliasing
AliasMode gMode = ALIAS_MODE_ALIASED;
At the top of LUtil.cpp, we have a global variable that controls how we're rendering the triangle.
From LUtil.cpp
    //Set blending
    glEnable( GL_BLEND );
    glDisable( GL_DEPTH_TEST );
    glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );

    //Set antialiasing/multisampling
    glHint( GL_LINE_SMOOTH_HINT, GL_NICEST );
    glHint( GL_POLYGON_SMOOTH_HINT, GL_NICEST );
    glDisable( GL_LINE_SMOOTH );
    glDisable( GL_POLYGON_SMOOTH );
    glDisable( GL_MULTISAMPLE );
In order to use antialiasing and multisampling, you have to enable blending. This isn't much of an issue because we've been using blending for a while now.

Using glHint() we can tell the OpenGL driver how to do polygon smoothing antialiasing. Here we're telling the OpenGL driver to use the nicest line and polygon smoothing. Whether the driver will listen to our request is all up to the card vendor's (AMD, nVidia, Intel, etc) driver implementation.

Finally, we disable line/polygon smoothing and multisampling in our initGL() function. For this demo we want aliased polygons to be our default behavior.
From LUtil.cpp
bool loadMedia()
{
    return true;
}

void update()
{

}
Since we're rendering a plain polygon, the loadMedia() and update() functions don't do much.
From LUtil.cpp
void render()
{
    //Clear color
    glClear( GL_COLOR_BUFFER_BIT );

    //Start alias mode
    switch( gMode )
    {
        case ALIAS_MODE_ALIASED:
            glDisable( GL_LINE_SMOOTH );
            glDisable( GL_POLYGON_SMOOTH );
            glDisable( GL_MULTISAMPLE );
            break;

        case ALIAS_MODE_ANTIALIASED:
            glEnable( GL_LINE_SMOOTH );
            glEnable( GL_POLYGON_SMOOTH );
            glDisable( GL_MULTISAMPLE );
            break;

        case ALIAS_MODE_MULTISAMPLE:
            glDisable( GL_LINE_SMOOTH );
            glDisable( GL_POLYGON_SMOOTH );
            glEnable( GL_MULTISAMPLE );
            break;
    }
At the top of the render() function, we clear the screen as usual and then set the aliasing mode.

If we want the polygon to be aliased, smoothing and multisampling are disabled. If we want the polygon to be smoothed, we enable smoothing and disable multisampling. If we want to render things multisampled, we disable smoothing and enable multisampling.
From LUtil.cpp
    //Render Triangle
    glColor3f( 1.f, 1.f, 1.f );
    glBegin( GL_TRIANGLES );
     glVertex2f( SCREEN_WIDTH, 0.f );
     glVertex2f( SCREEN_WIDTH, SCREEN_HEIGHT );
     glVertex2f( 0.f, SCREEN_HEIGHT );
    glEnd();
For the sake of simplicity, we're using the slow immediate mode to render the triangle.
From LUtil.cpp
    //End alias mode
    switch( gMode )
    {
        case ALIAS_MODE_ANTIALIASED:
            glDisable( GL_LINE_SMOOTH );
            glDisable( GL_POLYGON_SMOOTH );
            break;
            
        case ALIAS_MODE_MULTISAMPLE:
            glDisable( GL_MULTISAMPLE );
            break;
    }

    //Update screen
    glutSwapBuffers();
}
After we're done rendering the triangle, we disable whatever smoothing/multisampling was used.

Finally, we swap the buffers to update the screen.
From LUtil.cpp
void handleKeys( unsigned char key, int x, int y )
{
    //If the user presses q
    if( key == 'q' )
    {
        //Cycle alias mode
        switch( gMode )
        {
            case ALIAS_MODE_ALIASED:
                printf( "Antialiased\n" );
                gMode = ALIAS_MODE_ANTIALIASED;
                break;

            case ALIAS_MODE_ANTIALIASED:
                printf( "Multisampled\n" );
                gMode = ALIAS_MODE_MULTISAMPLE;
                break;

            case ALIAS_MODE_MULTISAMPLE:
                printf( "Aliased\n" );
                gMode = ALIAS_MODE_ALIASED;
                break;
        }
    }
}
And in our handleKeys() function we cycle through the different aliasing modes.

When you run the program, you can zoom in to see how your OpenGL driver handles the polygon rendering.

aliased
This is rendering with aliased edges.

multisampled
This is rendering with multisampled buffer.


If you're wondering how using polygon smoothing looks, that's.... something I would like to know too. See, antialiasing via polygon smoothing was one of the earlier methods of antialiasing in OpenGL. Then multisampling came along. While it's part of the OpenGL spec, polygon smoothing isn't always there and my home rig doesn't support it. When we make a call with glHint, it's handled as a request, not an order.

These days, it's generally not a good idea to rely on polygon smoothing for antialiasing. If you want antialiasing done for you, you can use multisampling. Many developers today don't rely on API level multisampling and use their own methods via shaders. One method I've seen is using a gaussian blur on edges.

Start looking up image processing is you want to use your own method for antialiasing.