Lazy Foo' Productions

Antialiasing and Multisampling

Last Updated 8/09/12
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.


This is rendering with aliased edges.


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.
Download the media and source code for this tutorial here.
Back to OpenGL Tutorials