查看矩阵:反转还是不反转?

View matrix: to invert rotation or to not invert rotation?

编辑:我的问题对于我真正要问的问题来说可能太复杂了,所以请跳到 TLDR;如果你需要的话。

我编写 3D 图形已经有一段时间了,直到现在我似乎从来没有遇到过这个问题,但也许这是我第一次真正理解我应该(或不应该)的东西。那么问题来了...

我的 3D 引擎使用 RH 坐标系的典型 OpenGL 传统约定,这意味着 X+ 向右,Y+ 向上,Z+ 朝向观察者,Z- 进入屏幕。我这样做是为了测试我的 3D 数学与 OpenGL 中的数学。

为了配合 Blender 3D/Collada 的坐标约定,我在导入过程中将每个矩阵在 X 轴上旋转 -90 度。 (Collada没记错的话X+右,Y+前,Z+上)

当我只使用投影矩阵、单位视图矩阵和将三角形变换到 (0, 0, -5) 位置的模型矩阵时,我会看到它,因为 Z- 在屏幕中。

在我的 (6DOF space) 游戏中,我有 space 飞船和小行星。我使用双精度坐标(因为它们很大)并且通过将相机放在 space 船内,坐标是相对于每一帧的,因此它们足够精确以适合在 GPU 上渲染的单精度坐标.

所以,现在我有一艘 space 飞船,相机在里面,它的旋转四元数是身份。这给出了一个单位矩阵,如果我没记错的话,row 列 1-3 代表对象指向的 X、Y 和 Z 轴。为了移动船,我使用这个 Z 轴向前移动。使用单位矩阵,Z 轴将为 (0, 0, 1).

编辑:实际上,我没有从矩阵中提取列,而是直接从四元数中提取轴。

现在,当我将相机放在 space飞船上时,这意味着它的机头指向 (0, 0, 1) 但 OpenGL 将以 -1 进入屏幕进行渲染,因为它的约定。

我总是听说当你将相机放在场景中的物体内部时,你需要获取模型矩阵并将其反转。这是合乎逻辑的:如果飞船位于 (0, 0, 1000) 而小行星位于 (0, 0, 1100),那么您需要将相机放在 (0, 0, -1000) 以便飞船将位于 (0, 0, 0),小行星将位于 (0, 0, 100)。

所以当我这样做的时候,船头会朝向 Z- 渲染,但是现在,当我开始移动时,我的船会移动到它的旋转(仍然相同)Z 为 (0, 0, 1 ) 并且船将后退而不是前进。如果 (0, 0, 1) 朝向观众,这是有道理的...

所以现在我很困惑......我应该如何正确处理这个问题???我错误地使用了哪个约定?我忘记了哪个约定?这似乎不合逻辑,例如,在计算运动矢量时反转船的旋转...

有人可以为我澄清一下吗?这已经困扰我一个星期了,我似乎无法直截了当地怀疑我正在犯新的错误。

编辑:为视图矩阵反转模型矩阵的旋转部分是不是很奇怪?我知道平移部分应该倒转,但是视图在渲染时仍然应该与对象看相同的方向,不是吗?

TLDR; 如果您使用旧版 OpenGL,设置标准投影矩阵和恒等模型视图矩阵并在 (0, 0, -5) 处渲染三角形,您会看到它,因为 OpenGL 查看 Z-。

但是如果你从视图矩阵(第3列)中获取Z轴,即单位矩阵上的(0,0,1),这意味着走 'forward' 意味着你会离那个三角形越来越远,这看起来不合逻辑。

我错过了什么?

编辑:由于答案隐藏在下面的许多评论中,我在这里总结一下:约定!我选择使用 OpenGL 遗留约定,但我也选择使用我自己的约定物理约定和它们发生碰撞,所以我需要对此进行补偿。

编辑:经过深思熟虑,我决定放弃 OpenGL 遗留惯例,使用对我来说最合乎逻辑的任何东西,即左手系统。

我想你困惑的根本原因可能就在这里

So, now I have a spaceship, the camera is inside, and it its rotation quaternion is identity. This gives an identity matrix and if I recall correctly, row 1-3 are representing the X, Y and Z axis of where the object is pointing at. To move the ship, I use this Z axis to go forward. With the identity matrix, the Z-axis will be (0, 0, 1).

由于我们可以假设视图矩阵仅包含旋转和平移(没有 scaling/shear 或透视技巧),我们知道左上角的 3x3 子矩阵将仅是旋转,并且它们是正交的根据定义,inverse(mat3(view)) 将是 transpose(mat3(view)),这是您的 的来源。由于在用于在固定坐标系中变换对象的标准矩阵(与移动参考坐标系相反),矩阵的 将简单地显示单位向量的位置对于 xyz(以及原点 (0,0,0,1) 将被此矩阵映射到。通过获取行,您使用转置,其中,这个特定的设置是相反的(当然不考虑包含翻译的最后一列)。

view 矩阵将从 worrd space 转换为 eye space。结果,inverse(view) 将从眼睛 space 变回世界 space。

所以,inverse(view) * (1,0,0,0) 会给你相机在世界 space 中的右向量,inverse(view) * (0,1,0,0) 上向量,但按照惯例相机会注视 -z 在眼睛 space 中,因此世界中的前向 space 将是 inverse(view) * (0,0,-1,0),在您的设置中,它只是矩阵的第三行 negated.

(相机位置当然是 inverse(view) * (0,0,0,1),但我们要做的不仅仅是转置才能使 inverse(view) 的第四列正确)。