Wie funktioniert gluLookAt?

9

Meinem Verständnis nach,

gluLookAt(
        eye_x, eye_y, eye_z,
        center_x, center_y, center_z,   
        up_x, up_y, up_z
    );

ist äquivalent zu:

glRotatef(B, 0.0, 0.0, 1.0);
glRotatef(A, wx, wy, wz);
glTranslatef(-eye_x, -eye_y, -eye_z);

Aber wenn ich die ModelViewMatrix ausdrucke, glTranslatef()scheint der Aufruf von nicht richtig zu funktionieren. Hier ist das Code-Snippet:

#include <stdlib.h>
#include <stdio.h>
#include <GL/glut.h>

#include <iomanip>
#include <iostream>
#include <string>

using namespace std;

static const int Rx = 0;
static const int Ry = 1;
static const int Rz = 2;

static const int Ux = 4;
static const int Uy = 5;
static const int Uz = 6;

static const int Ax = 8;
static const int Ay = 9;
static const int Az = 10;

static const int Tx = 12;
static const int Ty = 13;
static const int Tz = 14;

void init() {
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glEnable(GL_DEPTH_TEST);
    glShadeModel(GL_SMOOTH);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    GLfloat lmodel_ambient[] = { 0.8, 0.0, 0.0, 0.0 };
    glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
}

void displayModelviewMatrix(float MV[16]) {
    int SPACING = 12;
    cout << left;
    cout << "\tMODELVIEW MATRIX\n";
    cout << "--------------------------------------------------" << endl;
    cout << setw(SPACING) << "R" << setw(SPACING) << "U" << setw(SPACING) << "A" << setw(SPACING) << "T" << endl;   
    cout << "--------------------------------------------------" << endl;
    cout << setw(SPACING) << MV[Rx] << setw(SPACING) << MV[Ux] << setw(SPACING) << MV[Ax]  << setw(SPACING) << MV[Tx] << endl;
    cout << setw(SPACING) << MV[Ry] << setw(SPACING) << MV[Uy] << setw(SPACING) << MV[Ay]  << setw(SPACING) << MV[Ty] << endl;
    cout << setw(SPACING) << MV[Rz] << setw(SPACING) << MV[Uz] << setw(SPACING) << MV[Az] << setw(SPACING)  << MV[Tz] << endl;
    cout << setw(SPACING) << MV[3] << setw(SPACING) << MV[7] << setw(SPACING) << MV[11] << setw(SPACING) << MV[15] << endl;
    cout << "--------------------------------------------------" << endl;
    cout << endl;
}

void reshape(int w, int h) {
    float ratio = static_cast<float>(w)/h;
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(45.0, ratio, 1.0, 425.0);
}

void draw() {
    float m[16];
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glGetFloatv(GL_MODELVIEW_MATRIX, m);
    gluLookAt(
        300.0f, 0.0f, 0.0f,
        0.0f, 0.0f, 0.0f,
        0.0f, 1.0f, 0.0f
    );
    glColor3f(1.0, 0.0, 0.0);
    glutSolidCube(100.0);
    glGetFloatv(GL_MODELVIEW_MATRIX, m);
    displayModelviewMatrix(m);
    glutSwapBuffers();
}


int main(int argc, char** argv) {
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
    glutInitWindowSize(400, 400);
    glutInitWindowPosition(100, 100);
    glutCreateWindow("Demo");
    glutReshapeFunc(reshape);
    glutDisplayFunc(draw);
    init();
    glutMainLoop();
    return 0;
} 

Egal welchen Wert ich für den eyeVektor verwende:
300, 0, 0oder
0, 300, 0oder
0, 0, 300
der Übersetzungsvektor ist der gleiche, was keinen Sinn ergibt, da die Reihenfolge des Codes in Rückwärtsreihenfolge ist und daher zuerst ausgeführt werden glTranslatefsollte, dann die 2 Umdrehungen. Außerdem ist die Rotationsmatrix völlig unabhängig von der Übersetzungsspalte (in der ModelView-Matrix). Was würde dann dieses seltsame Verhalten verursachen? Hier ist die Ausgabe mit dem Augenvektor(0.0f, 300.0f, 0.0f)

        MODELVIEW MATRIX
