OpenGL gluLookAt()未按预期工作

OpenGL gluLookAt()未按预期工作,opengl,camera,glut,interpolation,glulookat,Opengl,Camera,Glut,Interpolation,Glulookat,我正在用OpenGL在skybox中制作过山车,没有太多关于它的功能或计算机图形的背景知识,这是非常困难的。我用Catmull Rom样条插值画了一个过山车,并用glVertex3f画了每个点。现在,我想每隔50毫秒调用一个update()函数,以在轨迹上移动摄影机gluLookAt()正在产生奇怪的结果,要么从屏幕上删除轨迹,要么产生黑屏,等等。我想我需要移动一些矩阵函数,但我不确定将每个函数放在哪里。以下是我目前的代码: int main(int argc, char** argc) {

我正在用OpenGL在skybox中制作过山车,没有太多关于它的功能或计算机图形的背景知识,这是非常困难的。我用Catmull Rom样条插值画了一个过山车,并用glVertex3f画了每个点。现在,我想每隔50毫秒调用一个
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++;
}
intmain(intargc,char**argc)
{
//…装载轨道等。。。
//Init currpos,nextpos,iter,向上
currpos=Vec3f(0,0,0);
nextpos=currpos;
iter=0;
up=Vec3f(0,1,0);
德克点;
Vec3f-newpt;
//通过点循环并插值
对于(PointVector pv=g_Track.points().begin();pv!=g_Track.points().end();pv++)
{
Vec3f curr(*pv);//初始化当前点和新点(待绘制)
points.push_back(curr);//将当前点推到堆栈上
allpoints.push_back(curr);//将当前点添加到总堆栈中
if(points.size()==4)//检查堆栈中是否有4个点,如果有,则进行插值
{
用于(浮动u=0.0f;u<1.0f;u+=0.01f)
{
newpt=插值(点[0],点[1],点[2],点[3],u);
gl3f(1,1,1);
glVertex3f(newpt.x(),newpt.y(),newpt.z());
所有点。推回(新点);
}
points.pop_front();
}
}
//glutInit、InitGL()等。。。
}
void InitGL(GLvoid)
{
glEnable(GLU深度试验);
glDepthFunc(GL_LEQUAL);
glMatrixMode(GL_投影);
glLoadIdentity();
GLU透视图(100.0,(GLfloat)窗宽/(GLfloat)窗高,.000119999);
glMatrixMode(GLU模型视图);
glClearColor(0.0f、0.0f、0.0f、0.5f);
}
作废显示(作废)
{
glClear(GL_颜色_缓冲_位| GL_深度_缓冲_位);
glMatrixMode(GLU模型视图);
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);//从现在开始启用纹理
/*绘制天空框,这是从上一次分配,并正确渲染*/
glPopMatrix();
//现在画过山车。。。
glPushMatrix();
glBegin(GL_线_带);
德克点;
Vec3f-newpt;
对于每个(所有点中的Vec3f pt)
{
gl3f(1,1,1);
glVertex3f(pt.x(),pt.y(),pt.z());
}
glutTimerFunc(50,更新,1);
格伦德();
glPopMatrix();
//交换缓冲区,这样就显示我们刚才画的缓冲区
glutSwapBuffers();
}
无效更新(INTA)
{
if(iter

我的想法是保留一个全局deque
allpoints
,其中包括样条曲线的控制点和插值点。完成后,我每50毫秒调用一次
update()
,并沿
allpoints
中的每个点移动相机。在项目的前一个版本中,我可以看到过山车的绘制是正确的。它是
gluLookAt()
,似乎无法按我所希望的方式工作。使用上面的代码,程序开始时,摄像机通过过山车的一部分查看skybox的一侧,然后在调用
update()
时,过山车消失,但摄像机不移动。我一直在乱搞OpenGL矩阵函数的放置位置,根据它们的位置,有时
update()
也会导致一个空白屏幕。

gluLookAt始终将其结果应用于当前矩阵,在您的例子中,这就是GL\U模型视图。但当渲染过山车时,会在该矩阵中加载标识,从而删除使用gluLookAt输入的值

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


我还建议您一帧只更改一次投影矩阵,而不是每一帧。

我已经很久没有接触OpenGL了,但这里有几点需要考虑:

  • 每次调用display(),您都会使用当前矩阵绘制skybox,然后加载标识矩阵以绘制过山车。也许在push/pop中加载标识,以便skybox保持不变,但会应用过山车上的主要转换
  • 是否需要在每次调用display()时调用gluPerspective和glMatrixMode
  • 从上到下反复计算binorm可能会在相机绕屏幕z轴旋转方面给您带来意想不到的结果
  • 对gluLookAt的调用似乎颠倒了nextpos和currpos,将相机指向相反的方向
  • (仅发表意见)如果天空盒完全静止,它看起来可能仍然很威严。绘制skybox和过山车时匹配相机旋转(但不平移)可能会更好

在您的代码中注意到
glPushMatrix()时不使用
glPopMatrix()

只是想一想,这可能有点什么
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 = ...;
}