Почему в OpenGL моя камера поворачивается на 180 градусов через раз?

#c #opengl

#c #opengl

Вопрос:

Я хочу сделать что-то вроде 3D-шутера. Расчеты кажутся правильными, но это работает через раз с разбросом с поворотом на 180 градусов при каждом вызове glutPostRedisplay(). Я понял это благодаря этой красной строке. Я делаю это с помощью такой IDE: Code Blocks / Qt Creator под Linux (Ubuntu x64).

main.cpp

 #include "Functions.h"

int main(int argc, char** argv)
{
    glutInit(amp;argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
    glutInitWindowSize(wnd_width, wnd_height);
    glutInitWindowPosition(300, 100);
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_NORMALIZE);
    glMatrixMode(GL_PROJECTION);
    glMatrixMode(GL_MODELVIEW);
    glutCreateWindow("OpenGL my");
    glutDisplayFunc(display);
    glutIdleFunc(Idle);
    glutSpecialFunc(KeyPressed);
    GLdouble aspect = wnd_width/wnd_height;
    gluPerspective(90, aspect, 0.1, 10);
    glTranslatef(0, -0.3, 0);
    glutMainLoop();
    return 0;
}
 

Functions.h

 #include <GL/glut.h>
#include <math.h>
#include <iostream>

int wnd_width=1300;
int wnd_height=900;
float pos_x=0, pos_z=0.1;
float angle = 0;
float speed = 0.1;

void DrawFloor(){
    glVertex3d(1, 0, 2.5);
    glVertex3d(1, 0, 0);
    glVertex3d(-1, 0, 0);
    glVertex3d(-1, 0, 2.5);
}

void DrawWall(float x, float width, float height){
    glVertex3f(x, height, 0);
    glVertex3f(x, height, width);
    glVertex3f(x, 0, width);
    glVertex3f(x, 0, 0);
}

void DrawLine(){
    glVertex3f(0, 0.1, -1);
    glVertex3f(0, 0.1, 1);
}

void KeyPressed(int key, int x, int y){
    switch (key) {
    case GLUT_KEY_UP: {
        //pos_x = speed * cos(3.14*angle/180);
        //pos_z = speed * sin(3.14*angle/180);
        pos_z =0.1;
        break;
    }
    case GLUT_KEY_DOWN: {
        pos_x = speed*cos(angle);
        pos_z = speed*sin(angle);
        break;
    }
    case GLUT_KEY_LEFT: {
        angle  = 1;
        pos_x = speed * cos(3.14 * angle/180);
        pos_z = speed * sin(3.14 * angle/180);
        break;
    }
    case GLUT_KEY_RIGHT: {
        angle -= 3;
        pos_x = speed * cos(3.14 * angle/180);
        pos_z = speed * sin(3.14 * angle/180);
        break;
    }
    }
    std::cout<<"x: "<<pos_x<<'t';
    std::cout<<"z: "<<pos_z<<'n';
    glutPostRedisplay();
}

void display(){
    glClearColor(0.6, 0.8, 1, 0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    gluLookAt(pos_x, 0, pos_z, pos_x, 0, pos_z 0.2, 0, 1, 0);

    glBegin(GL_QUADS);
    glColor3f(0, 0, 0.7);
    DrawFloor();
    glColor3f(0, 0.8, 0.1);
    DrawWall(-0.5, 2, 0.7);
    DrawWall(0.5, 2, 0.7);
    glEnd();

    glLineWidth(2);
    glColor3f(0.7, 0.2, 0.2);
    glBegin(GL_LINES);
    DrawLine();
    glEnd();
    glutSwapBuffers();
}

void Idle(){
    //pos_z =0.01;
    //glutPostRedisplay();
}

 

Комментарии:

1. разве не pos_x = ??? следует ссылаться на старую позицию? нравится pos.x = pos.x speed.x ?

Ответ №1:

Вы используете фиксированный стек функций, поэтому вам придется изучить, что glMatrixMode и как матрицы преобразования управляются этими старыми способами.

В любом случае, рассмотрите это как возможную реализацию glMatrixMode

 void glMatrixMode(GLenum m)
{
    switch(m){
    case GL_MODELVIEW:  ctx->M = amp;ctx->matrix_modelview;  break;
    case GL_PROJECTION: ctx->M = amp;ctx->matrix_projection; break;
    case GL_TEXTURE:    ctx->M = amp;ctx->matrix_texture;    break;
    case GL_COLOR:      ctx->M = amp;ctx->matrix_color;      break;
    }
}
 

Другими словами, существует (контекстная) глобальная матрица, выбранная с glMatrixMode помощью , которая впоследствии используется для всех последующих манипуляций с матрицей.

Следовательно, glMatrixMode это не какая-то форма инициализации, а то, что вы используете для переключения (часто несколько раз) во время рендеринга кадра! Ваше использование его в main функции в некотором роде бессмысленно. Вы должны использовать его в своей функции рисования.

Кроме того, каждая манипуляция с матрицей умножается поверх того, что есть в данный момент ctx->M . gluLookAt обычно используется с идентификационной матрицей. Если вы не сбросите свою личность, это gluLookAt будет работать по сравнению с предыдущим просмотром. Итак, что вы хотите, это:

 void display(){
    glClearColor(0.6, 0.8, 1., 1.); /* <<<----* */
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glMatrixMode(GL_PROJECTIOM);
    glLoadIdentity();
    setup_projection_here();

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(pos_x, 0, pos_z, pos_x, 0, pos_z 0.2, 0, 1, 0);

    glBegin(GL_QUADS);
    /* ... */

    glutSwapBuffers();
}
 

(*) Кроме того, вы обычно хотите очистить alpha = 1 в главном фреймбуфере, если только вы не планируете рисовать изображения, полупрозрачные в окне. В alpha = 0 окне все может выглядеть правильно, но если сделан снимок экрана или используется какая-либо запись экрана или совместное использование, это может привести к нежелательной прозрачности.