How do I fixate a light source in OpenGL while rotating an object?

13,907

Solution 1

I think changing

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glMatrixMode(GL_PROJECTION);
glLoadIdentity();

to

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

is a good place to start.

Solution 2

I also think your application "destroys" the modelview matrix; it's never re-computed from scratch. You should start each frame with a LoadIdentity(), then emit the lightsource, then rotate as desired, and finally emit the geometry.

This doesn't work, this doesn't work, this doesn't work, lalalalalalalala, and the FAQ is patently wrong, plain and simple.

Emitting the light just after glLoadIdentity() in order to get a camera-bound light will work in simple cases when you only translate, or only rotate the model around the origin. But when you start doing non-trivial, non-hello-world things like rotating an object around a point different than the origin (translate(-v), rotate(angle), translate(v)) and then moving it so that the rotation center is brought in front of the camera, then the "load identity, place light" technique starts failing spectacularly and in ways that make it very hard to deduce what is even going on.

No, I don't know the solution.

Solution 3

Try manually setting normal values for each vertex.

Solution 4

I ran into the same problem and got the solution. The problem was that I set the light position only in the OnLoad part of the program... I think it is the best to post some code. I work in C# using OpenTK cause I'm aware I will never enter graphic business. :)

The result is a teapot or some other object that is rotating with the light that has fixed position. I can move the eye position (LookAt method) and the light source stays still. It's just like in the real word: The object can spin but the sun will not. :) Also, we can walk around the object but the sun still remains unimpressed and stays still. This code will do that trick.

protected override void OnRenderFrame(FrameEventArgs e)
 {
        base.OnRenderFrame(e);

        GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
        System.Threading.Thread.Sleep(10); //useful thing to lower CPU usage

        //I can set the eye position at runtime, it's not necessary to have this
        modelview = Matrix4.LookAt(this.eye, Vector3.Zero, Vector3.UnitY);

        GL.MatrixMode(MatrixMode.Modelview);                       
        GL.LoadMatrix(ref modelview);           

        //**this is the key - you have to set the light position every time**
        GL.Light(LightName.Light0, LightParameter.Position, new float[4] { 1000, 1000, 0, 0 });


        // We don't want the walls to rotate so we push the current matrix
        GL.PushMatrix();

         GL.Rotate(move, Vector3.UnitY);
         move += 0.5f;

         GL.Color3(1.0f, 1.0f, 1.0f);

           GL.Begin(BeginMode.Triangles);
           //the object that will rotate             
           GL.End();
        GL.PopMatrix();              


        GL.Begin(BeginMode.Quads);
        //some quads (walls) in the background that will stay still
        GL.End();                                                

        SwapBuffers();
    }

I took this from my program and deleted a lot of stuff that is here unimportant so maybe it looks a bit weird. I hope it helps.

Share:
13,907
Attila Kun
Author by

Attila Kun

Updated on June 07, 2022

Comments

  • Attila Kun
    Attila Kun almost 2 years

    I have a glutSolidTeapot (which has its surface normals generated automatically according to opengl.org) and a light source which is emitting diffuse light. The problem comes when I try to rotate the teapot: it seems like the light source is doing the rotation as well, not remaining in the same position I defined it (it essentially follows the teaspot). As you can see in my code, I only modify the lighting position upon initialization, so it is not subjected to glRotatef(), since its called after setting the light position.

    Despite spending numerous hours trying to solve this problem, I really have no idea what this kind of behavior can be attributed to.

    Pasting glEnable(GL_NORMALIZE); in the initialization does not solve the problem neither.

    I think the desired output should be a teapot with a shiny right side (since the light is coming from that direction), no matter what angle the teapot is rotated by.

    If you want to test my code, press Space to rotate the teapot.

    #include <math.h>
    #include <stdlib.h>
    
    #if defined(WIN32) || defined(_WIN32) || defined(__WIN32__)
    #include <windows.h>     
    #endif
    
    #include <GL/gl.h>
    #include <GL/glu.h>
    #include <GL/glut.h>     
    
    void onInitialization( ) { //creating the light source
     glEnable(GL_LIGHTING);
     glEnable(GL_DEPTH_TEST); 
    
     GLfloat diffuse[]={0.8, 0.8, 0.8, 1.0};
     GLfloat pos[]={0.5, 0.0, 0.8, 0.0};
    
     glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
     glLightfv(GL_LIGHT0, GL_POSITION, pos);
    
     glEnable(GL_LIGHT0);
    
     glRotatef(-90, 1, 0, 0); //we want to see the top of the teapot
    }
    
    void onDisplay( ) {
        glClearColor(0.1f, 0.2f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
     //rotating on every frame (for testing purposes only)
     glRotatef(5, 0,1,0);
     glutSolidTeapot(0.4);
    
        glFinish();
        glutSwapBuffers();
    }
    
    
    void onKeyboard(unsigned char key, int x, int y) {
     if (key==32){ //do rotation upon hitting the Space key
      glutPostRedisplay();
     }
    }
    
    int main(int argc, char **argv) {
        glutInit(&argc, argv); 
        glutInitWindowSize(600, 600);
        glutInitWindowPosition(100, 100);
        glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
        glutCreateWindow("Teapot");
    
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
    
        onInitialization();
    
        glutDisplayFunc(onDisplay);
        glutKeyboardFunc(onKeyboard);
    
        glutMainLoop();
    
        return 0;
    }
    
  • Attila Kun
    Attila Kun over 14 years
    If the modelview matrix were destroyed, the rotation I use wouldn't work, I think. Anyway I tried what you suggested (again, because I previously tried something like this), but it didn't work. I know that the position of lights are multiplied by the current matrix, but they should only be multiplied upon intitialization, and never, ever after that, since I don't touch it.
  • David Ameller
    David Ameller almost 14 years
    I'm doing that, but the light still moving. Also I'm doing what is said in other answers :(