所以在GL_PROJECTION下我做了
glu.gluPerspective(90,aspect,1,10);
glu.gluLookAt(0,0,3,0,0,0,0,1,0);
这种方法很好但是当我切换顺序时,我的屏幕上没有任何物体,我旋转了相机而没有任何东西。
我知道切换两者会改变矩阵乘法的顺序,但我想知道为什么第一种情况有效,但第二种情况并非如此。感谢
答案 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。