LookAt 矩阵在向上或向下看时扭曲
LookAt matrix distorts when looking up or down
我正在使用一个在我为 LWJGL 找到的名为 JOML 的开源数学库中计算的 lookAt 矩阵,用于我的游戏中的免费 cam。它在左右旋转时效果很好,但向上和向下看似乎会导致类似于大幅增加 FOV 的重大扭曲问题。
向前看:
但是抬头的时候:
低头时:
我没能找到有类似错误的人,也没有人使用 JOML 报告过这个问题。我不是最擅长矩阵数学的,所以我所有计算自己的 lookAt 矩阵的尝试都失败了。
如果有人可以使用 JOML 制作 lookAt 矩阵,或者说出我(最有可能)可能出现的任何一个错误,将不胜感激,谢谢。
好吧,该库提供的 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
我正在使用一个在我为 LWJGL 找到的名为 JOML 的开源数学库中计算的 lookAt 矩阵,用于我的游戏中的免费 cam。它在左右旋转时效果很好,但向上和向下看似乎会导致类似于大幅增加 FOV 的重大扭曲问题。
向前看:
但是抬头的时候:
低头时:
我没能找到有类似错误的人,也没有人使用 JOML 报告过这个问题。我不是最擅长矩阵数学的,所以我所有计算自己的 lookAt 矩阵的尝试都失败了。 如果有人可以使用 JOML 制作 lookAt 矩阵,或者说出我(最有可能)可能出现的任何一个错误,将不胜感激,谢谢。
好吧,该库提供的 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