OpenGL/Glut: 用方向键让相机绕X轴旋转?

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

我正在尝试制作 gluLookAt() 函数,以便当我按下向上和向下键时,相机围绕 X 轴移动

我正在尝试我在以下位置看到的方法:http://www.lighthouse3d.com/tutorials/glut-tutorial/keyboard-example-moving-around-the-world/ 但这对我不起作用。有人知道更简单的方法吗?我应该把 gluLookAt() 放在 myDisplay() 函数的什么地方?

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

您可以在 init() 使用 gluLookAt 初始化您的相机,然后在按下箭头键时旋转它。如果你想围绕它的局部 x 轴旋转相机,假设你的初始模型视图矩阵是 V,新发生的围绕 x 轴的旋转是 R,你需要将模型视图矩阵设置为 R*V,不是 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;

渲染过程中不需要重置模型视图矩阵,视图部分已经完成,确保在渲染整个场景后恢复它:

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

首先应该只有1个显示回调函数:

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

    // [...]

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

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

    // [...]
}

设置一个具有扩展的近平面和远平面的正交投影。如果物体绕X轴旋转,它在3个维度上需要space:

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

添加一个变量anglaX,在键盘事件中改变:

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

设置视图后旋转模型:

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

不要调用 glutSwapBuffers()glFlush()glutPostRedisplay(),除了 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();
}

另外我推荐使用双缓冲:

glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);