Blending

Simple Transparency

Most special effects in OpenGL rely on some type of blending. Blending is used to combine the color of a given pixel that is about to be drawn with the pixel that is already on the screen. How the colors are combined is based on the alpha value of the colors, and/or the blending function that is being used. Alpha is a 4th color component usually specified at the end. In the past you have used GL_RGB to specify color with 3 components. GL_RGBA can be used to specify alpha as well. In addition, we can use glColor4f() instead of glColor3f().

Most people think of Alpha as how opaque a material is. An alpha value of 0.0 would mean that the material is completely transparent. A value of 1.0 would be totally opaque.

The Blending Equation

If you are uncomfortable with math, and just want to see how to do transparency, skip this section. If you want to understand how blending works, this section is for you.

(Rs Sr + Rd Dr, Gs Sg + Gd Dg, Bs Sb + Bd Db, As Sa + Ad Da)

OpenGL will calculate the result of blending two pixels based on the above equation. The s and d subscripts specify the source and destination pixels. The S and D components are the blend factors. These values indicate how you would like to blend the pixels. The most common values for S and D are (As, As, As, As) (AKA source alpha) for S and (1, 1, 1, 1) - (As, As, As, As) (AKA one minus src alpha) for D. This will yield a blending equation that looks like this:

(Rs As + Rd (1 - As), Gs As + Gd (1 - As), Bs As + Bd (1 - As), As As + Ad (1 - As))

This equation will yield transparent/translucent style effects.

Blending in OpenGL

We enable blending just like everything else. Then we set the equation, and turn off depth buffer writing when drawing transparent objects, since we still want objects behind the translucent shapes to be drawn. This isn't the proper way to blend, but most the time in simple projects it will work fine. Rui Martins Adds: The correct way is to draw all the transparent (with alpha < 1.0) polys after you have drawn the entire scene, and to draw them in reverse depth order (farthest first). This is due to the fact that blending two polygons (1 and 2) in different order gives different results, i.e. (assuming poly 1 is nearest to the viewer, the correct way would be to draw poly 2 first and then poly 1. If you look at it, like in reality, all the light comming from behind these two polys (which are transparent) has to pass poly 2 first and then poly 1 before it reaches the eye of the viewer. You should SORT THE TRANSPARENT POLYGONS BY DEPTH and draw them AFTER THE ENTIRE SCENE HAS BEEN DRAWN, with the DEPTH BUFFER ENABLED, or you will get incorrect results. I know this sometimes is a pain, but this is the correct way to do it.

We'll be using the code from the last tutorial. We start off by adding two new variables to the top of the code. I'll rewrite the entire section of code for clarity.

#include <windows.h>					// Header File For Windows
#include <stdio.h>					// Header File For Standard Input/Output
#include <gl\gl.h>					// Header File For The OpenGL32 Library
#include <gl\glu.h>					// Header File For The GLu32 Library
#include <gl\glaux.h>					// Header File For The GLaux Library

HDC		hDC=NULL;				// Private GDI Device Context
HGLRC		hRC=NULL;				// Permanent Rendering Context
HWND		hWnd=NULL;				// Holds Our Window Handle
HINSTANCE	hInstance;				// Holds The Instance Of The Application

bool	keys[256];					// Array Used For The Keyboard Routine
bool	active=TRUE;					// Window Active Flag Set To TRUE By Default
bool	fullscreen=TRUE;				// Fullscreen Flag Set To Fullscreen Mode By Default
bool	light;						// Lighting ON/OFF
bool    blend;						// Blending OFF/ON? ( NEW )
bool	lp;						// L Pressed?
bool	fp;						// F Pressed?
bool	bp;						// B Pressed? ( NEW )

GLfloat	xrot;						// X Rotation
GLfloat	yrot;						// Y Rotation
GLfloat xspeed;						// X Rotation Speed
GLfloat yspeed;						// Y Rotation Speed

GLfloat	z=-5.0f;					// Depth Into The Screen

GLfloat LightAmbient[]=  { 0.5f, 0.5f, 0.5f, 1.0f };	// Ambient Light Values
GLfloat LightDiffuse[]=	 { 1.0f, 1.0f, 1.0f, 1.0f };	// Diffuse Light Values
GLfloat LightPosition[]= { 0.0f, 0.0f, 2.0f, 1.0f };	// Light Position

GLuint	filter;						// Which Filter To Use
GLuint	texture[3];					// Storage for 3 textures

LRESULT	CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);	// Declaration For WndProc

Move down to LoadGLTextures(). Find the line that says: if (TextureImage[0]=LoadBMP("Data/Crate.bmp")). Change it to the line below. We're using a stained glass type texture for this tutorial instead of the crate texture.

	if (TextureImage[0]=LoadBMP("Data/glass.bmp"))	// Load The Glass Bitmap ( MODIFIED )

Add the following two lines somewhere in the InitGL() section of code. What this line does is sets the drawing brightness of the object to full brightness with 50% alpha (opacity). This means when blending is enabled, the object will be 50% transparent. The second line sets the type of blending we're going to use.

Rui Martins Adds: An alpha value of 0.0 would mean that the material is completely transparent. A value of 1.0 would be totally opaque.

	glColor4f(1.0f,1.0f,1.0f,0.5f);			// Full Brightness, 50% Alpha ( NEW )
	glBlendFunc(GL_SRC_ALPHA,GL_ONE);		// Blending Function For Translucency Based On Source Alpha Value ( NEW )

Look for the following section of code, it can be found at the very bottom of lesson seven.

	if (keys[VK_LEFT])				// Is Left Arrow Being Pressed?
	{
		yspeed-=0.01f;				// If So, Decrease yspeed
	}

