English 中文(简体)
How do I fixate a light source in OpenGL while rotating an object?
原标题:

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;
}
最佳回答

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.

问题回答

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.

Try manually setting normal values for each vertex.

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.

The FAQ states:

A light s position is transformed by the current ModelView matrix at the time the position is specified with a call to glLight*().

In other words, lights aren t positioned in some kind of magic static "world coordinate system"; they re multiplied by the modelview matrix just like any geometry would be. This makes sense; you often want to have lights locked to geometry.

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.

In my opinion what you should do is not only to call glLoadIdentity() at the beginning of your render routine, but to push and pop the modelview matrix.

for a scene with a globally fixed light source and two objects which are indepently positioned and rotated this pseudo code will do the trick:

glLoadIdentity();

// first object
glPushMatrix();
glTranslate(...);
glRotate(...)
glPopMatrix();

// second object
glPushMatrix();
glTranslate(...);
glRotate(...);
glPopMatrix();




相关问题
OpenGL 3D Selection

I am trying to create a 3D robot that should perform certain actions when certain body parts are clicked. I have successfully (sort of) implemented picking in that if you click on any x-plane part, it ...

CVDisplayLink instead of NSTimer

I have started to implement cvDisplayLink to drive the render loop instead of nstimer, as detailed in this technical note https://developer.apple.com/library/archive/qa/qa1385/_index.html Is it ...

Can the iPhone simulator handle PVR textures?

I have a really weird problem with PVR textures on the iPhone simulator- the framerate falls through the floor on the iPhone simulator, but on the iPhone itself it works just fine. Has anyone had any ...

Calculate fps (frames per second) for iphone app

I am using an opengl es iphone application. What is the most accurate way to calculate the frames per second of my application for performance tuning?

Java - Zoom / 3D Data Visualization Libraries

What are the best libraries/frameworks for doing 3D and/or Zoom interfaces in Java? I d like to be able to do some prototyping of creating new types of interfaces for navigating within data and ...

FLTK in Cygwin using Eclipse (Linking errors)

I have this assignment due that requires the usage of FLTK. The code is given to us and it should compile straight off of the bat, but I am having linking errors and do not know which other libraries ...

热门标签