Blending
What is the difference between transparent,
translucent, and blended primitives?
A transparent
physical material shows objects behind it as unobscured and doesn't reflect
light off its surface. Clear glass is a nearly transparent material.
Although glass allows most light to pass through unobscured, in reality it
also reflects some light. A perfectly transparent material is completely
invisible.
A
translucent physical material
shows objects behind it, but those objects are obscured by the translucent
material. In addition, a translucent material reflects some of the light
that hits it, making the material visible. Physical examples of translucent
materials include sheer cloth, thin plastic, and smoked glass.
Transparent and translucent are often used synonymously
An
opaque material is one that is
neither transparent nor translucent. It obscures everything behind it.
Blending is OpenGL's mechanism
for combining color already in the framebuffer with the color of the
incoming primitive. Blending is frequently used to simulate translucent
physical materials. One example is rendering the smoked glass windshield of
a car. The driver and interior are still visible, but they are obscured by
the dark color of the smoked glass.
"Blending" allows us to specify a blending function that combines color values from a source and a destination. The final effect is that parts of the scene appear translucent.
We have already seen alpha values (alpha is the A in RGBA), but they've
always been 1.0 (opaque) and they haven't been discussed. Alpha values are
specified with glColor*(), when using glClearColor() to
specify a clearing color, and when specifying certain lighting parameters
such as a material property or light-source intensity.
When
blending is enabled, the alpha value is used to combine the color value of
the fragment being processed (referred to as the source) with that of the
pixel already stored in the framebuffer (referred to as the destination).
Blending lpha values can also be used in the alpha test to accept or reject
a fragment based on its alpha value.
Without
blending, each new fragment overwrites any existing color values in the
framebuffer, as though the fragment is opaque. With blending, you can
control how much of the existing color value should be combined with the new
fragment's value.
The most natural way to think of blending operations is to view the RGB components of a fragment as representing its color, and the alpha component as representing opacity. Thus, transparent or translucent surfaces have lower opacity than opaque ones.
For example, if you're viewing an object through green glass, the color you see is partly green from the glass and partly the color of the object. The percentage varies depending on the transmission properties of the glass: If the glass transmits 80 percent of the light that strikes it (that is, has an opacity of 20 percent), the color you see is a combination of 20 percent glass color and 80 percent of the color of the object behind it. You can easily imagine situations with multiple translucent surfaces. If you look at an automobile, for instance, its interior has one piece of glass between it and your viewpoint; some objects behind the automobile are visible through two pieces of glass.
Source and Destination Factors
During blending, color values of the incoming fragment
(the source) are combined with the color values of the corresponding
currently stored pixel (the destination) in a two-stage process.
First, you specify how to compute source and destination factors. These
factors are RGBA quadruplets that are multiplied by each component of the R,
G, B, and A values in the source and destination, respectively. Then, the
corresponding components in the two sets of RGBA quadruplets are added. To
show this mathematically, let
Sr, Sg, Sb, Sa and Dr, Dg, Db, Da Source red, source green, source blue, source alha et
where S denotes source (new entry) and D denotes destination (already there)
Then, the final, blended RGBA values are given by
RsSr+RdDr, GsSg+GdDg, BsSb+BdDb, AsSa+AdDa (red source)x(red source blending factor) + (red destination)x(red destination blending factor) etc
(alpha source)x(alpha source blending factor) + (alpha destination)x(alpha destination blending factor)
Each component of this quadruplet is eventually clamped to [0,1].
How are the the source and destination blending factors are generated. You
use glBlendFunc() to supply two constants: one that specifies how the
source factor should be computed, and one that indicates how the destination
factor should be computed. Also, to have blending take effect, you need to
enable it:
glEnable(GL_BLEND);
Use glDisable() with GL_BLEND to disable blending.
Also, note that using the constants GL_ONE (source) and GL_ZERO
(destination) gives the same results as when blending is disabled; these
values are the default.void glBlendFunc(GLenum sfactor, GLenum
dfactor)
Controls how color values in the fragment being processed (the source) are
combined with those already stored in the framebuffer (the destination). The
argument sfactor indicates how to compute a source blending factor;
dfactor indicates how to compute a destination blending factor. The
possible values for these arguments are explained below . The blend factors
are assumed to lie in the range [0,1]; after the color values in the source
and destination are combined, they're clamped to the range [0,1].
In the
following table , the RGBA values of the source and destination are
indicated with the subscripts s and d, respectively. Also, division of an
RGBA quadruplet by a scalar means dividing each component by that value.
Similarly, subtraction of quadruplets means subtracting them componentwise.
The Relevant Factor column indicates whether the corresponding constant can
be used to specify the source or destination blend factor.
|
Source and Destination Blending Factors |
||
|
Constant |
Relevant Factor |
Computed Blend Factor |
|
GL_ZERO |
source or destination |
(0, 0, 0, 0) |
|
GL_ONE |
source or destination |
(1, 1, 1, 1) |
|
GL_DST_COLOR |
source |
(Rd, Gd, Bd, Ad) |
|
GL_SRC_COLOR |
destination |
(Rs, Gs, Bs, As) |
|
GL_ONE_MINUS_DST_COLOR |
source |
(1, 1, 1, 1)-(Rd, Gd, Bd, Ad) |
|
GL_ONE_MINUS_SRC_COLOR |
destination |
(1, 1, 1, 1)-(Rs, Gs, Bs, As) |
|
GL_SRC_ALPHA |
source or destination |
(As, As, As, As) |
|
GL_ONE_MINUS_SRC_ALPH A |
source or destination |
(1, 1, 1, 1)-(As, As, As, As) |
|
GL_DST_ALPHA |
source or destination |
(Ad, Ad, Ad, Ad) |
|
GL_ONE_MINUS_DST_ALPH A |
source or destination |
(1, 1, 1, 1)-(Ad, Ad, Ad, Ad) |
|
GL_SRC_ALPHA_SATURATE |
source |
(f, f, f, 1); f=min(As, 1-Ad) |
Blending Example
This program draws several overlapping filled polygons to demonstrate the effect order has on alpha blending results. Use the 't' key to toggle the order of drawing polygons. Which one was drawn first?
![]() |
![]() |
#include <GL/glut.h>
#include <stdlib.h>
static int leftFirst = GL_TRUE;
//Initialize alpha blending function.
static void init(void)
{
glEnable (GL_BLEND);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glShadeModel (GL_FLAT);
glClearColor (0.0, 0.0, 0.0, 0.0);
}
static void drawLeftTriangle(void)
{
/* draw yellow triangle on LHS of screen */
glBegin (GL_TRIANGLES);
glColor4f(1.0, 1.0, 0.0, 0.75); //what is the purpose of this line of code (exercise 2)
glVertex3f(0.1, 0.9, 0.0);
glVertex3f(0.1, 0.1, 0.0);
glVertex3f(0.7, 0.5, 0.0);
glEnd();
}
static void drawRightTriangle(void)
{
/* draw cyan triangle on RHS of screen */
glBegin (GL_TRIANGLES);
glColor4f(0.0, 1.0, 1.0, 0.75); //what is the purpose of this line of code? (exercise 2)
glVertex3f(0.9, 0.9, 0.0);
glVertex3f(0.3, 0.5, 0.0);
glVertex3f(0.9, 0.1, 0.0);
glEnd();
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT);
if (leftFirst)
{
drawLeftTriangle();
drawRightTriangle();
}
else
{
drawRightTriangle();
drawLeftTriangle();
}
glFlush();
}
void reshape(int w, int h)
{
glViewport(0, 0, (GLsizei) w, (GLsizei) h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (w <= h)
gluOrtho2D (0.0, 1.0, 0.0, 1.0*(GLfloat)h/(GLfloat)w);
else
gluOrtho2D (0.0, 1.0*(GLfloat)w/(GLfloat)h, 0.0, 1.0);
}
void keyboard(unsigned char key, int x, int y)
{
switch (key)
{
case 't':
case 'T':
leftFirst = !leftFirst;
glutPostRedisplay();
break;
case 27: /* Escape key */
exit(0);
break;
default:
break;
}
}
//Main Loop. Open window with initial window size, title bar, RGBA display mode, and handle input events.
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize (200, 200);
glutCreateWindow (argv[0]);
init();
glutReshapeFunc (reshape);
glutKeyboardFunc (keyboard);
glutDisplayFunc (display);
glutMainLoop();
return 0;
Example 2: Rotating Cubes (smaller inside a larger)

#include
<GL/glut.h>
#include
<GL/gl.h>
GLfloat
angle = 0.0;
void
cube (void)
{
//setting the axis about which to rotate
glRotatef(angle, 1.0, 0.0, 0.0);
//x axis
glRotatef(angle, 0.0, 1.0, 0.0);
//y axis
glRotatef(angle, 0.0, 0.0, 1.0);
//z axis
glColor4f(1.0, 0.0, 0.0, 0.2);
//set the color and alpha of the larger cube
glutSolidCube(2);
//draw larger solid cube
glColor4f(0.0, 1.0, 0.0, 0.5);
//set the color and alpha of the smaller cube
glutSolidCube(1);
//draw smaller solid cube
}
void
display (void)
{
glClearColor (0.0,0.0,0.0,1.0);
//set the background color
glClear (GL_COLOR_BUFFER_BIT);
glEnable(GL_BLEND); //enable the blending
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//set the blend function
glLoadIdentity();
//clear the
screen before rendering
gluLookAt (0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0,
0.0);
//camera location: 5 along positive z, positive
up
cube();
//call the above cube function
glutSwapBuffers();
angle ++;
//increment
the angle by 1
}
void
reshape (int w, int h)
{
glViewport (0, 0, (GLsizei)w, (GLsizei)h);
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
//clear the screen before rendering
gluPerspective (60, (GLfloat)w / (GLfloat)h, 1.0,
100.0);
glMatrixMode (GL_MODELVIEW);
}
int main
(int argc, char **argv)
{
glutInit (&argc, argv);
glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowSize (500, 500);
glutInitWindowPosition (100, 100);
glutCreateWindow ("Blending Example");
glutDisplayFunc (display);
glutIdleFunc (display);
//function to be executed if no other events
are pending
glutReshapeFunc (reshape);
glutMainLoop ();
return 0;
}
Change Example 1 above as follows
Change the background to light blue
Have a Red triangle overlapping a Green sphere
Part a: Run the program for a constant (see above) of GL_DST_COLOR with the sphere being drawn first
Part b: Run the program for a constant GL_SRC_COLOR with the sphere being drawn first
Part c: Run the program for a constant of GL_ONE_MINUS_DST_COLOR with the triangle being drawn first
What is the purpose of the following lines of code used in the program?
glColor4f(1.0, 1.0, 0.0, 0.75); glColor4f(0.0, 1.0, 1.0, 0.75);