用于Debug.Log
检查Mathf.Sin()/Cos()
实际返回的值。用于的默认精度Vector3.ToString()
是点后 5 位,iirc。要在调试日志中获得更高的精度,请使用
Vector3 v = new Vector3(1.1234567891011, 0.00000001, 2.2222222222);
Debug.Log(v.ToString("F10"));
这应该在点之后打印 10 位数字的向量值。
那么,究竟发生了什么?
我们以 90 度角为例。结果Mathf.Cos()
将是:
tmp1 = 90f * Mathf.Deg2Rad; // 1.570769
tmp2 = Mathf.Cos(tmp1); // -4.371139E-08
因此,Mathf.Cos()
返回-4.37139E-08
而不是0
. 原因是浮点精度限制。它破坏了计算机科学中的很多东西。
从 0、90、120 等角度得到的结果Mathf.Sin()/Cos()
不会给你 0 和 1,而是会给你像 4.371139E-08 这样的数字。这个值非常非常接近于零,但它不是零。因此,当您将这些结果与new Vector
代码中的 1、0 和 0 进行比较时,等式会失败。
虽然,Vector3 == Vector3
Unity 中的操作已经应用了一些舍入,因此彼此非常接近的值将被视为相等。而不是进行Vector3.Euals()
精确比较。
以下是Vector3 == Vector3
来自 Unity 源代码仓库的操作源代码:https://github.com/Unity-Technologies/UnityCsReference/blob/master/Runtime/Export/Math/Vector3.cs
// Returns true if the vectors are equal.
public static bool operator==(Vector3 lhs, Vector3 rhs)
{
// Returns false in the presence of NaN values.
float diff_x = lhs.x - rhs.x;
float diff_y = lhs.y - rhs.y;
float diff_z = lhs.z - rhs.z;
float sqrmag = diff_x * diff_x + diff_y * diff_y + diff_z * diff_z;
return sqrmag < kEpsilon * kEpsilon;
}
如您所见,它检查向量值之间的平方差是否小于kEpsilon * kEpsilon
( kEpsilon = 0.00001
,因此平方值为0.000000001
)。
这里棘手的是Mathf.Cos()
90 度可能会返回0.00001
,并且==
运算会比较0.00001 * 0.00001 < kEpsilon * kEpsilon
它会返回 false,因为这些值实际上是相同的,所以运算的结果
Vector3 v1 = new Vector3(1, 0, 0); // your "checkout" vector
Vector3 v2 = new Vector3(1.00001, 0, 0); // the result of Mathf.Cos()/Sin() in your code
// in the Vector3 == Vector3 operation Unity does:
float sqrmag = 0.00001 * 0.00001 + 0 * 0 + 0 * 0;
return sqrmag < kEpsilon * kEpsilon;
0.000001 * 0.000001
不小于kEpsilon * kEpsilon
所以你得到向量不相同的结果。
因此,您需要以其他方式比较向量。作为一种选择,您可以尝试Mathf.Approximately(float a, float b)
(https://docs.unity3d.com/ScriptReference/Mathf.Approximately.html)分别比较向量的每个x, y, z
值,而不是使用Vector3 == Vector3
.