Denis
Denis

Reputation: 41

Why in OpenGL my camera rotates 180 degrees every other time?

I want to do something like a 3d-shooter. The calculations seems to be correct, but it is works every other time with a spread with 180 degree rotation on every call glutPostRedisplay(). I understood that thanks to that red line. I do this with such IDE: Code Blocks / Qt Creator under Linux(Ubuntu x64).

main.cpp

#include "Functions.h"

int main(int argc, char** argv)
{
    glutInit(&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();
}

Upvotes: 1

Views: 279

Answers (1)

datenwolf
datenwolf

Reputation: 162164

You're using the fixed function stack, so you'll have to learn what glMatrixMode does and how transformation matrices are managed in those old ways.

Anyway, consider this a possible implementation of glMatrixMode

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

On other words, there's a (context) global matrix selected with glMatrixMode, that's subsequently used for all folloing matrix manipulations.

Hence, glMatrixMode is not some form of initialization, but something you use to switch (often several times) during rendering a frame! Your use of it in the main function is kind of pointless. You must use it in your drawing function.

Furthermore, every matrix manipulation multiplies on top, of what's currently in ctx->M. gluLookAt is normally used with a identity matrix. If you don't reset you identity, that gluLookAt will work relative to the look-at done previously. So what you want is this:

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();
}

(*) Also you normally want to clear to alpha = 1 on the main framebuffer, unless you're planning on drawing window-translucent imagery. With alpha = 0 things might look correct in the window, but if a screenshot is taken, or some screen recording or sharing is used, it may cause undesired transparence.

Upvotes: 2

Related Questions