Search code examples
copenglglutlightingopengl-compat

How to enable different GL_POSITION of two objects


enter image description here

I want to create two objects with different light position. But the light position of second object (Gold sphere) is always the same as the first object (Silver sphere) even I have set different position parameter.

I have enable both light one after another object. But the second one is always the same as the first/above one.

    // light from top right
    GLfloat light_position_top_right[] = { 1.0, 1.0, 1.0, 0.0 };
    // light from bottom left
    GLfloat light_position_bottom_left[] = { -1.0, -1.0, 1.0, 0.0 };

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glLightfv(GL_LIGHT0, GL_POSITION, light_position_top_right);
    glLightfv(GL_LIGHT1, GL_POSITION, light_position_bottom_left);

    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glEnable(GL_LIGHT1);
    glEnable(GL_DEPTH_TEST);

You can find complete code in this gist.

I expect the second object to have light position from bottom left. But it shows from top right as the first object.


Solution

  • The fourth coordinate of your light positions must be 1.0 instead of 0.0, otherwise due to how projective transformations work the lights will behave as if they are infinitely far away in the specified direction.

    With a fourth coordinate of 0.0:

    Lights are infinitely far away

    With a fourth coordinate of 1.0:

    Lights are properly located

    As for why there are two highlights instead of just one, you forgot to set the proper glLight* settings for your lights. By default, GL_LIGHT0 begins with white diffuse and specular color, but all other lights have black diffuse and specular color by default.


    EDIT:

    If you want separate spheres to use separate lights, you'll need to initialize the lights during init(). But instead of glEnableing the lights right then, do the following:

    void display(void)
    {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
        glPushMatrix();
        glTranslatef(1.0, 0.0, -1.0);
        glEnable(GL_LIGHT0);
        drawGraySphere();
        glutSolidSphere(0.5, 50, 50);
        glDisable(GL_LIGHT0);
        glPopMatrix();
    
        glPushMatrix();
        glTranslatef(-0.75, -0.8, 0.0);
        glEnable(GL_LIGHT1);
        drawGoldSphere();
        glutSolidSphere(0.5, 50, 50);
        glDisable(GL_LIGHT1);
        glPopMatrix();
    
        glFlush();
    }
    

    Alternatively, you have the option to just use a single light, and change its parameters using glLight* each frame, before rendering each sphere. This is the better option if you plan on having a bunch of objects, each with their own light.