Evan Allan Evan Allan - 3 months ago 13
C++ Question

OpenGL lighting changing based on look direction

AKA What am I doing wrong?

I've been messing around with OpenGL and I'm just trying to work on lighting a cube right now. I'm not sure if I'm understanding what I'm supposed to do correctly because when I move the camera around, the lighting on the cube changes.

For example:

Looking at the cube from the top down:

top down

Looking at the cube from the side:

enter image description here

From searching around all of the answers that I've seen say that this happens when the normal isn't set correctly, but I think they are being set correctly, because when I print out all of the vertices along with their normals, this is the result (grouped by face, in the order they're drawn):

Position: 0 0 0 Normal: -1 0 0
Position: 0 30 0 Normal: -1 0 0
Position: 0 30 30 Normal: -1 0 0
Position: 0 0 30 Normal: -1 0 0

Position: 0 0 0 Normal: 0 1 0
Position: 0 0 30 Normal: 0 1 0
Position: 30 0 30 Normal: 0 1 0
Position: 30 0 0 Normal: 0 1 0

Position: 0 0 0 Normal: 0 0 -1
Position: 30 0 0 Normal: 0 0 -1
Position: 30 30 0 Normal: 0 0 -1
Position: 0 30 0 Normal: 0 0 -1

Position: 0 0 30 Normal: 0 0 1
Position: 0 30 30 Normal: 0 0 1
Position: 30 30 30 Normal: 0 0 1
Position: 30 0 30 Normal: 0 0 1

Position: 0 30 0 Normal: 0 -1 0
Position: 30 30 0 Normal: 0 -1 0
Position: 30 30 30 Normal: 0 -1 0
Position: 0 30 30 Normal: 0 -1 0

Position: 30 0 0 Normal: 1 0 0
Position: 30 0 30 Normal: 1 0 0
Position: 30 30 30 Normal: 1 0 0
Position: 30 30 0 Normal: 1 0 0


Here's also some of the code used for rendering in case the mistake is in there:

RenderEngine::RenderEngine(int width, int height) {
//initializing the window...

glClearDepth(1.f);
glClearColor(217.f / 256.f, 233.f / 256.f, 255.f / 256.f, 1.f);

glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);

glFrontFace(GL_CW);
glEnable(GL_CULL_FACE);

glEnable(GL_LIGHTING);

//glEnable(GL_COLOR_MATERIAL);

GLfloat lightPos[] = { 0.f, -1.0f, 0.0f, 0.f };
GLfloat ambient[] = {0.3f,0.3f,0.3f,1.0f};
GLfloat diffuse[] = {0.7f,0.7f,0.7f,1.0f};
glLightfv(GL_LIGHT0, GL_POSITION, lightPos);
glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
glEnable(GL_LIGHT0);

//more window related things
}

void RenderEngine::beginRender() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}

void RenderEngine::endRender() {
//window stuff
}

void RenderEngine::translatePlayer(const sf::Vector3f& position) {
glTranslatef(-(position.x + 0.5) * 30, -(position.y + 1.75) * 30, -(position.z + 0.5) * 30);
}

void RenderEngine::rotatePlayer(const sf::Vector3f& rotation) {
glRotatef(rotation.x, 1.f, 0.f, 0.f);
glRotatef(rotation.y, 0.f, 1.f, 0.f);
glRotatef(rotation.z, 0.f, 0.f, 1.f);
}

void RenderEngine::renderVertexArray(const std::vector<Vertex>& vertices) {
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);

glVertexPointer(3, GL_FLOAT, sizeof(Vertex), &vertices[0].pos[0]);
glColorPointer(3, GL_FLOAT, sizeof(Vertex), &vertices[0].color[0]);
glNormalPointer(GL_FLOAT, sizeof(Vertex), &vertices[0].normal[0]);

glDrawArrays(GL_QUADS, 0, vertices.size());

glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
}


And the vertex object:

struct Vertex {
float pos[3];
float color[3];
float normal[3];

Vertex(float _pos[3], float _color[3], float _normal[3]) :
pos {_pos[0], _pos[1], _pos[2]},
color {_color[0], _color[1], _color[2]},
normal{_normal[0], _normal[1], _normal[2]} {}

Vertex() : pos{0,0,0}, color{0,0,0}, normal{0,0,0} {}
};


Please ignore all the random 30's. I'm aware that those are out of place and should not be done that way, but that's not the issue here.

Answer

When you call the following:

glLightfv(GL_LIGHT0, GL_POSITION, lightPos);

... then the passed lightPos is transformed with the current model-view matrix and then stored in camera coordinates. Thus, your light will move together with the camera. If you want it to be static, you have to execute the above line again after setting the model-view matrix.