协助翻译旋转的相机
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
此方法适用于您可以用矩阵形式表示的任何相机模型。
我已经实现了围绕中心实体的相机旋转,现在想添加相机平移。我不能只做 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
此方法适用于您可以用矩阵形式表示的任何相机模型。