为了简化问题,我要做的第一件事是转换坐标空间,使相机位于 (0, 0, 0) 并直接指向其中一个轴(所以方向是 (0, 0 , 1))。翻译使相机位于 (0, 0, 0) 非常简单,所以我不会深入讨论。旋转使相机方向为 (0, 0, 1) 有点棘手...
一种方法是构建相机的完整正交基,然后将其粘贴到旋转矩阵中并应用它。相机的“标准正交基”是指从相机指向前方、上方和右侧的三个向量的一种奇特方式。它们都应该彼此成 90 度(这是正交位的含义),并且它们的长度都应该是 1(这是正常位的含义)。
您可以通过一些叉积技巧获得这些向量:两个向量的叉积与两者垂直(成 90 度)。
要获得向右的向量,我们可以将相机方向向量与 (0, 1, 0) (一个指向正上方的向量)进行叉积。您需要对从叉积中得到的向量进行归一化。
要获得相机的向上矢量,我们可以将相机方向矢量与我们刚刚计算的向右矢量进行交叉乘积。假设两个输入向量都已归一化,则不需要进行归一化。
我们现在有了相机的正交基。如果我们将这些向量粘贴到 3x3 矩阵的行中,我们会得到一个旋转矩阵,它将转换我们的坐标空间,因此相机直接指向其中一个轴(哪个轴取决于您粘贴向量的顺序)。
现在计算对象的方位角和仰角相当容易。
要获得方位角,只需在对象的 x/z 坐标上执行 atan2。
要获得高程,请将对象坐标投影到 x/z 平面上(只需将 y 坐标设置为 0),然后执行:
acos(dot(normalise(object coordinates), normalise(projected coordinates)))
这将始终给出一个正角度——如果对象的 y 坐标小于 0,您可能想要否定它。
所有这些的代码如下所示:
fwd = vec3(camDirectionX, camDirectionY, camDirectionZ)
cam = vec3(camX, camY, camZ)
obj = vec3(objectX, objectY, objectZ)
# if fwd is already normalised you can skip this
fwd = normalise(fwd)
# translate so the camera is at (0, 0, 0)
obj -= cam
# calculate the orthonormal basis of the camera
right = normalise(cross(fwd, (0, 1, 0)))
up = cross(right, fwd)
# rotate so the camera is pointing straight down the z axis
# (this is essentially a matrix multiplication)
obj = vec3(dot(obj, right), dot(obj, up), dot(obj, fwd))
azimuth = atan2(obj.x, obj.z)
proj = vec3(obj.x, 0, obj.z)
elevation = acos(dot(normalise(obj), normalise(proj)))
if obj.y < 0:
elevation = -elevation
需要注意的一点是,当您的相机正面朝上或朝下时,原始相机向量与 (0, 1, 0) 的叉积将返回零长度向量。为了完全定义相机的方向,我假设它始终是“笔直的”,但这并不意味着当它正面朝上或朝下时——你需要另一个规则。