在Unity3D中,Vector3.Dot表示求两个向量的点积;Vector3.Cross表示求两个向量的叉积。
点积计算的结果为数值,而叉积计算的结果为向量。两者要注意区别开来。
简单的说,点乘判断角度,叉乘判断方向。
形象的说当一个敌人在你身后的时候,叉乘可以判断你是往左转还是往右转更好的转向敌人,点乘得到你当前的面朝向的方向和你到敌人的方向的所成的角度大小。
1.点积
a·b=|a|·|b|cos<a,b>
- |a|和|b|表示向量的模
- <a,b>表示两个向量的夹角。<a,b>和<b,a> 夹角是不分顺序的。
- 通过点积可以计算两个向量的夹角的。
如果两个向量a,b均 为单位 向量 ,那么a.b等于向量b在向量a方向上的投影的长度
应用
通过点积的计算我们可以简单粗略的判断当前物体是否朝向另外一个物体: 只需要计算当前物体的transform.forward向量与 (otherObj.transform.position – transform.position)的点积即可。
- 若结果 == 0,则两向量互垂直 。
- 若结果 > 0 ,则两向量夹角小于90°,当前物体面对
- 若结果 < 0 ,则两向量夹角大于 90°,当前物体背对
2.叉积
c =a x b
- 其中a,b,c均为向量。即两个向量的叉积得到的还是向量!
- 性质1:c⊥a,c⊥b,即向量c垂直与向量a,b所在的平面。
- 性质2:模长|c|=|a||b|sin<a,b>
- 性质3:满足右手法则。从这点我们有axb ≠ bxa,而axb = – bxa。所以我们可以使用叉积的正负值来判断向量a,b的相对位置,即向量b是处于向量a的顺时针方向还是逆时针方向。
求两向量夹角
using UnityEngine;
using System.Collections;
public class MainScript : MonoBehaviour
{
//向量a
private Vector3 a;
//向量b
private Vector3 b;
void Start ()
{
//向量的初始化
a = new Vector3 (1, 2, 1);
b = new Vector3 (5, 6, 0);
}
void OnGUI ()
{
//点积的返回值
float c = Vector3.Dot (a, b);
//向量a,b的夹角,得到的值为弧度,我们将其转换为角度,便于查看!
float angle = Mathf.Acos (Vector3.Dot (a.normalized, b.normalized)) * Mathf.Rad2Deg;
GUILayout.Label ("向量a,b的点积为:" + c);
GUILayout.Label ("向量a,b的夹角为:" + angle);
//叉积的返回值
Vector3 e = Vector3.Cross (a, b);
Vector3 d = Vector3.Cross (b, a);
//向量a,b的夹角,得到的值为弧度,我们将其转换为角度,便于查看!
angle = Mathf.Asin (Vector3.Distance (Vector3.zero, Vector3.Cross (a.normalized, b.normalized))) * Mathf.Rad2Deg;
GUILayout.Label ("向量axb为:" + e);
GUILayout.Label ("向量bxa为:" + d);
GUILayout.Label ("向量a,b的夹角为:" + angle);
}
}
上面的示例中,我们定义了两个向量a和b。分别求出了他们的点积和叉积,并通过点积和叉积来反过来计算他们的夹角。
这里要说明的是:
1.a.normalized 和 b.normalized 表示的是两个向量的单位向量, 因为在公式里,有向量和模的除法,得出来的结果就是单位向量(单位向量模为1),所以我们这里和后面都直接用单位向量来计算,省去不少麻烦。
2.Mathf.Rad2Deg表示的是 单位弧度的度数。也就是2π/360
3.通过叉积计算度数是通过公式|c|=|a||b|sin<a,b>来逆向求值。|c| 其实就是叉积的模,换句话说,也代表着Vector3.Distance (Vector3.zero, Vector3.Cross (a.normalized, b.normalized))的值。
结果图如下:
[图片上传失败...(image-d2d56f-1649414557572)]
点乘与叉乘项目中的应用
项目需求:
1 通过点乘计算物体B在物体A的前方还是后方
2 通过叉乘,计算物体A转向物体B时,最小角的旋转方向
实现过程:
首先计算出物体A的前方朝向向量v_Bz=B.transform.forward,然后计算物体B相对于物体A的位置向量 v_AB = A.position - B.position;
通过计算v_Bz与v_AB向量点乘结果的正负,判断物体B在物体A的前后
如果物体B在物体A前方, Vector3.Dot(v_Bz,v_AB)大于0
如果物体B在物体A后方, Vector3.Dot(v_Bz,v_AB)小于0
通过计算v_Bz与v_AB向量叉乘的结果,判断旋转方向
如果逆时针旋转,v_C = Vector3.Cross(v_Bz, v_AB)为沿y轴负方向
如果顺时针旋转,v_C = Vector3.Cross(v_Bz, v_AB)为沿y轴正方向
using UnityEngine;
using System.Collections;
public class Vector3_Dot : MonoBehaviour {
public Transform A, B;
Vector3 v_Bz, v_AB, v_A,v_B,v_C;
string str = "";
// Use this for initialization
void Start()
{
}
// Update is called once per frame
void Update()
{
//点乘
v_Bz = B.transform.forward;//B.transform.TransformDirection(Vector3.forward);
v_AB = A.position - B.position;
float f = Vector3.Dot(v_Bz,v_AB);
if (f>0)
{
str = "A在B自身座标系的前方";
}
else if (f<0)
{
str = "A在B自身座标系的后方";
}
else
{
str = "A在B自身座标系的左前方或右方";
}
//差乘
v_A = A.position;
v_B = B.position;
v_C = Vector3.Cross(v_Bz, v_AB);
// A.Rotate(0,0,0);
}
void OnGUI()
{
GUI.Label(new Rect(10,10,200,60),str);
}
void OnDrawGizmos()
{
//差乘绘制相关线
Gizmos.color = Color.blue;
Gizmos.DrawLine(-v_C,Vector3.zero);
//点乘绘制相关线
Gizmos.color = Color.yellow;
Gizmos.DrawLine(Vector3.zero,A.position);
Gizmos.color = Color.yellow;
Gizmos.DrawLine(Vector3.zero,B.position);
Gizmos.color = Color.red;
Gizmos.DrawLine(A.position, B.position);
Gizmos.color = Color.red;
Gizmos.DrawLine(Vector3.zero,v_AB);
Gizmos.color = Color.green;
// Gizmos.DrawLine(A.transform.position, Vector3.left);
}
}
[图片上传失败...(image-ee4442-1649414557572)]
总结
1.判断目标在自己的前后方位可以使用下面的方法:
Vector3.Dot(transform.forward, target.position-transform.position)
返回值为正时,目标在自己的前方,反之在自己的后方
2.判断目标在机子的左右方位可以使用下面的方法:
Vector3.Cross(transform.forward, target.position-transform.position).y
返回值为正时,目标在自己的右方,反之在自己的左方
【参考原文】Unity3D之Vector3.Dot和Vector3.Cross的使用
【参考原文】Unity3D之点乘和差乘