Mathf.Atan2返回错误的结果

时间:2015-05-19 11:12:25

标签: c# unity3d trigonometry

有时当我移动鼠标(围绕角色旋转相机)时,我的角色会旋转。 但我没有鼠标任何字符旋转。 这是我的旋转代码,它仅依赖于键盘输入(我从标准统一样本中获取此代码):

private void ConvertMoveInput()
{
    Vector3 localMove = transform.InverseTransformDirection(_moveInput);
    _turnAmount = Mathf.Atan2(localMove.x, localMove.z);
    _forwardAmount = localMove.z;
}

我发现有时当我移动鼠标Mathf.Atan2时返回数字PI,即使两个参数仍然等于零。这是怎么发生的?

Breakpoint

我的演示项目here

2 个答案:

答案 0 :(得分:5)

请记住,atan2(x, z)返回z轴与矢量之间的角度(x,z)

Graph showing the vector (x, z), atan2(x, z), and atan2(z, x)

但是对于atan2(0, 0),你试图找到一个点与z轴或x轴之间的角度,这是没有意义的:

enter image description here

即使atan2(0, 0)毫无意义,如果atan2(x, y)x是有效数字,大多数编程语言数学库都会y返回值而不是错误代码,并且在atan2(0, 0)的特殊情况下,返回值为pi。 The implementation of atan2() in the C++ standard library does this,我认为很多语言,包括Unity的C#实现,都是如此。

这意味着您需要检查xz都是0的特殊情况。例如:

if ((localMove.x != 0) && (localMove.z != 0)) {
  _turnAmount = Mathf.Atan2(localMove.x, localMove.z);
}
else {
  _turnAmount = 0;
}

答案 1 :(得分:2)

tan函数是周期性的,周期为π。因此,在tan0上调用π会产生相同的值(即零)。

这是你不能简单地使用atan来恢复原始角度的原因之一 - 你丢失了很多原始信息,而你所获得的角度只会介于{ {1}}和-π/2

Unity中的

+π/2旨在解决此问题 - 它需要Atan2x坐标,而不是它们的划分(这就是你使用y的方式)。然后它可以找出角度的正确象限 - 适当地偏移它。同样重要的是,它处理atan坐标为零时的情况 - 这通常会导致除零错误。例如,y可能会返回0°,[1; 0] 270°(注意 - 我不确定确切的数字;这取决于“参考”的位置,我没有使用过此在Unity3D中。关键是原则,而不是确切的值。)

然而,这只有在至少有一个坐标为零时才有效 - 坐标[0; 1] [0; 0]有任何有意义的角度。所有角度都同样有效(或两者都不同,具体取决于您的观点)。无论出于何种原因,Unity都会从所有可能的选项中选择[0; 0]。它真的和其他任何东西一样好。唯一真正的替代方案是抛出一个异常并让你的游戏崩溃 - 这通常不会像这样的小故障首选:)