Comment fonctionne gluLookAt?

9

De ma compréhension,

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

est équivalent à:

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

Mais lorsque j'imprime la ModelViewmatrice, l'appel à glTranslatef()ne semble pas fonctionner correctement. Voici l'extrait de code:

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

Peu importe la valeur que j'utilise pour le eyevecteur:
300, 0, 0ou
0, 300, 0ou
0, 0, 300
le vecteur de traduction est le même, ce qui n'a aucun sens car l'ordre du code est en ordre inverse et glTranslatefdoit donc s'exécuter en premier, puis les 2 rotations. De plus, la matrice de rotation est complètement indépendante de la colonne de traduction (dans la matrice ModelView), alors qu'est-ce qui provoquerait ce comportement étrange? Voici la sortie avec le vecteur oeil est(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
--------------------------------------------------

Je m'attendrais à ce que la Tcolonne soit (0, -300, 0)! Alors, quelqu'un pourrait-il m'aider à expliquer cela?

La mise en œuvre de gluLookAtde 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
la source

Réponses:

7

gluLookAtfera pivoter et translater le monde d'une manière, que la caméra sera située {0, 0, 0}et regarde vers l'axe z négatif. Il s'agit de la configuration de la caméra utilisée dans OpenGL. La caméra ne bouge jamais, le monde le fait. Cela vous semble confus? Enfer ouais, laissez-moi essayer d'expliquer :)

Prenons cet exemple:

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

Nous devons d'abord analyser la partie de rotation de la matrice: R, Uet A. Comme vous pouvez le voir, le bon vecteur ( R) n'est plus sur l'axe des x {1, 0, 0}, il est sur l'axe des z {0, 0, 1}. Cela signifie qu'il est tourné de 90 degrés autour de l'axe y. Il en va de même pour la position des yeux. Une rotation {-300, 0, 0}de 90 degrés autour de l'axe des y permet de se retrouver à {0, 0, -300}, le tour est joué.

C'est -300et pas 300parce que le monde est déplacé et non pas la caméra, donc le monde est déplacé dans la direction opposée, toujours à 300 unités de la caméra {0, 0, 0}. Et encore une fois, il est déplacé vers l'axe z négatif, car c'est là que la caméra OpenGL regarde, comme mentionné ci-dessus.


Remarque: il y a une anomalie dans votre exemple, le vecteur normalisé de la position des yeux au point de vue ne doit pas être le même que le vecteur up, donc:

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

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

ne fonctionnera pas, nous devons choisir un autre vecteur ascendant, par exemple {1, 0, 0}

Maik Semder
la source
Merci beaucoup, même si je suis encore un peu confus même si je comprends votre explication.
Chan