GluLookAt hoạt động như thế nào?


9

Từ sự hiểu biết của tôi,

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

tương đương với:

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

Nhưng khi tôi in ra ModelViewma trận, cuộc gọi đến glTranslatef()dường như không hoạt động đúng. Đây là đoạn mã:

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

Không có vấn đề gì giá trị tôi sử dụng cho các eyevector:
300, 0, 0hoặc
0, 300, 0hoặc
0, 0, 300
vector dịch là như nhau, mà không thực hiện bất kỳ ý nghĩa bởi vì thứ tự của mã là theo thứ tự ngược quá glTranslatefnên chạy đầu tiên, sau đó 2 phép quay. Thêm vào đó, ma trận xoay, hoàn toàn độc lập với cột dịch (trong ma trận ModelView), vậy thì điều gì sẽ gây ra hành vi kỳ lạ này? Đây là đầu ra với vector mắt là(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
--------------------------------------------------

Tôi mong đợi Tcột được (0, -300, 0)! Vì vậy, bất cứ ai có thể giúp tôi giải thích điều này?

Việc thực hiện gluLookAttừ 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);
}

Câu trả lời:


7

gluLookAtsẽ xoay và dịch thế giới theo cách mà camera sẽ được đặt {0, 0, 0}và nhìn về phía trục z âm. Đây là thiết lập máy ảnh được sử dụng trong OpenGL. Máy ảnh thực sự không bao giờ di chuyển, thế giới không. Nghe có vẻ khó hiểu? Chúa ơi, để tôi thử giải thích :)

Hãy lấy ví dụ này:

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

Đầu tiên chúng ta cần phải phân tích các phần quay của ma trận: R, UA. Như bạn có thể thấy vectơ bên phải ( R) không nằm trong trục x nữa {1, 0, 0}, nó nằm trong trục z {0, 0, 1}. Điều đó có nghĩa là nó được xoay 90 độ quanh trục y. Điều tương tự cũng xảy ra với vị trí mắt. Xoay {-300, 0, 0}90 độ quanh trục y cho phép nó kết thúc tại {0, 0, -300}, thì đấy, nó đây rồi.

Đó là -300và không phải 300vì thế giới được di chuyển chứ không phải máy ảnh, nên thế giới bị di chuyển theo hướng ngược lại, vẫn cách camera 300 đơn vị {0, 0, 0}. Và một lần nữa, nó được di chuyển về phía trục z âm, bởi vì đó là nơi mà camera OpenGL hướng đến, như đã đề cập ở trên.


Lưu ý: có một sự bất thường trong ví dụ của bạn, vectơ chuẩn hóa từ vị trí mắt đến điểm nhìn không được giống như vectơ hướng lên, vì vậy:

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

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

trong thực tế sẽ không hoạt động, chúng ta phải chọn một vector khác, ví dụ {1, 0, 0}


Cảm ơn rất nhiều, mặc dù tôi vẫn hơi bối rối mặc dù tôi hiểu lời giải thích của bạn.
Chan
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.