Lab 3: Virtual world and specular shading

Goal: In this lab, you will expand your view to a richer virtual world, including herarcical models and a skybox. You will also implement the Phong lighting model.

Note: I expect this lab to be relatively demanding, parts 3 and 4 in particular. Please let me know if anything is incomplete, misleading or harder than it should. (See below for a draft for a revision of part 4 in order to reduce the risk of mistakes, as of 12-02-19.)

Lab files:

lab3.zip

Mac users will need the updated MicroGlut, see the main lab page.

If you run into problems, there are several resources. You have your textbook. OpenGL Reference Pages describe all the OpenGL API functions. OpenGL Shading Language Specification (found via http://www.opengl.org/documentation/specs/, "OpenGL Shading Language Specification") describes GLSL.


1) Hierarcical modelling, the windmill

In the files from lab 2, there is a windmill in two parts, the mill and the wings. Build a working windmill from the parts. Four wings should be placed at the appropriate place and rotate around it. Create appropriate rotation and translation matrices to make suitable model-to-world transformations.

Questions:


2) Manual viewing controls

The "look-at" function is useful for more than placing the camera in some fixed place. You can use glutPassiveMotionFunc to write a control based on mouse movements. The function glutPassiveMotionFunc() takes a callback argument, a pointer to a function that accepts the x and y coordinates of the mouse as parameters. For keyboard controls, there are GLUT functions for accepting keydown and keyup events, but for many purposes you are better off with knowing what keys are presently down. That is provided in the utility module. This overrides the key-up and key-down callbacks so you can not use them. You initializes this with initKeymapManager(), and after that you can check any key with keyIsDown(), e.g. if (keyIsDown('a')) { (something happens) }.

Questions:


3) Virtual world and skybox

Using the manual controls above, you should expand your virtual universe to a simple "virtual world" with a set of basic features.

Your program is growing now. You may want to look into ways to structure it a bit. There are many ways to do that.

Questions:


4) Specular shading, external light sources

Now you have a nice scene but you need better light. Implement specular Phong shading in your shaders. Not only should it include a specular component, but it should also do that using light sources that are specified by the CPU. (This is a challenging task, but quite rewarding.)

Here are specifications of four light sources:

OLD SPECIFICATION (WORKING BUT CAN CAUSE TROUBLE, SEE BELOW):

// Color r, g, b and specularity
GLfloat lightSourcesColors[] = { 1.0f, 0.0f, 0.0f, 10.0f, // Red light
                                        0.0f, 1.0f, 0.0f, 20.0f, // Green light
                                        0.0f, 0.0f, 1.0f, 60.0f, // Blue light
                                        1.0f, 1.0f, 1.0f, 5.0f }; // White light

// Light source direction x, y, z and an unused component (used for indicating positional or directional light)
GLfloat lightSourcesDirections[] = { 5.0f, 0.0f, 0.0f, 0.0f, // Red light along X
                                        0.0f, 0.0f, 5.0f, 0.0f, // Green light along Z
                                        -1.0f, 0.0f, 0.0f, 1.0f, // Blue light along X
                                        0.0f, 0.0f, -1.0f, 1.0f }; // White light along Z

The red and green light sources should be positional, the other directional. All four should be implemented. This information needs to be uploaded to the fragment shader as uniform data.

The fourth component of the color is the specularity, the exponent in the Phong model.

You may upload the entire matrices or as vector as you please. If you upload as matrices, you may get vectors by columns. If your white light source is extremely strong, that is an indication of that problem. Then you have to read out your vectors differently. Try forming a vec4 by reading separate components.

NEW SPECIFICATION:

The data above has one major problem: Since I defined the data as two 4x4 matrices, it is tempting to treat the data as matrices, but this gave some problems. You can easily get into problems where the matrix is transposed compared to what you think it should be. Also, it was a mistake to put the positional light sources at height 0; If they are some distance above the ground, they will be visible in a typical ground plane which helps a lot.

Here is an alternate formulation, almost the same data (only adding height of the positional lights) but now avoiding 4x4 matrices:

Point3D lightSourcesColorsArr[] = { {1.0f, 0.0f, 0.0f}, // Red light
                                 {0.0f, 1.0f, 0.0f}, // Green light
                                 {0.0f, 0.0f, 1.0f}, // Blue light
                                 {1.0f, 1.0f, 1.0f} }; // White light

GLfloat specularExponent[] = {10.0, 20.0, 60.0, 5.0};
GLint isDirectional[] = {0,0,1,1};

Point3D lightSourcesDirectionsPositions[] = { {10.0f, 5.0f, 0.0f}, // Red light, positional
                                       {0.0f, 5.0f, 10.0f}, // Green light, positional
                                       {-1.0f, 0.0f, 0.0f}, // Blue light along X
                                       {0.0f, 0.0f, -1.0f} }; // White light along Z

Upload to shader:

glUniform3fv(glGetUniformLocation(program, "lightSourcesDirPosArr"), 4, &lightSourcesDirectionsPositions[0].x);
glUniform3fv(glGetUniformLocation(program, "lightSourcesColorArr"), 4, &lightSourcesColorsArr[0].x);
glUniform1fv(glGetUniformLocation(program, "specularExponent"), 4, specularExponent);
glUniform1iv(glGetUniformLocation(program, "isDirectional"), 4, isDirectional);

Thus, I upload as arrays of three-component vectors and arrays of scalars. Declarations in shader:

uniform vec3 lightSourcesDirPosArr[4];
uniform vec3 lightSourcesColorArr[4];
uniform float specularExponent[4];
uniform bool isDirectional[4];

END OF REVISION

Debugging light like this requires some care. Take special care in keeping track on what coordinate system you work in. Model data starts in model coordinates, light sources are given in world coordinates. All lighting calculations take place in any coordinate system, model, world or view (camera) coordinates (not projected though) but you must decide which one. Select one and stick to it. I recommend that you use view coordinates. Make sure normal vectors, light direction and viewing direction are all given in the same coordinate system.

The viewing direction requires that you create a vector from the surface to the camera. For that, you need the position of the surface. You get that by interpolating the vertex positions using varying ("in" in vertex, "out" in fragment) variables.

Start out working on a single light source, diffuse component only. When that works, switch to the specular component. Once that works for one positional and one directional light source, chances are good that everything works. Working on one at a time will help you not to get distracted by too much information.

Questions:


5) Multitexturing

Using multiple textures on a model can be very useful for many purposes. The difference from the texture mapping introduced in lab 2 is that you must bind textures to specific texture units:
  glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textureId);

This enables the textures as texture unit 0.

If the texture is called "tex" in your shader, you can pass the texture unit to that variable like this:Next, go back to init() again. After the shaderTimeLocation has been located, perform the following operation:

  glUniform1i(getUniformLocation(shaderProgram, "tex"), 0);
Load two textures and apply them to an object. Build from your specular shader, and combine lighting and texture.

Questions:

Extra) Managing transparency

In your virtual world, make at least two object semi-transparent. Move around. You should be able to find locations where the transparency (combined with Z buffering) causes problems. Solve these problems.

Questions:


That concludes lab 3. Good work! In the next lab, we will make the ground more interesting, a 3D terrain.