Homework 8: OpenGL Shading Language

Updated Last Year (11/1/2009)

In this homework you wil use OpenGL Shading Language to produce a water surface similar to the one from Homework 6 and also blend a leaf texture on top of the reflected image.

Homework 8 is due on Friday Dec. 3 at 11:59 pm

The GPU

Modern graphics cards have the ability to replace parts of the OpenGL pipeline with small programs called shaders. This is pretty much the only way to achieve really cool special effects in OpenGL; you can do a lot with the built-in functionality, but you are bounded by OpenGL unless you use shaders.

There are three kinds of shaders: vertex shaders operate on the vertices (obviously). They control things like vertex position (they replace transformations), normals, texture coordinates, lighting, fog, and pretty much anything you pass between glBegin and glEnd. Geometry shaders are used to generate extra vertices inside polygons. They can be used to add things like bumpiness to a surface. Geometry shaders are only available on the most modern graphics cards (i.e., not the ones in the lab), so we will not be working with them. Fragment shaders are basically used to draw the interior of a polygon. They operate on individual fragments (like pixels with extra data) and have full control over pixel color. They handle things such as texturing, per-pixel lighting, and advanced effects, but they generally don't participate in depth testing or blending between polygons.

When we combine a vertex shader, fragment shader, and an optional geometry shader, we have what OpenGL calls a program object.

In this lab, you will write a vertex shader and a fragment shader to achieve a simple effect that isn't possibly with "vanilla" OpenGL.

GLSL

The OpenGL Shading Language is a high-level language for creating vertex and fragment shaders. The language itself looks a tad like C. See the GLSL language specification for more details. A fairly good tutorial can be found at NeHe, but be aware that that page has a few typos. Also see the GLSL quick reference.

GLSL was approved by the OpenGL ARB to be part of OpenGL 2.0, but it was included in earlier versions as an extension. To use GLSL you're supposed to add the following to your source files:

   #define GL_GLEXT_PROTOTYPES
   #include <GL/gl.h>
   #include <GL/glu.h>
   #include <GL/glut.h>

However, please see the CS cluster-specific note below.

The relevant functions for this lab are

glCreateProgram
Generates an empty program object
glCreateShader
Creates an empty shader
glShaderSource
Loads GLSL source code for a shader
glCompileShader
Compiles the source code loaded with glShaderSource
glAttachShader
Attaches a shader to a program object
glLinkProgram
Links the shaders attached to a program object into a program
glGetProgramInfoLog
Fetches debugging information for a program, such as compilation error messages
glUseProgram
Sets the current program object. You can only use one program at a time, although multiple programs can exist. Pass 0 to disable shaders.
glGetUniformLocation
Fetches a handle for a uniform variable
glUniform[...]
Sets the value for a uniform variable

Don't worry too much about these if you stick with the template code. The template will set up your shader for you; you just have to write the GLSL code.

Textures in GLSL

Accessing textures from GLSL fragment shaders is fairly poorly-documented, so here's how you do it:

  1. Declare a uniform sampler2D object in the fragment shader.
  2. Get the handle of the sampler2D uniform you created with glGetUniformLocation.
  3. (Here comes the tricky part...) Use glActiveTexture with the parameter GL_TEXTUREi (i is an integer) to select a texture unit. Modern graphics cards can load multiple textures at the same time and then blend them together. We won't be using the blending part, but this is how we select the textures for the fragment shader to use.
  4. Bind the texture as you would normally.
  5. Use glUniform1i to set the texture unit number for the sampler2D object. DO NOT PASS THE TEXTURE NAME.

If you want to use more than one texture at the same time, repeat the above steps, changing GL_TEXTUREi each time. Also make sure to pass texture coordinates with glMultiTexCoord, rather than glTexCoord.

What your program should do

Your program should draw a rippling environment-mapped water surface with leaves blended on top using a vertex shader and a fragment shader. The water and leaf textures are provided. The inputs to the shaders are the following:

A key should toggle the render mode for the normals, defaulting to per-vertex normal calculation. In this case, the normals should be computed in the vertex shader, and the interpolated normals should be used for lighting in the fragment shader. In the other case, the normals should be computed per fragment, giving a somewhat smoother surface.

A textured cube floating over water

Your program should take the window size on the command line:

   glslRenderer <xRes> <yRes>

Include a README file with your code saying what you did and anything you think we need to know.

Strategy

Your vertex shader should do the following

Your fragment shader should do the following

Template code

For your convenience, a program to do most of this is provided. The program feeds a grid into OpenGL, the example vertex shader converts it into a deformed torus, and the fragment shader draws a grid of red and green lines on it. All you will have to do is replace the shader.

The provided code for this lab uses a display list for the water surface. This provides a substantial performance improvement over blasting the vertices across the bus every frame.

CS cluster-specific notes

Last year, in order for this program to work in the lab, you must link against the correct version of OpenGL; the default version (in /usr/lib) does not support shaders. The Makefile provided with the template handles this. If you write your own Makefile, keep this in mind.

The template code may work on the Linux machines in the lab. If it doesn't work, please let a TA know and try one of the machines by the windows.

Extra Credit

Here are some ideas: