从四元数中获得类似指南针的行为

时间:2017-07-25 00:50:40

标签: unity3d quaternions

假设您有一个摄像机投影矩阵,即摄像机平移矢量+旋转四元数,就像每个典型的摄像机一样,它可以向任何方向移动和旋转。并且无论它向前,向上还是向下,我都需要显示一个类似指南针的指示器,指向相机所针对的位置。

问题在于,当摄像机指向下方时,摄像机围绕其旋转的光学中心定义了罗盘的值,但是当摄像机指向前方时,摄像机围绕它旋转的中心不再影响罗盘的价值,在这种情况下,摄像机的方向定义罗盘的值。

当相机向下倾斜45度时,它会变得更加难看,在这种情况下,相机中心周围的旋转是否会影响罗盘的旋转,这一点甚至不清楚。

那么有一种优雅的方法可以根据任意相机投影矩阵/四元数得到罗盘值吗?

提前谢谢!

2 个答案:

答案 0 :(得分:2)

如果你只想指向目标的箭头:

Transform camera = Camera.main.transform;
Transform target = Target.transform;
Vector3 relativePosition = target.position - camera.position;

Vector3 targetRelative = Vector3.ProjectOnPlane(relativePosition, camera.forward);

float angle = Angle360(camera.up, targetRelative, camera.forward);  

Compass.transform.rotation = Quaternion.Euler(0, 0, angle);

角度函数是:

float Angle360(Vector3 from, Vector3 to, Vector3 normal)
{
    float dot = Vector3.Dot(from, to);
    float det = Vector3.Dot(normal, Vector3.Cross(from, to));
    return Mathf.Atan2(det, dot)*Mathf.Rad2Deg;
}

以下是如何在世界空间中获取指南针的方向:

在XZ平面上投影摄像机方向和目标位置

Transform camera = Camera.main.transform;
Transform target = Target.transform;

Vector3 cameraWorldDirXZ = Vector3.ProjectOnPlane(camera.forward, Vector3.up).normalized;
Vector3 targetWorldDirXZ = Vector3.ProjectOnPlane(target.position, Vector3.up).normalized; 

cameraWorldDirXZtargetWorldDirXZ之间的角度是指南针的角度。

但我不认为这会像你认为的那样。这为您提供了围绕camera.forward轴旋转y向量以面向目标所需的角度。如果围绕camera.forward进行旋转,则不要更改camera.forward向量或y轴,以免指南针发生变化。

您可能想在本地空间尝试指南针。为此你投影到相机XZ平面:

Vector3 cameraLocalDirXZ = camera.forward;
Vector3 targetLocalDirXZ = Vector3.ProjectOnPlane(target.position, camera.up).normalized; 

cameraLocalDirXZtargetLocalDirXZ之间的角度再次是罗盘针的角度。这为您提供了在camera.forward周围camera.up旋转以面向目标所需的角度。请注意,当您围绕camera.forward进行旋转时,它会更改camera.up,因此它会更改指南针方向。

答案 1 :(得分:1)

如果有人偶然发现这个问题,解决方法(感谢@Pluto)非常简单,将相机四元数乘以三个轴向量(0,0,1),(0,1,0),(1,0) ,0),你将得到三个矢量来定义你的相机的坐标系,将这三个矢量投影到你的平面上,找到你的三个投影点的质心,并且你有罗盘方向。

以下是这段代码:

def f(row):
    phone_numbers_59 = phone_data['Number'].tolist()
    callid = phone_data['CALL ID'].tolist()

    get_callid = []
    for i in range(0, len(phone_numbers_59)):
        if any([x in phone_numbers_59[i] for x in row['Numbers']]):
            get_callid.append(callid[i])

    if len(get_callid) > 0:
        return get_callid
    else:
        return "NA"

s = data.apply(f, axis=1)