Unity计算二维向量夹角余弦值和正弦值的优化方法参考

        如果不考虑优化问题,计算两个向量的余弦值或者正弦值可以直接使用类似的方法:

[SerializeField]
Vector2 v1, v2;

void Start()
{
    float valCos = Mathf.Acos(Vector2.SignedAngle(v1, v2));
    float valSin = Mathf.Asin(Vector2.SignedAngle(v1, v2));
}

        但是上面的Vector2.SignedAngle方法实际上是先计算出余弦值再根据余弦值计算角度,然后我们再根据角度计算出余弦值,这个太绕了,属于脱那什么放那什么的做法。

        从数学原理上来说,计算夹角余弦的思路如下:

将公式代入得到:

但是这里面出现了两次开方运算,可以变换成如下形式:

这样就只需要一次开方运算,对应代码参考如下:

	bool TryVectorAcos(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, out float acos)
	{
		acos = 0;
		if (Mathf.Approximately((p2 - p1).sqrMagnitude, 0) || Mathf.Approximately((p4 - p3).sqrMagnitude, 0)) return false;

		float ax = p2.x - p1.x;
		float ay = p2.y - p1.y;
		float bx = p4.x - p3.x;
		float by = p4.y - p3.y;

		acos = (ax * bx + ay * by) / (Mathf.Sqrt((ax * ax + ay * ay) * (bx * bx + by * by)));

		return true;
	}

带入上面的余弦值公式可得到:

但这个公式也出现了两次开方运算,可以将该公式变换成如下形式:

这样也是只需要一次开方运算就好,对应代码参考如下:

	bool TryVectorAsin(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, out float asin)
	{
		asin = 0;
		if (Mathf.Approximately((p2 - p1).sqrMagnitude, 0) || Mathf.Approximately((p4 - p3).sqrMagnitude, 0)) return false;

		float ax = p2.x - p1.x;
		float ay = p2.y - p1.y;
		float bx = p4.x - p3.x;
		float by = p4.y - p3.y;

		asin = (ax * by - ay * bx) / Mathf.Sqrt((ax * ax + ay * ay) * (bx * bx + by * by));

		return true;
	}

        如果要同时获得正弦值和余弦值,以避免重复计算两个矢量模的积,代码参考如下:

	bool TryVectorAcosAndAsin(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, out float acos, out float asin)
	{
		acos = 0;
		asin = 0;
		if (Mathf.Approximately((p2 - p1).sqrMagnitude, 0) || Mathf.Approximately((p4 - p3).sqrMagnitude, 0)) return false;

		float ax = p2.x - p1.x;
		float ay = p2.y - p1.y;
		float bx = p4.x - p3.x;
		float by = p4.y - p3.y;

		float denominator = Mathf.Sqrt((ax * ax + ay * ay) * (bx * bx + by * by));
		acos = (ax * bx + ay * by) / denominator;
		asin = (ax * by - ay * bx) / denominator;

		return true;
	}

猜你喜欢

转载自blog.csdn.net/ttod/article/details/143361272