如何使用点积获得两个向量之间的夹角?


16

我正在学习在游戏中使用归一化向量。

我了解到,为了知道两个向量之间的角度,我可以使用点积。这给我一个介于-1和1之间的值,其中

  • 1表示矢量平行并且面向相同方向(角度为180度)。
  • -1表示它们平行且面对相反的方向(仍为180度)。
  • 0 表示它们之间的角度为90度。

我想知道如何将两个向量的点积转换为以度为单位的实际角度。例如,如果两个向量的点积为0.28,则0和360度之间的对应角度是多少?


1
请注意,仅当初始向量是单位向量时,点积的预期用途才有效。
sam hocevar

@SamHocevar是的,这就是我的意思。
user3150201 2014年


1
@ user3150201 Alex的答案是正确的,但您还应该考虑是否需要获得以度为单位的实际角度。我唯一可以想到的地方是在UI上以度为单位显示某些内容。否则,可能只有很少的应用程序无法直接处理正弦和余弦。
TravisG 2014年

Answers:


22

dot(A,B) = |A| * |B| * cos(angle)
可以重新排列为
angle = arccos(dot(A,B) / (|A|* |B|))

使用此公式,您可以找到两个向量之间的最小角度,该角度介于0和180度之间。如果您需要在0到360度之间的温度范围,此问题可能会对您有所帮助。


顺便说一句,指向同一方向的两个平行向量之间的角度应为0度,而不是180度。


+1表示“顺便说一句,指向同一方向的两个平行矢量之间的角度应为0度,而不是180度。”
塔拉

8

我将利用您的问题带有“ 2D”标签的事实来扩展TravisG的评论并给出另一个答案。

您可以使用点积获得两个向量之间的角度,但是无法使用点积获得两个向量之间的正负角度。换句话说,如果您想随着时间将角色转向某个点,则点积将为您提供转向的角度,而不是转向的方向。但是,还有另一个简单的公式,与点积结合使用时非常有用。你不仅有

dot(A,B) = |A| * |B| * cos(angle)

您还可以使用另一个公式(我为政治上的正确性起了名字):

pseudoCross(A,B) = |A| * |B| * sin(angle)

其中如果A =(a,b),B =(x,y),则将伪交叉(A,B)定义为叉积(a,b,0)x(x,y,0 )。换一种说法:

a*x+b*y = |A| * |B| * cos(angle)

-b*x+a*y = |A| * |B| * sin(angle)

这样就形成了全angle=atanfull(-b*x+a*y,a*x+b*y)正负号(如果您传递非标准化值,则atanfull或atan2函数会原谅您)。如果将A和B进行归一化,也就是说,如果|A|=|B|=1它们是简单的:

a*x+b*y = cos(angle)

-b*x+a*y = sin(angle)


要进行更深入的说明,请注意,上述方程可以由矩阵方程表示:

[ a,b]   [x]   [cos(angle)]
[-b,a] * [y] = [sin(angle)]

但是,对于某个值a=cos(ang1),a和b可以表示为,(不是)。因此,左侧的矩阵是将向量(x,y)旋转-ang1的旋转矩阵。这等效于切换到参考系,其中将单位矢量“ A”视为矢量/轴(1,0)!因此,仅通过在此帧中绘制单位圆/直角三角形,您就可以知道为什么该乘积的最终矢量为(cos(angle),sin(angle))。b=sin(ang1)ang1angle

如果以极坐标形式写(a,b)和(x,y),并应用角度差公式cos(l)*cos(m)+sin(l)*sin(m)=cos(l-m)sin(l)*cos(m)-cos(l)*sin(m)=sin(l-m),则由于(lm)= angle,因此您重新表达了此乘积给出的正弦/余弦值。或者,可以使用这些标识来查看为什么上面给出的线性乘积旋转矢量。

所有这些身份意味着您很少需要角度。因为角度可能很奇怪-弧度/度数,反正弦/余弦的约定,它们每2 * pi重复一次的事实-这实际上可能会更有用,并且可以节省一堆“ if(ang <180)”等逻辑。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.