Right under the above code, we want to add the following lines. The lines below watch to see if the 'B' key has been pressed. If it has been pressed, the computer checks to see if blending is off or on. If blending is on, the computer turns it off. If blending was off, the computer will turn it on.

	if (keys['B'] && !bp)				// Is B Key Pressed And bp FALSE?
	{
		bp=TRUE;				// If So, bp Becomes TRUE
		blend = !blend;				// Toggle blend TRUE / FALSE	
		if(blend)				// Is blend TRUE?
		{
			glEnable(GL_BLEND);		// Turn Blending On
			glDisable(GL_DEPTH_TEST);	// Turn Depth Testing Off
		}
		else					// Otherwise
		{
			glDisable(GL_BLEND);		// Turn Blending Off
			glEnable(GL_DEPTH_TEST);	// Turn Depth Testing On
		}
	}
	if (!keys['B'])					// Has B Key Been Released?
	{
		bp=FALSE;				// If So, bp Becomes FALSE
	}

But how can we specify the color if we are using a texture map? Simple, in modulated texture mode, each pixel that is texture mapped is multiplied by the current color. So, if the color to be drawn is (0.5, 0.6, 0.4), we multiply it times the color and we get (0.5, 0.6, 0.4, 0.2) (alpha is assumed to be 1.0 if not specified).

Thats it! Blending is actually quite simple to do in OpenGL.

Note (11/13/99)

I ( NeHe ) have modified the blending code so the output of the object looks more like it should. Using Alpha values for the source and destination to do the blending will cause artifacting. Causing back faces to appear darker, along with side faces. Basically the object will look very screwy. The way I do blending may not be the best way, but it works, and the object appears to look like it should when lighting is enabled. Thanks to Tom for the initial code, the way he was blending was the proper way to blend with alpha values, but didn't look as attractive as people expected :)

The code was modified once again to address problems that some video cards had with glDepthMask(). It seems this command would not effectively enable and disable depth buffer testing on some cards, so I've changed back to the old fashioned glEnable and Disable of Depth Testing.

Alpha From Texture Map.

The alpha value that is used for transparency can be read from a texture map just like color, to do this, you will need to get alpha into the image you want to load, and then use GL_RGBA for the color format in calls to glTexImage2D().

Questions?

If you have any questions, feel free to contact me at stanis@cs.wisc.edu.

Tom Stanis

Jeff Molofee (NeHe)

* DOWNLOAD Visual C++ Code For This Lesson.

* DOWNLOAD Borland C++ Builder 6 Code For This Lesson. ( Conversion by Christian Kindahl )
* DOWNLOAD C# Code For This Lesson. ( Conversion by Brian Holley )
* DOWNLOAD Code Warrior 5.3 Code For This Lesson. ( Conversion by Scott Lupton )
* DOWNLOAD Cygwin Code For This Lesson. ( Conversion by Stephan Ferraro )
* DOWNLOAD D Language Code For This Lesson. ( Conversion by Familia Pineda Garcia )
* DOWNLOAD Delphi Code For This Lesson. ( Conversion by Michal Tucek )
* DOWNLOAD Dev C++ Code For This Lesson. ( Conversion by Dan )
* DOWNLOAD Euphoria Code For This Lesson. ( Conversion by Evan Marshall )
* DOWNLOAD Game GLUT Code For This Lesson. ( Conversion by Milikas Anastasios )
* DOWNLOAD GLUT Code For This Lesson. ( Conversion by Andy Restad )
* DOWNLOAD Irix Code For This Lesson. ( Conversion by Lakmal Gunasekara )
* DOWNLOAD Java Code For This Lesson. ( Conversion by Jeff Kirby )
* DOWNLOAD Jedi-SDL Code For This Lesson. ( Conversion by Dominique Louis )
* DOWNLOAD JoGL Code For This Lesson. ( Conversion by Pepijn Van Eeckhoudt )
* DOWNLOAD LCC Win32 Code For This Lesson. ( Conversion by Robert Wishlaw )
* DOWNLOAD Linux Code For This Lesson. ( Conversion by Richard Campbell )
* DOWNLOAD Linux/GLX Code For This Lesson. ( Conversion by Mihael Vrbanec )
* DOWNLOAD Linux/SDL Code For This Lesson. ( Conversion by Ti Leggett )
* DOWNLOAD LWJGL Code For This Lesson. ( Conversion by Mark Bernard )
* DOWNLOAD Mac OS Code For This Lesson. ( Conversion by Anthony Parker )
* DOWNLOAD Mac OS X/Cocoa Code For This Lesson. ( Conversion by Bryan Blackburn )
* DOWNLOAD MASM Code For This Lesson. ( Conversion by Nico (Scalp) )
* DOWNLOAD Visual C++ / OpenIL Code For This Lesson. ( Conversion by Denton Woods )
* DOWNLOAD Power Basic Code For This Lesson. ( Conversion by Angus Law )
* DOWNLOAD Pelles C Code For This Lesson. ( Conversion by Pelle Orinius )
* DOWNLOAD Python Code For This Lesson. ( Conversion by Ryan Showalter )
* DOWNLOAD Scheme Code For This Lesson. ( Conversion by Brendan Burns )
* DOWNLOAD Solaris Code For This Lesson. ( Conversion by Lakmal Gunasekara )
* DOWNLOAD Visual Basic Code For This Lesson. ( Conversion by Peter De Tagyos )
* DOWNLOAD Visual Fortran Code For This Lesson. ( Conversion by Jean-Philippe Perois )
* DOWNLOAD Visual Studio .NET Code For This Lesson. ( Conversion by Grant James )

 

< Lesson 07Lesson 09 >