在Unity3D中计算两个向量之间的实际角度

11

在Unity中有没有一种方法可以计算两个3D向量之间的实际角度?Vector3.Angle提供两个向量之间的最短角度。我想知道按顺时针方向计算得出的实际角度。


最短角度是什么意思?两个向量之间只有一个角度。通常通过(概念上)从第一个向量沿弧线移动到第二个向量来计算角度。 - snibbets
我不希望通过将第一个向量顺时针或逆时针移动到另一个向量来计算角度。在Vector3.Angle的实现中,如果Vector 2从Vector 1开始顺时针旋转90度,甚至是270度,那么得到的结果都是90度。我希望它返回270度。 - shaveenk
我刚才发布并删除的答案显然是错误的,但我认为你最终一定会使用这两个向量的点积。 - Max Yankov
顺便问一下,“顺时针”具体是什么意思?你想从哪个点开始观察这些向量,并确定它们是顺时针还是逆时针? - Max Yankov
如果从空间中所述点的角度来看,这些向量恰好投影到一条直线上怎么办?例如,如果您想通过从(0,+9001,0)点观察来确定向量的“顺时针方向”,那么在X-Y平面上的向量呢? - Max Yankov
是的,我明白3D向量可能会出现这种情况。我使用它是为了简单理解,但我想它被错误地解释了。考虑将向量放在XY平面上,然后Z = 0。如果Vector1是(0,1,0),而Vector2是(-1,0,0),我希望结果是270度而不是90度。Vector3.Angle的当前实现不会给您大于180度的角度,因为如果角度大于180度,则会执行360 - result。我想知道是否有一种方法可以获得额外的信息,如果角度实际上是270度。希望问题现在清楚了。 - shaveenk
3个回答

21

这应该是你需要的内容。 ab是您想计算角度的向量,n将是您所谓的“顺时针/逆时针”的平面法线。

float SignedAngleBetween(Vector3 a, Vector3 b, Vector3 n){
    // angle in [0,180]
    float angle = Vector3.Angle(a,b);
    float sign = Mathf.Sign(Vector3.Dot(n,Vector3.Cross(a,b)));

    // angle in [-179,180]
    float signed_angle = angle * sign;

    // angle in [0,360] (not used but included here for completeness)
    //float angle360 =  (signed_angle + 180) % 360;

    return signed_angle;
}

为简单起见,我重复使用 Vector3.Angle,然后从平面法线nab的叉积(垂直向量)之间的角度大小计算符号。


1
请问您能否提供该方法的使用示例? - Ash Blue
4
Jedrak的回答很好,但如果你想获得在[0, 360)范围内的角度,你必须修改angle360公式(将180改为360):float angle360 = (signed_angle + 360) % 360; - Dominik Lang
你能解释一下这个背后的数学原理吗?特别是 float sign = Mathf.Sign(Vector3.Dot(n,Vector3.Cross(a,b))); - Ugo Hed
1
@UgoHed 2个向量ab定义了一个平面,但是有一个隐含的第三个向量,即前两个向量的叉积,它定义了平面的法线。任何ab之间的角度都会围绕着第三个轴旋转。所以问题是我们应该如何旋转?两个向量之间的角度始终是正角度。Vector3.Angle(a,b) == Vector3.Angle(b,a)。为了找到旋转方向,我们使用您确定的线路,它基本上只是将用户定义的旋转轴n与隐式轴进行比较。如果匹配,则符号为正,否则符号为负。 - Jerdak

0

如果你只使用加法和减法,这很容易。看这个例子:

/Degrees
  float signedAngleBetween (Vector3 a, Vector3 b, bool clockwise) {
  float angle = Vector3.angle(a, b);

  //clockwise
  if( Mathf.Sign(angle) == -1 && clockwise )
    angle = 360 + angle;

  //counter clockwise
  else if( Mathf.Sign(angle) == 1 && !clockwise)
    angle = - angle;
  return angle;
}

这是我的意思: 如果我们是顺时针方向,角度为负数,例如-170, 要使它变成180度,可以使用这个公式:“180-|angle|+180”。 你已经知道角度是负数,所以使用“180-(-angle)+180”,再加上180度的部分“360 + angle”。 然后,如果是顺时针方向,继续,但如果是逆时针方向,则将角度变为负数,因为360度角的另一部分(即360 + angle的补角)是“360 -(360 + angle)”或“360 - 360 - angle”或“(360 - 360)- angle”,再次使用“- angle”。这样就得到了最终的角度。

-8

如上面的评论所提到的,我不是在寻找最短的角度,而是考虑向量顺序的角度。 - shaveenk
好的,这里有一个想法:检查向量位于哪个象限。例如,如果x分量为正,y分量为负,则在第4象限中。使用您的2个向量进行计算,您将了解它们相对于彼此的方向。现在,如果两个向量恰好在同一个象限内,只需计算每个向量与另一个向量之间的角度,比如位于第1和第4象限之间的向量。从这些角度中,您应该能够确定它们的相对方向。 - aaa
我尝试了相同的方法。这部分有效,但是如果我尝试比较向量之间的角度,则在象限内会出现相同的问题。然而,对最后一步进行轻微更改可以给我们一个解决方案,但仍不太方便。与其检查向量与该象限中任意向量之间的角度,不如在两个象限内比较两个向量的x分量。您仍然需要确保两个向量位于相同的象限半部分,否则它将无法正确工作。 - shaveenk
2
如果您查看文档,Vector3.Angle指出:“返回的角度始终是锐角...永远不会大于180度”。因此,这个答案不仅回答了问题的问题,而且还包含误导性或错误的信息。 - House

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接