Search code examples
c++openglglutlight

OpenGL lighting position is fixed at undesired location


I am trying to locate my light at position 0,0,0 but it always go bottom left of the box which has coords -20,-20,0 and I try to change light position to some arbitrary coordinates but it still stays at bottom left.

I provided a picture where camera positioned at 0,0,40:

enter image description here

void initLighting()
{
    // Enable lighting
    glEnable(GL_LIGHTING);
    glEnable(GL_NORMALIZE);
    glEnable(GL_COLOR_MATERIAL);
    glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
    //glEnable(GL_DEPTH_TEST);
    glShadeModel(GL_SMOOTH);
    glEnable(GL_LIGHT0);

    // Set lighting intensity and color
    glLightfv(GL_LIGHT0, GL_AMBIENT, value_ptr(lights.at(0).ambient));
    glLightfv(GL_LIGHT0, GL_DIFFUSE, value_ptr(lights.at(0).diffuse));
    glLightfv(GL_LIGHT0, GL_SPECULAR, value_ptr(lights.at(0).specular));
    glLightfv(GL_LIGHT0, GL_POSITION, value_ptr(vec4(lights.at(0).position, 1.0f)));
    ////////////////////////////////////////////////
    glLightf(GL_LIGHT0, GL_SPOT_CUTOFF, 15.0);// set cutoff angle
    glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, value_ptr(box.center));
    glLightf(GL_LIGHT0, GL_SPOT_EXPONENT, 1); // set focusing strength
}

void display(void)
{
    glMatrixMode(GL_MODELVIEW);
    // clear the drawing buffer.
    glClear(GL_COLOR_BUFFER_BIT);
    // clear the identity matrix.
    glLoadIdentity();

    glPushMatrix();
    gluLookAt(camera.position.x, camera.position.y, camera.position.z, box.center.x, box.center.y, box.center.z,
    camera.upVector.x, camera.upVector.y, camera.upVector.z);
    glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, value_ptr(materials.at(box.material).ambient));
    glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, value_ptr(materials.at(box.material).diffuse));
    glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, value_ptr(materials.at(box.material).specular));
    glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, materials.at(box.material).exponent);
    glBegin(GL_TRIANGLES);
    for (int i = 0; i < box.indices.size(); i = i + 3)
    {
        glNormal3fv(value_ptr(box.vertices.at(box.indices.at(i)).Normal));
        glVertex3f(box.vertices.at(box.indices.at(i)).Position.x, box.vertices.at(box.indices.at(i)).Position.y, box.vertices.at(box.indices.at(i)).Position.z);

        glNormal3fv(value_ptr(box.vertices.at(box.indices.at(i + 1)).Normal));
        glVertex3f(box.vertices.at(box.indices.at(i + 1)).Position.x, box.vertices.at(box.indices.at(i + 1)).Position.y, box.vertices.at(box.indices.at(i + 1)).Position.z);

        glNormal3fv(value_ptr(box.vertices.at(box.indices.at(i + 2)).Normal));
        glVertex3f(box.vertices.at(box.indices.at(i + 2)).Position.x, box.vertices.at(box.indices.at(i + 2)).Position.y, box.vertices.at(box.indices.at(i + 2)).Position.z);
    }
    glEnd();
    glPopMatrix();

    glPushMatrix();
    gluLookAt(camera.position.x, camera.position.y, camera.position.z, box.center.x, box.center.y, box.center.z,
    camera.upVector.x, camera.upVector.y, camera.upVector.z);
    glLightfv(GL_LIGHT0, GL_POSITION, value_ptr(vec4(lights.at(0).position, 1.0f)));
    glPopMatrix();

    glFlush();
    glutSwapBuffers();
}

Solution

  • When the light position is set by glLightfv(GL_LIGHT0, GL_POSITION, pos), then pos is multiplied by the current model view matrix.
    This means if the position is set before the view matrix is set (gluLookAt), then the light position is relative to the camera (view space position).
    If it is set after the view matrix was set, then the light position has to be in world coordinates, becaus it is transformed by the view matrix.

    When the spot light direction is set by glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, dir), then the direction is multiplied by the upper 3x3 of the modelview matrix.

    Note, that the parameter GL_SPOT_DIRECTION has to be a direction vector and not a position.
    This means you have to set it somehow like this, after the view matrix was set:

    vec3 dir = box.center - lights.at(0).position;
    glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, value_ptr(dir));
    

    Further note, that the OpenGL fixed function pipeline calculates the light per vertex: Gouraud shading.
    This may cause, that you can't "see" the light, if the light cone of the spotlight does not hit any vertex position. You are in danger of that behavior, because your geometry consists of "large" primitives and the cone opening angle of the spot light is very small (15°).

    See OpenGL Lighting on texture plane is not working

    Edit:

    Your light cone angle (GL_SPOT_DIRECTION) is 15° and the direction of the light is slightly directed to the bottom left, because according to the comment below box.center is (-6.6,-6.6,-53). This causes that the one and only vertex coordinate which receives light is the bottom left corner (Gouraud shading).
    So it seem as if the light is directly directed to the bottom left corner.

    Increase or skip the light cone angle to solve the issue:

    e.g.:

    glLightf(GL_LIGHT0, GL_SPOT_CUTOFF, 45.0);