OpenGL / Glut: заставить камеру вращаться вокруг оси X с помощью клавиш со стрелками? - PullRequest
2 голосов
/ 24 апреля 2019

Я пытаюсь настроить функцию 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 ]

1 голос
/ 24 апреля 2019

Вы можете запустить камеру с помощью gluLookAt на init(), а затем повернуть ее, когда нажаты клавиши со стрелками. Если вы хотите повернуть камеру вокруг своей локальной оси 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()
0 голосов
/ 24 апреля 2019

Прежде всего, должна быть только одна функция обратного вызова дисплея:

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

...