Tutorial: Introduction to the use of shaders

Aims

  1. To learn the uses of vertex and fragment shaders

Capabilities

  1. Be able to load and make use of different vertex and fragment shaders

Exercises

In this tutorial:

  1. Compile and run the Orange book brick and particle system examples.
  2. Compile a program to load and use vertex and fragment shaders

Note that we use OpenGL Shading Language (GLSL) in this subject but others exist.

1: Build and run the Orange book brick and particle demos

Extract the brick and particle examples from the Orange book. Build and run them. (-lGLU may need to be added to the makefile).

Look at particle.vert and identify the code that moves the particle. When might each particle respawn?

For the brick demo change the model which is being textured to a sphere - follow the instructions given when the program runs.

Modify the tessellation of the sphere (stacks and slices in glutSolidSphere), reducing it. What difference do you see, in the highlight in particular, as tessellation is reduced?

2: Create your own shader

Either use your code from last weeks tutorial or add glutSolidTeapot to its base code. Anything will do as long as it draws some polygonal geometry. Extract shaders.tgz and add the source files to your makefile.

Create two files, shader.vert and shader.frag:
//shader.vert
void main(void)
{
	vec4 osVert = gl_Vertex;
	vec4 esVert = gl_ModelViewMatrix * osVert;
	vec4 csVert = gl_ProjectionMatrix * esVert;
	gl_Position = csVert;
}
    
//shader.frag
void main (void)
{
	gl_FragColor = vec4(0, 0, 1, 1);
}
    

The vertex shader transforms the vertex by both modelview and projection matrices. This is what allows you to move objects with glTranslatef and also applies the perspective projection from gluPerspective.

The fragment program will colour each pixel rendered blue. gl_FragColor is the main output from fragment programs.

Call getShader (in main!) to load and compile your shaders. Then call glUseProgram before you draw your geometry in display(). Run the program and make sure the geometry draws with it's new colour from the fragment shader.

Create a varying float distance variable in both vertex and fragment shaders, set to the eye-space depth -esVert.z in the vertex shader. This value will be interpolated for each rasterized fragment.

In the fragment shader, set the output colour to represent depth. This could be done simply with gl_FragColor.rgb = vec3(distance) or with a custom colour ramp, interpolating individual channels. GLSL offers a full range of maths functions and utilities - see the GLSL reference at the bottom of the page.

There are many ways to shade objects. A common method is to use pre-computed geometry normals for lighting calculations. This will be covered in next weeks tutorial.

Resources