【问题标题】:How does gluLookAt work?gluLookAt 是如何工作的?
【发布时间】:2012-10-31 19:27:25
【问题描述】:

据我了解,

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

相当于:

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

但是当我打印出ModelView 矩阵时,对glTranslatef() 的调用似乎无法正常工作。这是代码sn-p:

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

无论我对eye 向量使用什么值:
300, 0, 0
0, 300, 0
0, 0, 300
平移向量是相同的,这没有任何意义,因为代码的顺序是倒序的,所以 glTranslatef 应该首先运行,然后是 2 次旋转。另外,旋转矩阵完全独立于平移列(在 ModelView 矩阵中),那么什么会导致这种奇怪的行为呢? 这是眼睛向量的输出是(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 列是(0, -300, 0)!那么有人可以帮我解释一下吗?

http://www.mesa3d.org实现gluLookAt

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

【问题讨论】:

  • 请在执行 3 次转换的地方发布代码,而不是 gluLookAt。你确定 gluLookAt 等同于它们吗?我看到了它的实现,但我很困惑如何使用 forwardupside 向量执行旋转代码..(前 3 列)pastebin.com/2HQvKBH7
  • @Max:我相信是的。事实上,实际实现中的最后一行是glTranslated(-eyex, -eyey, -eyez),所以我的假设一定是正确的。 forwardupside 向量仅用于左上角3x3 矩阵,所以我看不出它们如何影响平移向量?
  • 是的,旋转不会影响平移向量。我的意思是,请在您使用这 3 个调用而不是 gluLookAt 的位置发布代码。这可能是错误的..
  • 尝试查看here 以获得一些提示

标签: c++ opengl glulookat


【解决方案1】:

如果我们让旋转和平移矩阵像您的模型视图矩阵一样

Rxx Rxy Rxz Tx 
Ryx Ryy Ryz Ty 
Rzx Rzy Rzz Tz 
 0   0   0   1 

作用于任意向量

x
y
z
1

我们得到

Rxx x + Rxy y + Rxz z  +  Tx 
Ryx x + Ryy y + Ryz z  +  Ty
Rzx x + Rzy y + Rzz z  +  Tz
1

(我在写东西,所以向量乘以左边的矩阵)。

这表明矩阵的平移分量在进行旋转后 给出了平移。这就是为什么它们与您的 (-eye_x, -eye_y, -eye_z) 向量不同的原因,因为正如您指出的那样,平移是在旋转之前完成的。

平移总是沿 -z 方向的原因是因为在视图框架中 -z 方向指向中心。由于您的中心始终距眼睛 300 个单位,因此您的所有眼睛位置都将中心置于视图框架中的 (0, 0, -300) 处。因此,因为中心在我们进行任何翻译之前从原点开始,所以为它提供正确坐标的翻译必须是 (0, 0, -300)。

另外,您可能已经注意到这一点,但是您显示的模型视图矩阵是病态的,因为您的向上向量指向视图方向(从眼睛到中心)。这就解释了为什么它有两行完整的零。

【讨论】:

    【解决方案2】:

    “我对如何在这段代码中使用前向、向上和侧向向量执行旋转感到非常困惑……” 我想你应该对“UVN相机”有所了解。有一些关于坐标在两个坐标系之间转换的理论。在上面的例子中,两个坐标是世界坐标和相机坐标。 结果是: x

    N - 从目标到相机的向量。在某些 3D 文献中也称为“查看”矢量。这个向量对应于-Z轴。

    V - 直立时,这是从您的头部到天空的矢量。如果您正在编写飞行模拟器并且飞机反转,则该矢量很可能指向地面。这个向量对应于 Y 轴。

    U - 这个向量从相机指向它的“右侧”。它对应于 X 轴。

    【讨论】:

    • 该图对于这个问题是完全错误的。那是行优先的表示,OpenGL 是列优先的。它在数学上有效,但规范 UVN 应该被转置或 (x_world,y_world,z_world) 应该在另一边。
    【解决方案3】:

    @Andon M. Coleman - 上面的图表行专业怎么样? 具有行或列主矩阵是关于 2D 结构在 1D 内存中的内存表示,与上面的 4x4 变换矩阵图无关。

    如果向量 U、V、N 像您建议的那样写成列,那么您将拥有相机空间到世界空间的转换。

    但是,矩阵的输入是世界空间位置,输出是相机空间位置,因此矩阵是世界空间到相机空间的转换。

    转置 U,V,N 的原因是因为这是您建议的矩阵的逆矩阵,并且通过使用正交矩阵的属性,它们的逆矩阵也是它的转置矩阵。也就是说,我们将 U,V,N 向量写入行以获得世界空间到相机空间的转换,将 U,V,N 写入列以获得相机空间到世界空间的转换。

    此外,选择与右侧的世界位置相乘是因为该图使用了列向量。如果我们使用行向量,我们会留下乘法。它与我们如何将矩阵存储在内存中无关,而是与我们如何将两个矩阵相乘有关,也就是说,在将向量与 4x4 矩阵相乘之前,我们是否将其转换为 1X4 或 4X1 矩阵。

    总之,上图没问题,只是从一个空间到另一个空间的转换,请不要将这件事与讨论内存布局混为一谈,这是一个编程细节。

    【讨论】:

      猜你喜欢
      • 2013-07-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多