Laboration 3 (TSBK11 and ETE378 version)

Preliminary version:

1) Ground plane

Add a "ground" as a fairly large textured polygon. You can do that with a few arrays and using 

#define kGroundSize 100.0f
vec3 vertices[] =
{
 { -kGroundSize,0.0f,-kGroundSize},
 {-kGroundSize,0.0f,kGroundSize},
 {kGroundSize,-0.0f,-kGroundSize},
 {kGroundSize,-0.0f,kGroundSize}
};

vec3 vertex_normals[] =
{
  {0.0f,1.0f,0.0f},
  {0.0f,1.0f,0.0f},
  {0.0f,1.0f,0.0f},
  {0.0f,1.0f,0.0f}
};

vec2 tex_coords[] =
{
  {0.0f,0.0f},
  {0.0f,20.0f},
  {20.0f,0.0f}, 
  {20.0f,20.0f}
};
GLuint indices[] =
{
  0, 1, 2, 1, 3, 2
};

and pass this data to LoadDataToModel (in LittleOBJLoader).

2) Populate the world (the TSBK11 town?)

Put several objects into the scene, most of them stationary.

We have provided a few suitable models:

TSBK11-lab3-new-models-preliminary.tar.gz

This is a good time to add more structure to your code. You have a few options:

• Add separate functions for helping you. For instance, how about a function like this:

void DrawObject(Model *m, GLuint shader, GLuint texture, mat4 placement);

No, it isn’t in the lab code, it is a prototype for you if that is what you want.

• Make an array of structs, each describing an object, with Model, shader, texture, placement.

• Specific calls for certain objects, so you just pass the placement transform and the rest are model specific.

There are more ways to do it, but for the lab, a function like DrawObject suggested above will change things dramatically, when you can literally add one more object to your scene with a single call!

You can start with a few, then do part 3. After that works, this part will be more fun!

Advice: Don’t be shy, make it big! We want many objects. You can use for-loops or instancing for multiple instances of the same model. (I will cover instancing on the lectures. Don’t worry about it. You don’t need millions of houses.)

3) 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. Change the camera position, and its direction, and make the movement based on the direction.

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, we recommend the function glutKeyIsDown, e.g. if (glutKeyIsDown('a')) { (something happens) }.

When using glutPassiveMotionFunc(), you may also want glutWarpPointer(). It moves the mouse pointer to a specific place on the screen. Note: This captures the mouse which makes it hard to exit the program. It can be convenient to react on glutKeyboardFunc for a specific key to release the mouse or quit the program. Check out the “Warprotation” demo in the demo archive (under “various”).

Questions:

What kind of control did you implement?

Can you make this kind of control in some other way than manipulating a "look-at" matrix?

4) Skybox

Now, add a "skybox". For this purpose, a skybox model (labskybox.obj) and texture (LabSkyBox512.tga) are provided. To implement a skybox, the skybox should follow the camera and seem to be drawn at the back. To do this, you should draw the skybox first, with Z-buffer turned off (glDisable(GL_DEPTH_TEST)) . The skybox should be rotated as the camera, but not translated. You can do this with a copy of the camera matrix where you zero out the translation component. Culling needs to be off; you always want to draw the skybox (and the model is not designed for culling). Finally, don't forget to turn the Z-buffer on again after drawing the skybox.

Note! Your skybox may not look 100% perfect with the model that comes with the lab. Pretty good, but it has a (somewhat minor) problem, when working with a flat floor like we do here. What would you do to fix this? Look into the “skybox” folder! (Not for the lab but might help you in the projects.)

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:

How did you handle the camera matrix for the skybox?

How did you represent the objects? Is this a good way to manage a scene or would you do it differently for a "real" application?

What special considerations are needed when rendering a skybox?

What is the problem with the “labskybox" object used in the lab? (The problem doesn't have to be corrected.)

5) Diffuse shading, external light source

We did diffuse light before. We will modify that a little bit by making the light direction come from the CPU, and also verify that it doesn’t follow the camera.


The light source

You should use one directional light source, given by the main program like this:

vec3 lightSourceColor = {1.0f, 0.0f, 0.0f}; // Red light

vec3 lightSourceDirection = {0.0f, 0.0f, -1.0f}; // Light along Z


Upload to shader:

glUniform3fv(glGetUniformLocation(program, "lightSourceDirection"), 1, & lightSourceDirection);

glUniform3fv(glGetUniformLocation(program, "lightSourceColor"), 1, & lightSourceColor);

They can be declared in the shader like this:

uniform vec3 lightSourceDirection;

uniform vec3 lightSourceColor;

You need to do the proper transformation of normal vectors in order to make the light stationary when you move around.

Questions are not decided yet.

6) Specular shading (non-mandatory)

Add the specular component to your shading. It is given (per object) like this:

GLfloat specularExponent = 100.0; // Should be defined per object

This will require you to calculate the reflected vector as well as the direction towards the camera.

For more detail, look in the specular shading part for TSBK07.

Upload to shader:

glUniform3fv(glGetUniformLocation(program, "lightSourceDirection"), 1, & lightSourceDirection);

glUniform3fv(glGetUniformLocation(program, "lightSourceColor"), 1, & lightSourceColor);

glUniform1f(glGetUniformLocation(program, "specularExponent"), specularExponent);

Declarations in shader:

uniform vec3 lightSourceDirection;

uniform vec3 lightSourceColor;

uniform float specularExponent;

Note that the specularExponent can (should) be different for each object.


Questions (non-mandatory part):

Why do we get a white area in the distance for the specular light but not for the diffuse?

How do you generate a vector from the surface to the eye?

Which vectors need renormalization in the fragment shader?

This page is maintained by Ingemar Ragnemalm