--------------------------------------------------
R           U           A           T
--------------------------------------------------
0           0           0           0
0           0           0           0
0           1           0           -300
0           0           0           1
--------------------------------------------------

Ich würde erwarten, dass die TKolumne ist (0, -300, 0)! Könnte mir jemand helfen, das zu erklären?

Die Implementierung von gluLookAtvon http://www.mesa3d.org

void GLAPIENTRY
gluLookAt(GLdouble eyex, GLdouble eyey, GLdouble eyez, GLdouble centerx,
      GLdouble centery, GLdouble centerz, GLdouble upx, GLdouble upy,
      GLdouble upz)
{
    float forward[3], side[3], up[3];
    GLfloat m[4][4];

    forward[0] = centerx - eyex;
    forward[1] = centery - eyey;
    forward[2] = centerz - eyez;

    up[0] = upx;
    up[1] = upy;
    up[2] = upz;

    normalize(forward);

    /* Side = forward x up */
    cross(forward, up, side);
    normalize(side);

    /* Recompute up as: up = side x forward */
    cross(side, forward, up);

    __gluMakeIdentityf(&m[0][0]);
    m[0][0] = side[0];
    m[1][0] = side[1];
    m[2][0] = side[2];

    m[0][1] = up[0];
    m[1][1] = up[1];
    m[2][1] = up[2];

    m[0][2] = -forward[0];
    m[1][2] = -forward[1];
    m[2][2] = -forward[2];

    glMultMatrixf(&m[0][0]);
    glTranslated(-eyex, -eyey, -eyez);
}
Chan
quelle

Antworten:

7

gluLookAtdreht sich und übersetzt die Welt so, dass sich die Kamera {0, 0, 0}auf der negativen Z-Achse befindet und in diese schaut. Dies ist das in OpenGL verwendete Kamera-Setup. Die Kamera bewegt sich eigentlich nie, die Welt schon. Klingt verwirrend? Hölle ja, lass mich versuchen zu erklären :)

Nehmen wir dieses Beispiel:

eye    :  {300, 0, 0}
lookat :  {  0, 0, 0}
up     :  {  0, 1, 0}

MODELVIEW MATRIX
--------------------------------------------------
R           U           A           T           
--------------------------------------------------
0           0           -1          0           
0           1           0           0           
1           0           0           -300        
0           0           0           1           
--------------------------------------------------

Zunächst müssen wir den Dreh Teil der Matrix analysieren: R, Uund A. Wie Sie sehen, befindet sich der rechte Vektor ( R) nicht mehr auf der x-Achse {1, 0, 0}, sondern auf der z-Achse {0, 0, 1}. Das heißt, es wird um 90 Grad um die y-Achse gedreht. Das gleiche passiert mit der Augenposition. Wenn Sie sich {-300, 0, 0}um 90 Grad um die y-Achse {0, 0, -300}drehen, endet es bei voila, da ist es.

Es ist -300und nicht, 300weil die Welt bewegt wird und nicht die Kamera, also wird die Welt in die entgegengesetzte Richtung bewegt, immer noch 300 Einheiten von der Kamera entfernt {0, 0, 0}. Und wieder wird es in Richtung der negativen Z-Achse bewegt, da die OpenGL-Kamera dort wie oben erwähnt hinschaut.


Hinweis: In Ihrem Beispiel gibt es eine Anomalie. Der normalisierte Vektor von der Augenposition zum Betrachtungspunkt darf nicht mit dem Aufwärtsvektor identisch sein.

eye    : {0, 300, 0}
lookat : {0,   0, 0}
up     : {0,   1, 0}    

normalize(eye - lookat): {0, 1, 0} -> the same as the up-vector

wird in der Tat nicht funktionieren, müssen wir zum Beispiel einen anderen Aufwärtsvektor auswählen {1, 0, 0}

Maik Semder
quelle
Vielen Dank, obwohl ich immer noch ein wenig verwirrt bin, obwohl ich Ihre Erklärung verstehe.
Chan