Clone last week project and call the new one 'lab10_lighting'. Alternatively, you can recover the sources from this archive here:
You may have implemented to this already - here is my version:
And this is the 'manager' of the cameras:
World, then holds a 'cameras' object:
Cameras cameras;
void World::keyPress(unsigned char ch)
{
if (ch >= '1' && ch <= '4')
{
projectors.keyPress(ch);
}
else if (ch >= '5' && ch <= '6')
{
cameras.keyPress(ch);
}
else
{
cameras.currentCamera->keyStroke(ch);
}
glutPostRedisplay();
}
void World::specialKeyPress(int key, int x, int y)
{
if (projectors.isPerspective())
{
cameras.currentCamera->specialKeyboard(key, x, y);
}
glutPostRedisplay();
}
void World::mouseMovement(int x, int y)
{
cameras.currentCamera->mouseMovement(x,y);
}
This is the jetmodel geometry again:
... and this is the class definition:
#pragma once
#include "actor.h"
struct JetPlane : public Actor
{
JetPlane();
void render();
};
#include "libs.h"
#include "jetplane.h"
#include "Color.h"
#include "jetplanegeometry.h"
using namespace std;
void render (Vector3 vectors[][3], int size)
{
for (int i=0; i<size; i++)
{
glBegin(GL_TRIANGLES);
vectors[i][0].render();
vectors[i][1].render();
vectors[i][2].render();
glEnd();
}
}
JetPlane::JetPlane()
{}
void JetPlane::render()
{
glShadeModel(GL_SMOOTH);
glPolygonMode(GL_FRONT,GL_FILL);
Color::Yellow.render();
::render(noseCone, 3);
Color::Red.render();
::render(body, 3);
Color::Green.render();
::render(wings, 4);
Color::Cyan.render();
::render(tail, 7);
Color::White.render();
glPolygonMode(GL_FRONT,GL_LINE);
}
Scene:: Scene(Model *model)
{
foreach (GeometryMap::value_type &value, model->entities)
{
string name = value.first;
Actor *actor;
if (name == "cube")
{
actor = new CubeActor(&value.second);
animateActors[name] = (AnimateActor*) actor;
}
else
{
actor = new Actor(&value.second);
}
actors.insert(name, actor);
}
string jet="jet";
actors.insert(jet, new JetPlane());
}
Lets to some experiments with in world.cpp.
The code we introduce is experimental, and not encapsulated in any way. It is primarily to get familiar with the effects of lighting in OpenGL.
In World::initalise, enable lighting:
glEnable(GL_LIGHTING);
Build and test. Results not impressive, as the plan is now gone (invisible).
It is in fact still being rendered, but all in black.
In World::render, change black background to blue:
Color::Blue.renderClear();
Build and test.
Plane is now visible, but completely black.
Introduce some ambient light - set this as follows:
GLfloat ambientLightFull[] = { 1.0f, 1.0f, 1.0f, 1.0f };
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambientLightFull);
Build and test. Still nothing visible.
Problem is, we have no material properties set for any of our surfaces.
We can try a simple gray material for all surfaces:
float gray[] = { 0.75f, 0.75f, 0.75f, 1.0f };
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, gray);
Build and test - the plane should appear a light gray
Instead of having everything gray, we can turn on colour tracking. Comment out the last two lines, and replace with these:
glEnable(GL_COLOR_MATERIAL);
glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
Build and test - you should have your colours back.
Experiment with different values for the ambient light.
Try half:
float ambientLightHalf[] = { 0.5f, 0.5f, 0.5f, 1.0f };
float ambientLightDefault[] = { 0.2f, 0.2f, 0.2f, 1.0f };
For lighting to function properly, we need to know "which way is up"
This requires the computation of Normals.
This could be implemented as a global function - say in vector3.cpp. Note however, that this is not a member of Vector3.
Vector3 findNormal(const Vector3& point1, const Vector3& point2, const Vector3& point3)
{
Vector3 v1, v2;
// Calculate two vectors from the three points. Assumes counter clockwise winding
v1.X = point1.X - point2.X;
v1.Y = point1.Y - point2.Y;
v1.Z = point1.Z - point2.Z;
v2.X = point2.X - point3.Z;
v2.Y = point2.Y - point3.Y;
v2.Z = point2.Z - point3.Z;
// Take the cross product of the two vectors to get he normal vector.
Vector3 result;
result.X = v1.Y * v2.Z - v2.Y * v1.Z;
result.Y = -v1.X * v2.Z + v2.X * v1.Z;
result.Z = v1.X * v2.Y - v2.X * v1.Y;
return result;
}
void render (Vector3 vectors[][3], int size)
{
for (int i=0; i<size; i++)
{
glBegin(GL_TRIANGLES);
Vector3 normal = findNormal( vectors[i][0], vectors[i][1], vectors[i][2]);
glNormal3f(normal.X, normal.Y, normal.Z);
vectors[i][0].render();
vectors[i][1].render();
vectors[i][2].render();
glEnd();
}
}
void basicAmbient()
{
GLfloat ambientLightFull[] = { 1.0f, 1.0f, 1.0f, 1.0f };
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambientLightFull);
}
void grayMaterial()
{
float gray[] = { 0.75f, 0.75f, 0.75f, 1.0f };
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, gray);
}
void colourTracking()
{
glEnable(GL_COLOR_MATERIAL);
glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
}
Place them in lignts.cpp, and prototype them in lights.h
In our initialise method, having first enabled lighting, we can comment calls to these methods in or out to see their effect:
void World::initialize(int width, int height, std::string name)
{
//...
glEnable(GL_LIGHTING);
//basicAmbient();
grayMaterial();
colourTracking();
//...
`experiment with various combinations of the above functions being enabled/disabled
Now, int lights, introduce 2 more functions to control the lighting:
void lightSource()
{
float ambientLightModerate[] = { 0.3f, 0.3f, 0.3f, 1.0f };
float diffuseLightModerate[] = { 0.7f, 0.7f, 0.7f, 1.0f };
glLightfv(GL_LIGHT0,GL_AMBIENT,ambientLightModerate);
glLightfv(GL_LIGHT0,GL_DIFFUSE,diffuseLightModerate);
glEnable(GL_LIGHT0);
glEnable(GL_NORMALIZE);
}
void positionLight()
{
float lightPos[] = { -50.f, 50.0f, 100.0f, 1.0f };
glLightfv(GL_LIGHT0,GL_POSITION,lightPos);
}
glEnable(GL_LIGHTING);
//basicAmbient();
//grayMaterial();
lightSource();
colourTracking();
//basicAmbient();
grayMaterial();
lightSource();
//colourTracking();
void World::render()
{
Color::Blue.renderClear();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
if (projectors.isPerspective())
{
glLoadIdentity();
cameras.currentCamera->render();
}
scene->render();
glutSwapBuffers();
}
Where is the best place? Remember to test this your camera will be moving, not the light, so the essential lumination/shadows should not change as you move around the scene.
In particular, explore what happens if the light is positioned after the glLoadIdentity() call, but before the camera render.
See if you can identify the light source position by view the plan (using the third person camera) from different directions.
Move the light source, and see if you can ascertain the difference.
Finally, revert to this combination:
//basicAmbient();
grayMaterial();
lightSource();
//colourTracking();
void render (Vector3 vectors[][3], int size)
{
for (int i=0; i<size; i++)
{
glBegin(GL_TRIANGLES);
Vector3 normal = findNormal( vectors[i][0], vectors[i][1], vectors[i][2]);
//glNormal3f(normal.X, normal.Y, normal.Z);
vectors[i][0].render();
vectors[i][1].render();
vectors[i][2].render();
glEnd();
}
}
Build and test. Can you see the major effect the normals are having?
Put the normals back in and test again.
enum MaterialTypes {flatRed, flatYellow, flatBlue, flatGreen, flatGray, plasticRed, shinyWhite, brass, bronze,
chrome, copper, gold, pewter, silver, polishSilver, plasticBlack} ;
void applyMaterial(MaterialTypes material);
struct Material
{
GLfloat ambient[4];
GLfloat diffuse[4];
GLfloat specular[4];
GLfloat shiny;
};
Material materials [] =
{
{ {0.8, 0.0, 0.0, 1.0}, // flatRed
{0.8, 0.0, 0.0, 1.0},
{0.8, 0.0, 0.0, 1.0}, 25.0 },
{ {0.8, 0.0, 0.0, 1.0}, //flatYellow
{0.8, 0.0, 0.0, 1.0},
{0.8, 0.0, 0.0, 1.0}, 25.0 },
{ {0.0, 0.0, 0.8, 1.0}, // flatblue
{0.0, 0.0, 0.8, 1.0},
{0.0, 0.0, 0.8, 1.0}, 25.0 },
{ {0.0, 0.8, 0.0, 1.0}, // flatgreen
{0.0, 0.8, 0.0, 1.0},
{0.0, 0.8, 0.0, 1.0}, 25.0 },
{ {0.5, 0.5, 0.5, 1.0}, // flatgrey
{0.5, 0.5, 0.5, 1.0},
{0.5, 0.5, 0.5, 1.0}, 25.0 },
{ {0.3, 0.0, 0.0, 1.0}, //plasticRed
{0.6, 0.0, 0.0, 1.0},
{0.8, 0.6, 0.6, 1.0}, 32.0 },
{ {1.0, 1.0, 1.0, 1.0}, //shinyWhite
{1.0, 1.0, 1.01, 1.0},
{1.0, 1.0, 1.0, 1.0}, 100.0 },
{ {0.329412, 0.223529, 0.027451, 1.0}, //brass
{0.780392, 0.568627, 0.113725, 1.0},
{0.9922157, 0.941176, 0.807843, 1.0}, 27.8974 },
{ {0.2125, 0.1275, 0.054, 1.0}, //bronze
{0.714, 0.4284, 0.18144, 1.0},
{0.303548, 0.271906, 0.106721, 1.0}, 25.6 },
{ {0.25, 0.25, 0.25, 1.0}, //chrome
{0.4, 0.4, 0.4, 1.0},
{0.774597, 0.774597, 0.774597, 1.0}, 76.8 },
{ {0.19125, 0.0735, 0.0225, 1.0}, //copper
{0.7038, 0.27048, 0.0828, 1.0},
{0.256777, 0.137622, 0.086014, 1.0}, 12.8 },
{ {0.24725, 0.1995, 0.0745, 1.0},// gold
{0.75164, 0.60648, 0.22658, 1.0},
{0.628281, 0.555802, 0.366065, 1.0}, 51.2 },
{ {0.10558, 0.058824, 0.113725, 1.0}, //pewter
{0.427451, 0.470588, 0.541176, 1.0},
{0.3333, 0.3333, 0.521569, 1.0}, 9.84615 },
{ {0.19225, 0.19225, 0.19225, 1.0}, //silver
{0.50754, 0.50754, 0.50754, 1.0},
{0.508273, 0.508273, 0.508273, 1.0}, 51.2 },
{ {0.23125, 0.23125, 0.23125, 1.0}, //polishSilver
{0.2775, 0.2775, 0.2775, 1.0},
{0.773911, 0.773911, 0.773911, 1.0}, 89.6 },
{ {0.0, 0.0, 0.0, 1.0}, //plasticBlack
{0.01, 0.01, 0.01, 1.0},
{0.50, 0.50, 0.50, 1.0},32.0 }
};
void applyMaterial(MaterialTypes material)
{
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, materials[material].ambient);
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, materials[material].diffuse);
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, materials[material].specular);
glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, materials[material].shiny);
}
This is the completed lab to date:
void basicAmbient()
{
GLfloat ambientLightFull[] = { 1.0f, 1.0f, 1.0f, 1.0f };
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambientLightFull);
}
void grayMaterial()
{
float gray[] = { 0.75f, 0.75f, 0.75f, 1.0f };
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, gray);
}
void colourTracking()
{
glEnable(GL_COLOR_MATERIAL);
glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
}
void lightSource()
{
float ambientLightModerate[] = { 0.3f, 0.3f, 0.3f, 1.0f };
float diffuseLightModerate[] = { 0.7f, 0.7f, 0.7f, 1.0f };
glLightfv(GL_LIGHT0,GL_AMBIENT,ambientLightModerate);
glLightfv(GL_LIGHT0,GL_DIFFUSE,diffuseLightModerate);
glEnable(GL_LIGHT0);
glEnable(GL_NORMALIZE);
}
void positionLight()
{
float lightPos[] = { -50.f, 50.0f, 100.0f, 1.0f };
glLightfv(GL_LIGHT0,GL_POSITION,lightPos);
}
Devise a mechanism where by you can control the light by some key combination. These controls could: - Control ambient light intensity
Control the diffuse light intensity
Move the light