OpenGL / Glut:使用箭头键使相机绕X轴旋转吗?

时间:2019-04-23 22:46:17

标签: c++ opengl glut opengl-compat

我正在尝试使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();
}

2 个答案:

答案 0 :(得分:1)

您可以使用gluLookAt上的init()初始化相机,然后在按箭头键时旋转它。如果要围绕局部X轴旋转相机,请假定初始Modelview矩阵为V,新发生的围绕X轴的旋转为R,则需要将Modelview矩阵设置为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 :(得分:0)

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

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

    // [...]

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

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

    // [...]
}

设置正交平面投影,该平面具有扩展的近平面和远平面。如果对象绕X轴旋转,则会在3个维度上占据空间:

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