2009-11-18 82 views
5

我有一个glutSolidTeapot(它的表面法线根据opengl.org自动生成)和一个发出漫射光的光源。当我尝试旋转茶壶时,问题就出现了:它看起来像光源也在旋转,而不是保持在我定义的相同位置(它基本上遵循茶壶)。正如你在我的代码中看到的那样,我只是在初始化时修改了光照位置,所以它不会受到glRotatef()的影响,因为它在之后调用设置光源位置。如何在旋转对象时在OpenGL中注入光源?

尽管花了很多时间试图解决这个问题,我真的不知道这种行为可以归因于什么。

粘贴glEnable(GL_NORMALIZE);在初始化中也没有解决问题。

我认为所需的输出应该是一个有光泽的右侧茶壶(因为光线来自该方向),无论茶壶旋转的角度是多少。

如果您想测试我的代码,请按空格旋转茶壶。

#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; 
} 
+0

我会手动旋转点而不使用glRotate!这会有点烦人,但那会100%解决你的问题。我自己也遇到了这个问题,找不到任何其他解决方案。 – 2012-03-16 06:20:09

回答

2

我想改变

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

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

是一个良好的开端。

+0

谢谢,你帮了很多。 – kahoon 2009-11-18 19:07:05

+5

问题是最后一个MatrixMode保持活动状态。 – Andreas 2009-12-01 14:24:43

0

FAQ states

的光的位置由 当前模型视图矩阵在 时间的位置与 调用glLight *(指定)变换。

换句话说,灯光没有定位在某种魔术静态的“世界坐标系”中;就像任何几何图形一样,它们乘以模型视图矩阵。这是有道理的;你经常想让灯锁定在几何体上。

我也认为你的应用程序“破坏”模型视图矩阵;它从来没有从头开始重新计算。您应该使用LoadIdentity()开始每个帧,然后发射光源,然后根据需要旋转,最后发射几何。

+0

如果模型视图矩阵被破坏,我认为我使用的旋转不起作用。无论如何,我尝试了你的建议(再次,因为我以前尝试过这样的事情),但它没有奏效。我知道光的位置乘以当前的矩阵,但它们只能在初始化时相乘,并且从来没有,因为我没有碰它。 – kahoon 2009-11-18 18:27:25

1

我也认为你的应用程序“破坏”模型视图 矩阵;它从来没有从头开始重新计算。你应该在 之间用LoadIdentity()开始每个帧,然后发射光源,然后根据需要旋转,最后发射 几何。

这不行,这不行,这不行,lalalalalalalala和常见问题是公然错误,简单明了。

只有在glLoadIdentity()后面发光才能获得摄像机绑定的光线,在仅转换或仅旋转原点周围的模型的简单情况下可以工作。但是,当你开始做非平凡的,非喜欢的事物时,例如围绕不同于原点的点旋转对象(translate(-v),rotate(angle),translate(v)),然后移动它,使旋转中心被带到相机的前面,然后“负载标识,地点灯”技术开始失败壮观和在很多方面,使得很难推断甚至正在进行。

不,我不知道解决方案。

0

在我看来你应该做的不仅是在渲染例程开始时调用glLoadIdentity(),而且还要推动和弹出模型视图矩阵。

用于与全局固定光源和其自主承担定位并旋转该伪代码将执行特技两个对象的场景:

glLoadIdentity(); 

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

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

我正在那样做,但灯光仍在移动。此外,我正在做什么说在其他答案:( – 2010-07-11 18:00:43

1

尝试手动每个顶点设置正常值。

1

我遇到了同样的问题,并得到了解决方案。问题是,我设置的灯光位置只有OnLoad程序的一部分...我认为这是最好的张贴一些代码。我在C#中使用OpenTK工作,因为我知道我永远不会进入图形业务。 :)

结果是一个茶壶或其他物体与具有固定位置的光线旋转。我可以移动眼睛位置(LookAt方法)并且光源保持静止。这就像真正的词:物体可以旋转,但太阳不会。 :)另外,我们可以在物体周围走动,但太阳依然不动,并且保持不动。这段代码会做到这一点。

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(); 
    } 

我把这个从我的程序,并删除了很多东西,在这里不重要,所以也许这看起来有点怪异。我希望它有帮助。