2011-10-11 93 views
5

我在OpenGL中的天空盒内制作过山车,并且没有太多关于它的功能或计算机图形的背景,它证明是非常困难的。我用Catmull-Rom样条插值绘制了过山车,并用glVertex3f绘制了每个点。现在我想每50ms调用一次update()函数来移动摄像机在轨道上。 gluLookAt()正在产生奇怪的结果,无论是从屏幕上移除轨道,产生黑屏等。我想我需要移动一些矩阵函数,但我不确定在哪里放置每一个。这是我到目前为止的代码:OpenGL gluLookAt()未按预期工作

int main(int argc, char** argc) 
{ 
    // ... load track, etc ... 

    // Init currpos, nextpos, iter, up 
    currpos = Vec3f(0, 0, 0); 
    nextpos = currpos; 
    iter = 0; 
    up = Vec3f(0, 1, 0); 

    deque<Vec3f> points; 
    Vec3f newpt; 

    // Loop through the points and interpolate 
    for (pointVectorIter pv = g_Track.points().begin(); pv != g_Track.points().end(); pv++) 
    { 
     Vec3f curr(*pv);   // Initialize the current point and a new point (to be drawn) 
     points.push_back(curr);  // Push the current point onto the stack 
     allpoints.push_back(curr); // Add current point to the total stack 

     if (points.size() == 4) // Check if there are 4 points in the stack, if so interpolate 
     { 
      for (float u = 0.0f; u < 1.0f; u += 0.01f) 
      { 
       newpt = interpolate(points[0], points[1], points[2], points[3], u); 
       glColor3f(1, 1, 1); 
       glVertex3f(newpt.x(), newpt.y(), newpt.z()); 

       allpoints.push_back(newpt); 
      } 

      points.pop_front(); 
     } 
    } 

    // glutInit, InitGL(), etc... 
} 

void InitGL(GLvoid) 
{ 
    glEnable(GL_DEPTH_TEST); 
    glDepthFunc(GL_LEQUAL); 
    glMatrixMode(GL_PROJECTION); 
    glLoadIdentity(); 
    gluPerspective(100.0, (GLfloat)WINDOW_WIDTH/(GLfloat)WINDOW_HEIGHT, .0001, 999999); 
    glMatrixMode(GL_MODELVIEW); 
    glClearColor(0.0f, 0.0f, 0.0f, 0.5f); 
} 

void display (void) 
{ 
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 
    glMatrixMode(GL_MODELVIEW); 
    glLoadIdentity(); 
    gluLookAt(currpos.x(), currpos.y(), currpos.z(), nextpos.x(), nextpos.y(), nextpos.z(), up.x(), up.y(), up.z()); 

    glPushMatrix(); 
    glEnable(GL_TEXTURE_2D); // Enable texturing from now on 

    /* draw skybox, this was from previous assignment and renders correctly */ 

    glPopMatrix(); 

    // now draw rollercoaster ... 

    glPushMatrix(); 
    glBegin(GL_LINE_STRIP); 

    deque<Vec3f> points; 
    Vec3f newpt; 

    for each (Vec3f pt in allpoints) 
    { 
     glColor3f(1, 1, 1); 
     glVertex3f(pt.x(), pt.y(), pt.z()); 
    } 

    glutTimerFunc(50, update, 1); 
    glEnd(); 
    glPopMatrix(); 

    // Swap buffers, so one we just drew is displayed 
    glutSwapBuffers(); 
} 

void update(int a) 
{ 
    if (iter < allpoints.size()) 
    { 
     currpos = allpoints[iter]; 
     nextpos = allpoints[iter + 1]; 

     gaze = nextpos - currpos; 
     gaze.Normalize(); 

     Vec3f::Cross3(binorm, gaze, up); 
     binorm.Normalize(); 

     Vec3f::Cross3(up, binorm, gaze); 
     up.Normalize(); 

     glutPostRedisplay(); 
    } 

    iter++; 
} 

的想法是,我保持一个全球性的双端队列allpoints包括样条曲线的控制点和插值点。一旦完成,我每隔50ms拨打update(),并沿着allpoints的每个点移动摄像机。在该项目的以前版本中,我可以看到过山车正在正确绘制。这是gluLookAt(),似乎并没有工作,我想如何。使用上面的代码,程序开始时摄像头用一部分过山车看着天空盒的一侧,然后当update()被调用时,过山车消失,但摄像机不动。我一直在搞乱OpenGL矩阵功能,根据它们的位置有时update()也会导致一个空白屏幕。

回答

5

