OpenGL gluLookAt()没有按预期工作



我在OpenGL中制作一个云霄飞车,没有太多关于它的功能或计算机图形学的背景,这被证明是非常困难的。我使用Catmull-Rom样条插值绘制了一个过山车,并使用glVertex3f绘制了每个点。现在我想每隔50ms调用一个update()函数来移动摄像机。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++;
}

这个想法是,我保持一个全局deque allpoints,包括样条的控制点和插值点。一旦完成,我每隔50毫秒调用update(),并沿着allpoints中的每个点移动相机。在项目的前一个版本中,我可以看到过山车是正确绘制的。这是gluLookAt(),似乎不工作,我想要它。在上面的代码中,程序开始时,相机看着云霄飞车的一侧,然后当调用update()时,云霄飞车消失了,但相机没有移动。我一直在搞乱我把OpenGL矩阵函数,并根据他们有时update()会导致一个空白屏幕以及。

除了缺少glPopMatrix (user971377已经发现)之外,您还可以在绘图例程中调用glLoadIdentity,这当然会覆盖您在update方法(使用gluLookAt)中对modelview矩阵所做的任何更改。

始终记住:gluLookAt, glOrtho, gluPerspective, glTranslate, glRotate以及所有其他矩阵和变换函数总是在当前选择的矩阵堆栈(由glMatrixMode更改)的顶部元素(由glPush/PopMatrix更改)上工作。它们总是乘以当前矩阵,而不是替换它。因此,与gluPerspective一样,您应该在调用gluLookAt之前调用glLoadIdentity。并且整个摄像机的更改应该在渲染例程中完成,而不是在更新例程中完成。

与其在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 = ...;
}

}

注意到在您的代码中glPushMatrix();被调用而没有glPopMatrix();

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

gluLookAt总是将其结果应用于当前矩阵,在您的示例中是GL_MODEL_VIEW。但是当你渲染过山车时,你会在矩阵中加载标识符,这将擦除你使用gluLookAt设置的值。

在这种情况下,您不需要触摸模型视图。实际上,GL_MODEL_VIEW表示模型矩阵乘以视图矩阵。在这种情况下,您可以在glPushMatrix()后面跟着glMulMatrix( myModelMatrix ),然后渲染glPopMatrix()。这样,您可以将视图矩阵保留在GL_MODEL_VIEW中,并且仍然为每个对象使用不同的模型矩阵

我也建议你只改变投影矩阵一次一帧,而不是每帧

我接触OpenGL已经很长时间了,但这里有一些事情需要考虑:

  • 每次调用display()时,您都是用当前矩阵绘制天空框,然后加载单位矩阵来绘制过山车。也许可以在push/pop中加载标识,这样天空框是恒定的,但是你在过山车上的流行变换被应用。
  • 你需要调用gluPerspective和glMatrixMode与每次调用display()吗?
  • 反复计算从上到下的双象,可能会给你意想不到的结果,相机围绕屏幕的z轴旋转。
  • 对gluLookAt的调用似乎颠倒了nextpos和currpos,将相机指向相反的方向。
  • (仅供意见)它可能仍然看起来很奇怪,一个完全静止的天空盒。在绘制天空盒和过山车时匹配相机旋转(但不是平移)可能会更好看。

相关内容

  • 没有找到相关文章

最新更新