协助翻译旋转的相机

Assistance translating a rotated camera

我已经实现了围绕中心实体的相机旋转,现在想添加相机平移。我不能只做 centre.xy += mouse.delta.xy 就好像相机面向 z 轴旋转并且我向右拖动,这显然会将相机移向我(因为 x 轴正在递增)。在这种情况下,需要增加 centre.z 属性。我想我需要将相机的俯仰、偏航和滚动属性纳入此计算中,但不确定如何去做……任何 suggestions/links?

我也尝试过使用光线投射(我已经实现)来代替鼠标增量,但无济于事。

编辑 - 简单方法:

val right = Vector3f(viewMatrix.m00(), viewMatrix.m01(), viewMatrix.m02()).mul(lmb.delta.x)
val up = Vector3f(viewMatrix.m10(), viewMatrix.m11(), viewMatrix.m12()).mul(lmb.delta.y)
val delta = right.add(up)
center.add(delta)

你没有写太多关于你如何代表你的相机,但我假设如下:

相机由一个焦点 centre 和描述围绕该焦点的旋转的三个欧拉角表示。大概也离对焦点有一段距离。

我将解释两种方法 - 一种相当简单,一种更复杂。

简单的方法

让我们回顾一下您尝试做的事情:

centre.xy += mouse.delta.xy

当相机未与坐标系对齐时失败。这种方法的更一般的表述是:

centre += mouse.delta.x * right + mouse.delta.y * up

这里,right 是指向屏幕右侧的世界-space 向量,up 是指向屏幕右侧的世界-space 向量。根据您的鼠标增量,您可能需要一个 down 向量。

那么,我们从哪里得到这些向量?简单。视图矩阵拥有我们所需要的一切。第一行(该行的前三个条目)是 right 向量。第二行是 up 向量。因此,只需获取视图矩阵、读取这些向量并更新焦点中心即可。您可能还想添加一些比例。

更复杂

在许多应用程序中,平移功能的设计方式使得鼠标下方的某个 3D 点在平移过程中保持在鼠标下方。这可以通过以下方式实现:

首先,我们需要要保留在鼠标下方的 3D 点的深度。两个常见的选项是焦点的深度或鼠标下 3D 场景的实际深度(从深度图中获得)。我会解释前者。

我们首先需要标准化设备坐标中的这个深度。为此,我们首先计算视图投影矩阵:

VP = ProjectionMatrix * ViewMatrix

然后,我们将焦点转换成剪辑space:

focusClip = VP * (focus, 1)

(focus, 1) 是一个 4D 向量,最后一个元素是 1。最后,我们得出 NDC 深度为

focusDepthNDC = focusClip.z / focusClip.w

好的,现在我们有了深度。所以我们可以计算出我们想要保留在鼠标下方的 3D 点。首先,让我们反转视图投影矩阵,因为这允许我们从剪辑 space 到世界 space:

VPInv = inverse(VP)

那么鼠标下的那个点就是(我就叫它x):

x = VPInv * (mouseStartNDC.x, mouseStartNDC.y, focusDepthNDC, 1)

mouseStartNDC是鼠标移动前的位置。请记住,这需要在标准化的设备坐标中。如果你只有屏幕 space 坐标,那么:

ndcX = 2 * screenX / windowWidth - 1
ndcY = -2 * screenY / windowHeight + 1

x 又是一个 4D 向量。做透视划分:

x *= 1.0 / x.w

现在我们有了 3D 点。我们只需要在shift之后的鼠标位置找到一个保持鼠标下方这个位置的camera的shift即可:

newX = VPInv * (mouseEndNDC.x, mouseEndNDC.y, focusDepthNDC, 1)

再做透视分割:

newX *= 1.0 / newX.w

最后更新你的相机中心:

centre += (x - newX).xyz

此方法适用于您可以用矩阵形式表示的任何相机模型。