除了没有glPopMatrix(其中user971377已发现),你在你的绘图程序,这当然会覆盖您在update方法做了模型视图矩阵的任何更改(使用gluLookAt)调用glLoadIdentity

始终牢记:gluLookAtglOrthogluPerspectiveglTranslateglRotate,和所有其他矩阵和转换功能始终是当前选定的矩阵堆栈(由glMatrixMode改变)的顶级元素(由glPush/PopMatrix改变)上工作。它们总是乘以当前的矩阵,而不是替换它。对于gluPerspective,您应该致电glLoadIdentity,然后致电gluLookAt。整个相机的改变应该在渲染程序中完成,而不是更新程序。

而是在update做任何GL转换的,你应该改变,而其上的摄像头所依赖的变量和方法display设定相机(gluLookAt在模型视图矩阵)。为了证明标准的使用这些功能,你的代码应该是这样的:

void display() 
{ 
    <general state setup (glClear, ...)> 

    glMatrixMode(GL_MODELVIEW); 
    glLoadIdentity(); 
    glLookAt(camera);  //view transformation (camera) 

    //object 1 
    glPushMatrix();  //save modelview 
    glTranslate/glRotate/glScale;  //local model transformations 
    <draw object 1> 
    glPopMatrix(); 
    ... 
    //object n 
    glPushMatrix();  //save modelview 
    glTranslate/glRotate/glScale;  //local model transformations 
    <draw object n> 
    glPopMatrix(); 

    gluSwapBuffers(); 
} 

void update() 
{ 
    camera = ...; 
} 

}

+0

对不起,'glPopMatrix()'是在过山车之前的天空盒代码的末尾(因为我没有包含天空盒代码,所以我在问题中忘记了它) - 是它应该去的地方,还是应该在过山车之后? –

+0

@Logan尽管控制流在运行时可能是相同的,但是'glPopMatrix'应该与'glPushMatrix'处于相同的范围,因为两者都代表一个整体,并且应该始终成对。 –

+0

我的意思是,如果'glPopMatrix()'在注释过的天空盒代码之后(在用'glVertex3f'绘制rc之前)之后,还是在循环之后用'glVertex3f'绘制rc? –

0

gluLookAt总是将其结果应用到当前矩阵,在你的情况下它是GL_MODEL_VIEW。但是当你渲染你的过山车时,你会在这个矩阵中加载身份,这会抹掉你使用gluLookAt的值。

在这种情况下,您不需要触摸模型视图。实际上,GL_MODEL_VIEW表示模型矩阵乘以视图矩阵。在这种情况下,您可以glPushMatrix()后跟glMulMatrix(myModelMatrix)并在呈现glPopMatrix()后。有了这个,你可以将视图矩阵保留在GL_MODEL_VIEW中,并且每个对象仍然使用不同的模型矩阵。我还建议你只改变投影矩阵一次而不是每帧。

0

它一直以来我感动OpenGL的很长一段时间,但这里要考虑几件事情:显示

  • 每次调用(),您绘制有那么当前矩阵加载身份天空盒矩阵绘制过山车。也许在push/pop内加载身份,以使天空盒保持不变,但是你在云霄飞车上的流行变形被应用。
  • 您是否需要每次调用display()时调用gluPerspective和glMatrixMode?
  • 反复从上往上计算binorm,然后从binorm开始,可能会给您带来意想不到的结果,即相机在屏幕z轴周围的旋转。
  • 对gluLookAt的调用似乎有反向的nextpos和currpos,将相机指向相反的方向。
  • (仅限意见)使用完全静止的天空盒可能仍会看起来很奇怪。在绘制天空盒和过山车时匹配相机旋转(但不能平移)可能会更好看。
+0

谢谢,您的建议是工作好(我认为),因为本身现在与相机旋转过山车。相机本身虽然行动起来,但它并未遵循轨道,最终失去控制并走出了天空盒。我确实切换了下一个位置和currpos,所以这可能是由于binorm/up向量计算?你知道如何计算这些,因为我的代码中有我们的TA所建议的。 –

+0

up的计算只应该影响相机的旋转角度,这并不能解释它在天空盒之外的转换。你的控制点是否使用与OpenGL相同的xyz方向? – SlightNihilism

+0

同时,如果你的过山车从来没有在步骤之间完全上下摆动,那么你应该能够保持“向上”稳定。我甚至会暂时调整轨道,以便我可以使用这种方法,直到我设法调试/测试相机的xyz位置。然后我担心之后会有更安全的计算。不幸的是,我没有推荐这种计算方法。 – SlightNihilism

3

在你的代码glPushMatrix();注意到的是所谓的无glPopMatrix();

只是一个想法,这可能是与你的问题。