视图矩阵:反转旋转还是不反转旋转?

时间:2019-09-15 10:05:21

标签: math opengl 3d rotation

编辑:对于我真正要问的问题,我的问题可能太复杂了,因此请跳至TLDR。如果需要的话。

我一直在编程3D图形有一段时间了,直到现在,我似乎从未遇到过这个问题,但这也许是我第一次真正了解应该(或不应该)的东西。所以这是问题...

我的3D引擎使用RH坐标系的典型OpenGL传统约定,这意味着X +正确,Y +向上,Z +朝向查看器,Z-进入屏幕。我这样做是为了可以针对OpenGL中的3D数学进行测试。

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

当我仅使用投影矩阵,恒等视图矩阵和将三角形转换为位置(0,0,-5)的模型矩阵时,我会看到它,因为Z-进入了屏幕。

在我的(6自由度太空)游戏中,我有飞船和小行星。我使用双精度坐标(因为它们很大),并且将照相机放在太空飞船中,因此坐标相对于每一帧都是相对的,因此它们的精度足以适合在GPU上渲染的单精度坐标。

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

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

现在,当我将相机放在飞船中时,这​​意味着它的鼻子指向(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)),则意味着“前进”意味着您将离这个看起来不合逻辑的三角形越来越远。

我想念什么?

编辑:由于答案隐藏在下面的许多评论中,因此我在此处进行总结:惯例!我选择使用OpenGL传统约定,但也选择使用自己的物理约定,它们会发生冲突,所以我需要对此进行补偿。

编辑:经过深思熟虑,我决定放弃OpenGL传统约定,并使用对我来说最合乎逻辑的东西,即左手系统。

1 个答案:

答案 0 :(得分:1)

我认为您困惑的根本原因可能在这里

  

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

由于我们可以假定视图矩阵仅包含旋转和平移(没有缩放/剪切或透视技巧),因此我们知道左上3x3子矩阵将仅是旋转,并且按照定义它们是正交的,因此inverse(mat3(view))将是transpose(mat3(view)),这是您的来自何处。由于在用于转换固定坐标系中对象(而不是移动参考坐标系)的标准矩阵中,矩阵的将仅显示{{ 1}},xy(以及原点z将被此矩阵映射到。通过获取行,您可以使用转置,在此特定设置中,则为倒数(当然,不考虑包含翻译的最后一列)。

(0,0,0,1)矩阵将从世界空间转换为眼睛空间。结果,view将从眼睛空间变回世界空间。

因此,inverse(view)将为您提供世界空间中相机的正确向量,inverse(view) * (1,0,0,0)为向上向量,但按照惯例,相机将在眼空间中注视inverse(view) * (0,1,0,0),因此世界范围内的前进方向将是-z,在您的设置中,该方向仅是矩阵求反了的第三行。

(相机位置当然是inverse(view) * (0,0,-1,0),但我们要做的不只是移调以使inverse(view) * (0,0,0,1)的第四列正确)。