我正在使用在我为LWJGL找到的开源数学库中计算的lookAt矩阵,在我的游戏中为JOML提供免费凸轮。左右旋转时效果很好,但向上和向下看似乎会导致严重的扭曲问题,类似于大幅增加FOV。
直截了当:
但是在查找时:
俯视时:
我还没能找到有类似错误的人,没有人使用JOML报告过这个。我在矩阵数学方面不是最好的,所以我计算自己的lookAt矩阵的所有尝试都失败了。 如果有人可以使用JOML查看矩阵,或者说我的(最可能的)任何一个可能的错误,那将非常感谢,谢谢。
答案 0 :(得分:3)
那么,该库提供的lookAt代码就是这样(我将实际的源代码保留下来,只保留注释,因为它们很好地解释了已完成的步骤):
public final static void lookAt(Vector3f position, Vector3f centre, Vector3f up, Matrix4f dest) {
// Compute direction from position to lookAt
// Normalize direction
// Normalize up
// right = direction x up
// up = right x direction
// Set matrix elements
}
此代码只是错误。有趣的是,我之前见过这个错误。它实际上是"official" gluLookAt()
manpage仍然包含的错误(实际的glu实现没有错误,只是文档错误)。
此代码的作用是构建标准正交基础。问题是,在计算right
的叉积之前,向上矢量被规范化。假设似乎是在构建两个单位长度向量的叉积时,结果也将是单位长度向量。但这是一种常见的误解。真正实现的是:
length( cross( a, b) ) == lenght(a) * length(b) * sin(alpha)
其中alpha是a
和b
之间的角度。因此,如果向量已经是正交,则单位长度假设仅保持。由于矢量在交叉乘积之后从未重新归一化,因此得到的基础不是正交的,而是会引入一些非均匀缩放。 lookAt
假设反转可以通过转置矩阵计算,在这种情况下完全失败。
当观察方向与向上矢量之间的角度偏离90度时,您看到的失真会变得更加严重。
处理这个问题的正确方法就是在不同的点进行规范化。不要在交叉乘积之前对向上矢量进行标准化,而是将其结果标准化。然后,您有两个相互正交的单位长度矢量,第二个交叉乘积也将按预期工作。所以实际的lookAt函数应该是:
// Compute direction from position to lookAt
// Normalize direction
// right = direction x up
// Normalize right
// up = right x direction
// Set matrix elements