首先,如果您想要解释GLM lookAt算法,请看这个问题的答案:https://stackoverflow.com/a/19740748/1525061。
mat4x4 lookAt(vec3 const & eye, vec3 const & center, vec3 const & up)
{
vec3 f = normalize(center - eye);
vec3 u = normalize(up);
vec3 s = normalize(cross(f, u));
u = cross(s, f);
mat4x4 Result(1);
Result[0][0] = s.x;
Result[1][0] = s.y;
Result[2][0] = s.z;
Result[0][1] = u.x;
Result[1][1] = u.y;
Result[2][1] = u.z;
Result[0][2] =-f.x;
Result[1][2] =-f.y;
Result[2][2] =-f.z;
Result[3][0] =-dot(s, eye);
Result[3][1] =-dot(u, eye);
Result[3][2] = dot(f, eye);
return Result;
}
现在我要告诉你们为什么我似乎对这个算法有一个概念上的问题。该视图矩阵分为平移和旋转两部分。翻译进行正确的逆变换,将相机位置转换为原点,而不是原点位置到摄像机。类似地,您也期望相机定义的旋转在放入此视图矩阵之前被反转。我看不出这里发生了什么,这是我的问题。
考虑前向矢量,这是你的相机看的地方。因此,这个正向向量需要映射到-Z轴,这是openGL使用的正向方向。这个视图矩阵的工作方式是在视图矩阵的列中创建一个正交基,所以当你在这个矩阵的右边乘一个顶点时,你实际上只是把它的坐标转换成不同的轴。
当我在脑海中进行旋转时,我看到的不是相机的反向旋转,而是应该发生的旋转,而是非逆的旋转。也就是说,我发现-Z轴不是前向映射到-Z轴,而是向前映射到摄像机轴。
如果你不明白我的意思,请考虑一个2D例子,这个例子就是发生在这里的同一类型的事情。假设前向矢量是(sqr(2)/2,sqr(2)/2),或者sin/cos是45度,我们也可以说,这个2D相机的侧矢量是sin/cos = -45度。我们要把这个正向量映射到(0,1),正Y轴。正Y轴可以看作是与-Z轴在openGL空间中的类比。让我们考虑一个与前向向量相同方向的顶点,即(1,1)。通过使用GLM.lookAt的逻辑,我们应该能够使用一个2x2矩阵将(1,1)映射到Y轴,该矩阵由第一列中的前向向量和第二列中的侧向量组成。这是计算+1的等效计算。
注意,你没有得到你的(1,1)顶点映射成你想要的正Y轴,而是把它映射到正X轴。如果应用此转换,还可以考虑位于正Y轴上的顶点发生了什么。果然,它被转换成正向向量。
因此,GLM算法似乎有些可疑之处。然而,我怀疑这个算法是不正确的,因为它是如此流行。我遗漏了什么?
发布于 2014-01-17 14:20:35
查看Mesa:http://cgit.freedesktop.org/mesa/glu/tree/src/libutil/project.c中的GLU源代码
首先,在gluPerspective的实现中,注意-1
使用的是索引[2][3]
,-2 * zNear * zFar / (zFar - zNear)
使用的是[3][2]
。这意味着索引是[column][row]
。
现在,在gluLookAt
的实现中,第一行设置为side
,下一行设置为up
,最后一行设置为-forward
。这给了你旋转矩阵,它是后乘的平移,把眼睛带到原点。
GLM似乎使用相同的[column][row]
索引(从代码)。您刚刚为lookAt
发布的文章与更标准的gluLookAt
(包括平移部分)是一致的。所以至少GLM和GLU都同意。
然后,我们逐步推导出完整的构造。注意C
的中心位置和E
的眼睛位置。
-E
的翻译。(x, y, z)
轴对齐。
2.1计算相机的正正交基础:
F=正规化(C- E) (指向中心)s=正规化(F X u) (指向右眼)u=s x f(指向上方)
有了这一点,(s, u, -f)
是相机的正正交基础。
2.2找到旋转矩阵R
,它将(s, u, -f)
轴映射到标准轴(x, y, z)
。逆旋转矩阵R^-1
做相反的工作,并将标准轴对齐到摄像机轴,根据定义这意味着:
(sx ux -fx) R^-1 = (sy uy -fy) (sz uz -fz)
自R^-1 = R^T
以来,我们有:
( sx sy )R=( ux uy uz) (-fx -fy -fz)M
被“查看”转换到R (M - E) = R M - R E = R M + t
映射。因此,用于“查看”的最后4x4转换矩阵确实是:
( sx sz tx )( sy sz -s.E )L=( ux uy uz ty )=( ux uz -u.E ) (-fx -fy -fz tz ) (-fx -fy -fz f.E )(0 0 0 1)(0 0 0 1)所以当你写:
也就是说,我发现-Z轴不是前向映射到-Z轴,而是向前映射到摄像机轴。
这是非常令人惊讶的,因为通过构造,“查看”转换将相机的前向轴映射到-z轴。这种“看”转换应该被认为是移动整个场景,使相机与标准的原点/轴对齐,这才是它真正要做的。
使用您的2D示例:
通过使用GLM.lookAt的逻辑,我们应该能够使用一个2x2矩阵将(1,1)映射到Y轴,该矩阵由第一列中的前向向量和第二列中的侧向量组成。
相反,按照我描述的构造,您需要一个2x2矩阵,将前向和行向量映射为行,而不是列来映射(1,1),并将另一个向量映射到y和x轴。要使用矩阵系数的定义,需要通过变换得到标准基向量的图像。这直接给出矩阵的列。但是因为你要寻找的是相反的(将你的向量映射到标准的基向量),你必须将转换(转置,因为它是一个旋转)。然后你的参考向量变成行而不是列。
发布于 2014-01-16 00:26:48
这些人可能会对你的可疑问题有更深入的了解:glm::lookAt vertical camera flips when z <= 0
你可能对答案感兴趣吗?
https://stackoverflow.com/questions/21152556
复制