We are now ready to begin exploring the various effects that can be applied in the fragment shader (also known as the pixel shader). In this stage of the pipeline, all the original geometry information is lost and effects are only performed on a per pixel basis. None the less, there is still a significant amount of scene enhancement that can be accomplished in this stage. The first effect we will explore in this lab is alpha blending. This effect combines the pixel colors currently in the framebuffer with those from the object being currently rendered to produce the appearance of translucency/transparency, i.e. objects can be seen through other objects.

Up to this point, we have only been using the first three components when applying colors - the R, G, and B channels. However, all colors in OpenGL are treated as 32-bit values with the last byte representing the alpha (or A) channel. This channel represents the opacity (or equivalently transparency) of the color. So far all of our alpha channels have been set to 1, meaning that all our objects are opaque, i.e. solid. An alpha channel of 0 would represent a completely transparent object (such as glass). By using values between 0 and 1, we get translucent objects where the final color of the pixel is a blend of the colors of both objects with the amount of blending determined by various parameters in the application.

0. Getting Started

Download CS370_Lab17.zip, saving it into the labs directory.

Double-click on CS370_Lab17.zip and extract the contents of the archive into a subdirectory called CS370_Lab17

Navigate into the CS370_Lab17 directory and double-click on CS370_Lab17.sln (the file with the little Visual Studio icon with the 12 on it).

If the source file is not already open in the main window, open the source file by expanding the Source Files item in the Solution Explorer window and double-clicking blendedCone.cpp.

If the header file is not already open in the main window, open the header file by expanding the Header Files item in the Solution Explorer window and double-clicking materials.cpp.

1. Alpha Channel

One common place to set the alpha channel is when creating a material (i.e. in materials.h). Thus we can make a translucent object by simply adjusting the alpha channel for the three lighting components.

Tasks

2. Alpha Blending

In order to use alpha blending we simply enable it (usually in the initializations) using:

glEnable(GL_BLEND);

Once blending is enabled, we must then specify how we wish OpenGL to combine the colors by setting a blending function for both the source (the pixel from the object being rendered) and the destination (the current pixel in the framebuffer). The blending function is a linear function with the proportion for each part set using:

glBlendFunc(src_val, dest_val);

where src_val, and dest_val are the factors used in the blending function. Two common src_val/dest_val pairs are (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) and (GL_SRC_ALPHA, GL_ONE).

GL_SRC_ALPHA/GL_ONE_MINUS_SRC_ALPHA

For source and destination colors given by (Rs,Gs,Bs,As) and (Rd,Gd,Bd,Ad), these blending factors combine the colors as follows

image

These factors guarantee that the color channels remain bounded within the range [0.0,1.0] and hence will appear more or less correct. However, the problem is that to use these factors properly, rendering order is important. In particular, objects must be rendered from back-to-front (i.e. using a painter's algorithm) to produce the proper final color. This is typically not difficult for static scenes, but for ones where the object positions are changing either relative to each other or relative to the camera, maintaing proper rendering order can be tricky.

GL_SRC_ALPHA/GL_ONE

For source and destination colors given by (Rs,Gs,Bs,As) and (Rd,Gd,Bd,Ad), these blending factors combine the colors as follows

image

These factors guarantee that the same color is rendered regardless of order and hence is much better for dynamic scenes. However, since the final color is simply the total sum of all the object colors, the final color may saturate in one or several of the color channels, i.e. be greater than one and hence be clipped to 1.0 when rendered. Thus the final color may not be the expected color (or may simply be white if all the color channels saturate).

Tasks

3. Quadric Objects

Creating even simple geometries by hand is usually a tedious process. Fortunately the OpenGL utility library (glu, which is available on most systems) provides a mechanism called quadrics for creating many common geometric objects, e.g. spheres, cylinders/cones, disks, etc. In order to use quadrics, we must first declare a pointer to a GLUQuadricObj variable as:

GLUQuadricObj *quadric;

where quadric is the variable name of the quadric. Note: We only need to define one pointer (but may wish to use several for readability or to set different rendering properties) which can then be used to create multiple (different) quadric objects.

Next we need to initialize the generic quadric object using the call:

quadric = gluNewQuadric();

where quadric is the variable declared previously.

We can then set various properties of the quadric that affect how they will be rendered. For example, we can set that the object be rendered as either solid, wireframe, etc. using:

gluQuadricDrawStyle(quadric,draw_mode);

where quadric is the quadric variable and draw_mode is one of the symbolic constants GLU_POINT, GLU_LINE, GLU_FILL, or GLU_SILHOUETTE.

Furthermore if we are using lighting, we can specify how normals should be generated for the quadric using:

gluQuadricNormals(quadric,norm_mode);

where quadric is the quadric variable and norm_mode is one of the symbolic constants GLU_SMOOTH, GLU_FLAT, or GLU_NONE.

Finally when we wish to render the quadric (in render_scene( ) or a display list) we simply call the appropriate quadric function gluSphere( ), gluCylinder( ), etc. with appropriate arguments - see section 4.7.1 of OpenGL: A Primer for more details.

NOTE: Later we will see how texture coordinates can also be automatically generated for quadric objects.

Tasks

4. GLUT Objects

Like quadrics, GLUT also provides many common objects such as spheres, cones, torii, various polyhedra, and the famous Utah Teapot. These objects are easier to create than quadrics but do not have as much flexibility in their final rendered appearance. Also since GLUT is a separate package that is usually not installed on most systems, using them will make the program far less portable. To create a GLUT object, simply call the desired function, e.g. glutSolidSphere( ), glutSolidTeapot( ), etc. with appropriate parameters - see section 4.7.2 of OpenGL: A Primer for more details.

Tasks

4. Depth Test and Alpha Blending

Normally we simply enable the depth test in order to perform hidden surface removal such that the closest object is the one that appears in the final scene. However since alpha blending occurs in the fragment processor if the depth test is enabled when translucent objects are rendered, they may be clipped before reaching the fragment processor. Hence whenever a translucent object is rendered, the depth test must be temporarily disabled using:

glDepthMask(GL_FALSE);

After rendering the translucent object, the depth test should be re-enabled to allow proper rendering of subsequent opaque objects. This is simply done using

glDepthMask(GL_TRUE);

Tasks

Compiling and running the program

Once you have completed typing in the code, you can build and run the program in one of two ways:

(On Linux/OSX: In a terminal window, navigate to the directory containing the source file and simply type make. To run the program type ./blendedCone.exe)

The output should look similar to below

image

To quit the program simply close the window.

You should experiment with different blending factors for both the source and destination to see what effects they produce. Also you can try out different rendering properties for the quadrics to see what they do. Even though alpha blending occurs in the fragment processor, it is still using pixels generated by the pipeline, i.e. that were produced by object geometry.