简体   繁体   中英

OpenGL/Glut: Making the camera rotate around X axis with arrow keys?

I'm trying to make the gluLookAt() function so that when I press the up & down key the camera moves around the X axis

I'm trying a method I saw at: http://www.lighthouse3d.com/tutorials/glut-tutorial/keyboard-example-moving-around-the-world/ but it's not working for me. Anyone knows an easier way? and where should I put the gluLookAt() so on myDisplay() func?

#include"glut.h"
#include<cmath>
#include<iostream>
using namespace std;

float xr = 0, yr = 0; //to control the object's movement from left to right

// actual vector representing the camera's direction
float lx = 0.0f, lz = -1.0f;
// XZ position of the camera
float x = 0.0f, z = 5.0f;

GLfloat angle = 0.0f;
int refreshmill = 1;

void timer(int value) { //to control the rotation of the object
    glutPostRedisplay();
    glutTimerFunc(refreshmill, timer, 0);
}

void myDisplay(void) {
    //Circle One
    float theta;
    glClear(GL_COLOR_BUFFER_BIT);
    glColor3f(1, 0, 0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glPushMatrix();
    glBegin(GL_POLYGON);
    for (int x = 0; x < 360; x++) {
        theta = x * 3.142 / 180;
        glVertex2f(150 * cos(theta)+xr,150 * sin(theta)+yr);
    }
    glEnd();
    glPopMatrix();

    //Circle Two
    float theta2;
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glPushMatrix();
    glTranslatef(0.5f, 0.0f, 0.0f); // rotation
    glRotatef(angle, 0.0f, 0.0f, -0.5f); // rotation
    glBegin(GL_POLYGON);
    glColor3f(0, 0, 1);
    for (int x = 0; x < 360; x++) {
        theta2 = x * 3.142 / 180;
        glVertex2f(150 + 15 * cos(theta2) + xr, 15 * sin(theta2) + yr);
    }
    glutSwapBuffers();
    angle += 0.2; // rotation
    glEnd();
    glPopMatrix();

    //Draw Star
    glColor3ub(119, 193, 15);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glPushMatrix();
    glBegin(GL_POLYGON);
    glVertex2d(15+xr, 60+yr);
    glVertex2d(75+xr, 75+yr); //right peak
    glVertex2d(15+xr, 90+yr);
    glVertex2d(0+xr, 150+yr); //Up-peak Changed
    glVertex2d(-15+xr, 90+yr);
    glVertex2d(-75+xr,75+yr);
    glVertex2d(-15+xr, 60+yr);
    glVertex2d(0+xr,0+yr);
    glEnd();
    glPopMatrix();
    glFlush();
    glutPostRedisplay();
    glutSwapBuffers();

}

void renderScene(void) {

    // Clear Color and Depth Buffers

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    // Reset transformations
    glLoadIdentity();
    // Set the camera
    gluLookAt(x, 1.0f, z,
        x + lx, 1.0f, z + lz,
        0.0f, 1.0f, 0.0f);

    // Draw ground
    glColor3f(0.9f, 0.9f, 0.9f);
    glBegin(GL_QUADS);
    glVertex3f(-100.0f, 0.0f, -100.0f);
    glVertex3f(-100.0f, 0.0f, 100.0f);
    glVertex3f(100.0f, 0.0f, 100.0f);
    glVertex3f(100.0f, 0.0f, -100.0f);
    glEnd();

    myDisplay();

    glutSwapBuffers();
}

//Move to left or right
void keyboard(int key, int x, int y) {

    float fraction = 0.1f;

    switch (key) {
    case GLUT_KEY_RIGHT:
        xr++;
        cout << x << endl;
        glutPostRedisplay();
        break;

    case GLUT_KEY_LEFT:
        xr--;
        cout << x << endl;
        glutPostRedisplay();
        break;

    case GLUT_KEY_UP:
        angle -= 0.01f;
        lx = sin(angle);
        lz = -cos(angle);
        break;

    case GLUT_KEY_DOWN:
        angle += 0.01f;
        lx = sin(angle);
        lz = -cos(angle);
        break;
    }
}

void init() {
    glClearColor(0, 0, 0, 1);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluOrtho2D(-250, 250, -250, 250); //IMPORTANT- Define from negative to positive
    glMatrixMode(GL_MODELVIEW);
}

int main(int argc, char** argv) {
    // init GLUT and create window
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
    glutInitWindowSize(500, 500);
    glutInitWindowPosition(0, 0);
    glutCreateWindow("Homework: Circle");
    // register callbacks
    glutDisplayFunc(myDisplay);
    glutDisplayFunc(renderScene);
    glutIdleFunc(renderScene);
    glutTimerFunc(0,timer,0);
    glutSpecialFunc(keyboard);
    // OpenGL init
    init();
    // enter GLUT event processing cycle
    glutMainLoop();
}

You can init your camera with gluLookAt at init() , then rotate it when arrow keys pressed. If you want to rotate camera around it's local x axis, assume your initial modelview matrix is V , newly happened rotation around x axis is R , you need to set modelview matrix to R*V , not V*R .

 case GLUT_KEY_UP:
       GLfloat temp[16];
       glGetFloatv(GL_MODELVIEW_MATRIX, temp);
       glLoadIdentity();
       glRotate(stepAngle, 1, 0, 0); // calculate stepAngle by your self
       glMultMatrixf(temp);
       break;

You don need to reset modelview matrix during rendering, view part is already done, make sure you restore it after rendering the whole scene:

glPushMatrix(GL_MODELVIEW_MATRIX)
// don't call glLoadIdentity() here, you don't need to reset view part.
...
...
glPopMatrix()

First of all there should be only 1 display call back function:

int main(int argc, char** argv) {

    // [...]

    // glutDisplayFunc(myDisplay); <----- DELETE!!!
    glutDisplayFunc(renderScene);

    // glutIdleFunc(renderScene);  <----- DELETE!!!

    // [...]
}

Setup an an orthographic projection with an extended near and far plane. If the object is rotated around the X axis, it takes space in the 3 dimensions:

void init() {
    glClearColor(0, 0, 0, 1);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(-250, 250, -250, 250, -250, 250); // <----
    glMatrixMode(GL_MODELVIEW);
}

Add a variable anglaX which is changed in the keyboard event:

float angleX = 0.0f;
void keyboard(int key, int x, int y) {

    switch (key) {
        case GLUT_KEY_RIGHT: xr++; break;
        case GLUT_KEY_LEFT:  xr--; break;
        case GLUT_KEY_UP:    angleX -= 1.0f; break;
        case GLUT_KEY_DOWN:  angleX += 1.0f; break;
    }
}

Rotate the model, after the view was set:

gluLookAt(x, 0.0f, z, x, 0.0f, z-1.0f, 0.0f, 1.0f, 0.0f);
glRotatef(angleX, 1, 0, 0);

Don't do any calls to glutSwapBuffers() , glFlush() and glutPostRedisplay() , except at the end of renderScene :

void timer(int value) { //to control the rotation of the object
    // glutPostRedisplay(); <--- DELETE
    glutTimerFunc(refreshmill, timer, 0);
}
void myDisplay(void) {
    //Circle One
    float theta;
    glClear(GL_COLOR_BUFFER_BIT);
    glColor3f(1, 0, 0);

    glPushMatrix();
    glBegin(GL_POLYGON);
    for (int x = 0; x < 360; x++) {
        theta = x * 3.142 / 180;
        glVertex2f(150 * cos(theta)+xr,150 * sin(theta)+yr);
    }
    glEnd();
    glPopMatrix();

    //Circle Two
    float theta2;

    glPushMatrix();
    glTranslatef(0.5f, 0.0f, 0.0f); // rotation
    glRotatef(angle, 0.0f, 0.0f, -0.5f); // rotation
    glBegin(GL_POLYGON);
    glColor3f(0, 0, 1);
    for (int x = 0; x < 360; x++) {
        theta2 = x * 3.142 / 180;
        glVertex2f(150 + 15 * cos(theta2) + xr, 15 * sin(theta2) + yr);
    }

    angle += 0.2; // rotation
    glEnd();
    glPopMatrix();

    //Draw Star
    glColor3ub(119, 193, 15);

    glPushMatrix();
    glBegin(GL_POLYGON);
    glVertex2d(15+xr, 60+yr);
    glVertex2d(75+xr, 75+yr); //right peak
    glVertex2d(15+xr, 90+yr);
    glVertex2d(0+xr, 150+yr); //Up-peak Changed
    glVertex2d(-15+xr, 90+yr);
    glVertex2d(-75+xr,75+yr);
    glVertex2d(-15+xr, 60+yr);
    glVertex2d(0+xr,0+yr);
    glEnd();
    glPopMatrix();
}
void renderScene(void) {

    // Clear Color and Depth Buffers
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    // Reset transformations
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    // Set the camera
    gluLookAt(x, 0.0f, z, x, 0.0f, z-1.0f, 0.0f, 1.0f, 0.0f);
    glRotatef(angleX, 1, 0, 0);

    // Draw ground
    glColor3f(0.9f, 0.9f, 0.9f);
    glBegin(GL_QUADS);
    glVertex3f(-100.0f, 0.0f, -100.0f);
    glVertex3f(-100.0f, 0.0f, 100.0f);
    glVertex3f(100.0f, 0.0f, 100.0f);
    glVertex3f(100.0f, 0.0f, -100.0f);
    glEnd();

    myDisplay();

    glFlush();
    glutPostRedisplay();
    glutSwapBuffers();
}

Further I recommend to use double buffering:

glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM