OpenGL gluLookAt () не работает должным образом - PullRequest
5 голосов
/ 11 октября 2011

Я делаю американские горки внутри скайбокса в OpenGL, и без особых знаний о его функциях или компьютерной графике это оказывается очень трудным. Я нарисовал американские горки, используя сплайн-интерполяцию Catmull-Rom, и нарисовал каждую точку с помощью glVertex3f. Теперь я хочу вызывать функцию update() каждые 50 мс, чтобы перемещать камеру по дорожке. 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, которая включает в себя контрольные точки сплайна и интерполированные точки. Как только это будет завершено, я звоню update() каждые 50 мс и перемещаю камеру вдоль каждой точки в allpoints. В предыдущей версии проекта я видел, что американские горки были нарисованы правильно. Кажется, что gluLookAt() не работает так, как я хочу. С помощью приведенного выше кода программа начинается с того, что камера смотрит на одну сторону скайбокса с частью американских горок, а затем, когда вызывается update(), американские горки исчезают, но камера не двигается. Я возился с тем, куда я помещаю матричные функции OpenGL, и в зависимости от того, где они иногда update() также приведет к пустому экрану.

Ответы [ 4 ]

5 голосов
/ 11 октября 2011

Помимо отсутствия glPopMatrix (который пользователь971377 уже определил), вы вызываете glLoadIdentity в своей процедуре рисования, которая, конечно, перезаписывает любые изменения, которые вы сделали в матрице вида модели в методе update (используя gluLookAt).

Всегда имейте в виду: gluLookAt, glOrtho, gluPerspective, glTranslate, glRotate, а все другие функции матрицы и преобразования всегда работают с верхним элементом (изменено с помощью glPush/PopMatrix) текущего выбранного стека матрицы (изменено на glMatrixMode).И они всегда умножают текущую матрицу, вместо того, чтобы заменить ее.Так же, как и для gluPerspective, вам следует позвонить glLoadIdentity перед тем, как позвонить gluLookAt.И все изменения камеры должны быть выполнены в процедуре рендеринга, а не в процедуре обновления.

Вместо того, чтобы делать какие-либо преобразования GL в update, вы должны скорее изменить переменные, от которых зависит камера, и установить камеру(gluLookAt на матрице вида модели) в методе display.Чтобы продемонстрировать стандартное использование этих функций, ваш код должен выглядеть примерно так:

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

}

3 голосов
/ 11 октября 2011

Замечено в вашем коде glPushMatrix(); вызывается без glPopMatrix();

Просто мысль, это может иметь какое-то отношение к вашей проблеме.

0 голосов
/ 11 октября 2011

Прошло много времени с тех пор, как я коснулся OpenGL, но вот несколько вещей, на которые следует обратить внимание:

  • При каждом вызове display () вы рисуете скайбокс с текущей матрицей, а затем загружаетеединая матрица для рисования на американских горках.Возможно, загрузите идентификатор в push / pop, чтобы скайбокс оставался постоянным, но ваши преобладающие преобразования на американских горках применяются.
  • Вам нужно вызывать gluPerspective и glMatrixMode при каждом вызове display ()?
  • Повторное вычисление бинорма вверх и затем вверх из бинорма, вероятно, даст вам неожиданные результаты с точки зрения поворота камеры вокруг оси z экрана.
  • Вызов gluLookAt, по-видимому, имеет nextpos и currpos.перевернут, указывая камеру в противоположном направлении.
  • (Только мнение) Он может выглядеть странно с полностью стационарным скайбоксом.Соответствующее вращение камеры (но не перемещение) при рисовании скайбокса и американских горок может выглядеть лучше.
0 голосов
/ 11 октября 2011

gluLookAt всегда применяет свой результат к текущей матрице, которая в вашем случае является GL_MODEL_VIEW.Но когда вы визуализируете ваши американские горки, вы загружаете идентичность в эту матрицу, которая стирает значение, введенное с помощью gluLookAt. * ​​1001 *

В этом случае вам не нужно прикасаться к представлению модели.Фактически, GL_MODEL_VIEW означает матрицу модели, умноженную на матрицу вида.В этом случае вы можете glPushMatrix(), затем glMulMatrix( myModelMatrix ) и после рендеринга glPopMatrix().Благодаря этому вы можете сохранить матрицу вида внутри GL_MODEL_VIEW и по-прежнему использовать разные матрицы моделей для каждого объекта

. Я также предлагаю менять матрицу проекции только один раз, а не каждый кадр.

...