在opengl为什么我们必须在gluLookAt之前做gluPerspective?

时间:2015-10-07 08:40:58

标签: opengl graphics 3d matrix-multiplication perspectivecamera

所以在GL_PROJECTION下我做了

    glu.gluPerspective(90,aspect,1,10);
    glu.gluLookAt(0,0,3,0,0,0,0,1,0);

这种方法很好但是当我切换顺序时,我的屏幕上没有任何物体,我旋转了相机而没有任何东西。

我知道切换两者会改变矩阵乘法的顺序,但我想知道为什么第一种情况有效,但第二种情况并非如此。感谢

2 个答案:

答案 0 :(得分:3)

要在屏幕上查看对象,您需要将其放在规范视图体积内,对于OpenGL,它在所有三个维度中都是[-1,1]。要转换对象,您大致可以

  

P'=投影×视图×模型×P

其中P'是规范视图中需要的最终点,P是模型空间中的起始点。 P由模型矩阵转换,然后是视图,然后是投影。

我遵循的顺序是基于列向量,其中每个进一步的变换是前/左乘。读取相同公式的另一种方法是从左到右读取它而不是变换点,转换坐标系,并在变换后的系统中解释P在空间上表示原始P'系统。这只是看到它的另一种方式,两者的结果是一样的;无论是在数字上还是在空间上。

  

为什么我们必须在gluLookAt之前做gluPerspective?

旧的固定功能管道 OpenGL post / right-multiplies 因此需要反转顺序以获得相同的效果。因此,当我们首先需要 LookAt 而接下来需要 Perspective 时,我们会反过来获得预期的结果。

以正确的顺序给出两个导致

  

P'=视图×投影×模型×P

因为矩阵乘法是反交换的,所以你没有得到正确的P',它属于规范视图体积,因此也是黑屏。

请参阅通用转换命令部分下的Chapter 3, Red Book,其中解释了OpenGL遵循的顺序。摘录:

  

注意:所有与OpenGL的矩阵乘法如下:假设当前矩阵为 C ,并且使用 glMultMatrix *()指定矩阵或任何转换命令 M 。乘法后,最终矩阵始终 CM 。由于矩阵乘法通常不是可交换的,因此顺序会有所不同。

  

我想知道为什么第一种情况有效但第二种情况不然。

要知道由不正确的顺序组成的矩阵究竟发生了什么,让我们在2D中做一个小的锻炼。假设规范视图 region 在X和Y中都是[-100,100];除此之外的任何东西都被删掉了。这个假想的方形屏幕的原点位于中心,X向右,Y向上。如果未应用任何变换,则调用DrawImage会在原点处绘制图像。你的图像是1×1;其模型矩阵按200缩放,使其成为200 × 200图像;一个填满整个屏幕。由于原点位于屏幕的中心,要绘制图像使其填满屏幕,我们需要一个视图矩阵,将图像平移(移动)(-100,-100)。制定这个

  

P'=查看×模型=翻译 -100,-100 ×Scale 200,200

[ 200,  0,  −100 ]
[  0,  200, −100 ]
[  0,   0,   1   ]

然而,

的结果
  

模型×视图= S 200,200 ×T -100,-100

[ 200,  0,  −20000 ]
[  0,  200, −20000 ]
[  0,   0,    1    ]

将前一个矩阵与点(0,0)和(1,1)相乘会得到(-100,-100)和(100,100)预期值。图像角落将与屏幕角落对齐。但是,将后一个矩阵与它们相乘会得到(-20000,-20000)和(-19800,-19800);远在可见区域之外。这是因为,在几何学上,后者矩阵首先平移然后缩放而不是缩放然后平移。翻译的比例导致一个完全关闭的点。

答案 1 :(得分:3)

glu.gluPerspective(90,aspect,1,10);
glu.gluLookAt(0,0,3,0,0,0,0,1,0);

情况下,第一个模型/世界坐标(在R ^ 3中)被转换为视图坐标(也是R ^ 3)。然后投影将视图坐标映射到透视空间(P ^ 4),然后通过透视分割将其减小到NDC坐标。这通常是它应该如何运作的。

现在看看:

glu.gluLookAt(0,0,3,0,0,0,0,1,0);
glu.gluPerspective(90,aspect,1,10);

这里,世界坐标直接投射在投影空间(P ^ 4)。由于lookAt矩阵是来自R ^ 3 - >的映射。 R ^ 3和我们已经在P ^ 4,这是行不通的。即使可以旋转P ^ 4,也必须调整gluLookAt的参数以适应投影空间的范围。

注意:通常,不应将gluLookAt添加到GL_PROJECTION堆栈。由于它描述了视图矩阵,因此它更适合GL_MODELVIEW堆栈。如需参考,请查看here