赞
踩
几何意义上说,向量是有大小和方向的有向线段。
“点”有位置,但没有大小和方向,“向量”有大小和方向,但没有位置。所以使用“点”和“向量”的目的完全不同。”点”描述位置,“向量”描述位移。
零向量非常特殊,因为它是唯一大小为零且没有方向的向量。
几何解释:向量变负,将得到一个和向量大小相等,方向相反的向量。
向量的大小就是向量各分量平方和的平方根
设三维向量A(x,y,z),则A向量的大小为:|A|=√(x^2 +y^2 +z^2)
二维向量同理
Unity中代码实现
Vector3 pos;//向量
// 开平方计算
Mathf.Sqrt(Mathf.Pow(pos.x, 2) + Mathf.Pow(pos.y, 2) + Mathf.Pow(pos.z, 2));
// UNITY现成的API计算
pos.magnitude;
标量与向量不能相加,但它们可以相乘。结果将得到一个向量。与原向量平行,但长度不同或者方向相反。
同理标量与向量也能相除
对于许多向量,我们只关心向量的方向不在乎向量的大小,如:“我面向的是什么方向?”,在这样的情况下,使用单位向量非常方便,单位向量就是大小为1的向量,单位向量经常也被称作为标准化向量或者法线。
要标准化向量,将向量除以它的大小(模)即可。
Unity中代码实现
Vector3 pos;//向量
// UNITY现成的API计算
pos.normalized;
两个向量的维数相同,那么它们能相加,或者相减。结果向量的维数与原向量相同。向量加减法的记发和标量加减法的记法相同。例如:[x,y,z] + [a,b,c] = [x+a,y+b,z+c]
向量点乘就是对应分量乘积的和。其结果是一个标量. [x,y,z] · [a,b,c] = ax+by+cz;
几何解释:
一般来说,点乘结果描述了两个向量的“相似”程度,点乘结果越大,两个向量越相近,也就是两个向量之间的夹角越小
通过反余弦函数 Acos 可以将点积的结果转换为两向量之间的夹角 θ 的角度,取值范围 [0, 180)
案例代码
void Start()
{
Vector3 up = Vector3.up;
Vector3 right = Vector3.right;
float dot = Vector3.Dot(up, right);
Debug.Log("点积结果:" + dot);
float rad = Mathf.Acos(dot);
Debug.Log("反余弦函数获取到的弧度值:" + rad);
float angle = Mathf.Rad2Deg * rad;
Debug.Log("弧度值转换后的角度值:" + angle);
}
判断物体的前后关系
using UnityEngine; public class Test : MonoBehaviour { public Transform Cube1; public Transform Cube2; private void Update() { if (Input.GetKeyDown(KeyCode.Space)) { Vector3 direction = Cube2.position - Cube1.position; float dot = Vector3.Dot(direction.normalized, Cube1.forward); if (dot > 0) { Debug.Log("Cube2在Cube1的前方"); } else if (dot < 0) { Debug.Log("Cube2在Cube1后方"); } else { Debug.Log("Cube2和Cube1在相同的位置"); } } } }
判断敌人是否在技能的攻击范围之内
using UnityEngine; public class Test : MonoBehaviour { public Transform Player;//玩家 public Transform Enemy;//敌人 public float AttackDistance = 2;//攻击距离 public float AttackRange = 90;//攻击角度 private void Update() { if (Input.GetKeyDown(KeyCode.Space)) { if(Vector3.Distance(Player.position,Enemy.position) <= AttackDistance) { //在攻击距离内,继续判断是否在攻击范围内 float dot = Vector3.Dot((Enemy.position - Player.position).normalized, Player.forward); float angle = Mathf.Acos(dot) * Mathf.Rad2Deg; Debug.Log("玩家和敌人之间的夹角:" + angle); if(angle <= AttackRange) { Debug.Log("敌人在玩家的攻击范围内,可以进行攻击"); } else { Debug.Log("敌人在玩家的攻击范围外"); } } else { Debug.Log("敌人在玩家的攻击距离外"); } } } }
向量叉乘得到一个向量,并且不满足交换律。 它满足反交换律 a × b = -(b × a)
叉乘公式:[x,y,z] × [a,b,c] = [yc-zb , za-xc , xb-ya]
几何解释:叉乘得到的向量垂直于原来的两个向量。
上图中向量a 和向量b 在一个平面上,向量c 垂直该平面,向量c 垂直于a和b
向量c 的长度 等于 向量a、向量b 模与夹角 sin值的积如下
c=axb = |a||b|sinθ
通过 |a||b|sinθ公式也可以推算出|axb|等于以a和b为两边的平行四边形面积
h = |a|sinθ
平行四边形面积=|b|h = |b|(|a|sinθ)
平行四边形面积=|b|h = |a||b|sinθ
也就是说a、b向量的叉积结果等于平行四边形的面积
那么垂直于平面的向量有两个,如何确认叉乘结果向量的朝向呢
通过计算向量c在坐标轴正方向 normal = (1, 1, 1).normalized 单位向量上的投影长度,判断向量a 到向量b是顺时针还是逆时针
令 value = c· normal = (y1z2 - z1y2, z1x2 - x1z2, x1y2 - y1x2) · (1, 1, 1).normalized
在右手坐标系中
当 value > 0 时,向量a到向量b是逆时针方向, θ 取值范围是 [0, 180)
当 value = 0 时,向量a 与向量b 平行共线, θ 值是 0
当 value < 0 时,向量a到向量b 是顺时针方向, θ 取值范围是 [0, -180)
在左手坐标系中(Unity 使用的是左手坐标系)
当 value > 0 时,向量a到向量b是顺时针方向, θ 取值范围是 [0, 180),
当 value = 0 时,向量a 与向量b 平行共线, θ 值是 0
当 value < 0 时,向量a到向量b是逆时针方向, θ 取值范围是 [0, -180),
叉乘符合右手定则
在左手坐标系中四根手指的旋转方向是顺时针的,所以在左手坐标系中(Unity 使用的是左手坐标系),如果向量a和向量b呈顺时针,那么叉乘结果c 指向大拇指方向,如果呈逆时针,则c指向大拇指的反方向
在右手坐标戏中四根手指的旋转方向是逆时针的,所以在右手坐标系中,如果向量a和向量b呈逆时针,那么叉乘结果c指向大拇指方向,如果呈顺时针,则c指向大拇指的反方向
叉积判断物体的左右关系
using UnityEngine; public class Test : MonoBehaviour { public Transform Cube1; public Transform Cube2; private void Update() { if (Input.GetKeyDown(KeyCode.Space)) { Vector3 direction = Cube2.position - Cube1.position; Vector3 cross = Vector3.Cross(direction, Cube1.forward); if (cross.y > 0) { Debug.Log("Cube2在Cube1的左方"); } else if (cross.y < 0) { Debug.Log("Cube2在Cube1右方"); } else { Debug.Log("Cube2和Cube1在相同的位置"); } } } }
叉积判断鼠标是否在UI矩形内
using UnityEngine; public class Test : MonoBehaviour { private RectTransform mRectTrans;//UI public Camera UICamera;//UI摄像机 Vector3[] points = new Vector3[4];//矩形的四个顶点 private void Update() { if (Input.GetMouseButtonDown(0)) { //获取UI坐标系中的鼠标位置 Vector2 mousePos = Input.mousePosition; Vector2 localPos; RectTransformUtility.ScreenPointToLocalPointInRectangle(mRectTrans, mousePos, UICamera, out localPos); //获取矩形的四个顶点位置 mRectTrans.GetLocalCorners(points); if (IsInRect(points[0], points[1], points[2], points[3], localPos)) { Debug.Log("在UI矩形内"); } else { Debug.Log("不在UI矩形内"); } } } private bool IsInRect(Vector2 A, Vector2 B, Vector2 C, Vector2 D,Vector2 E) { //true:水平方向在矩形内,false:水平方向在矩形外 bool h = Cross(A - B, A - E) * Cross(C - D, C - E) >= 0; //true:垂直方向在矩形内,false:垂直方向在矩形外 bool v = Cross(A - D, A - E) * Cross(C - B, C - E) >= 0; return h && v; } // Start is called before the first frame update void Start() { mRectTrans = GetComponent<RectTransform>(); } // 计算两个向量的叉积 public static float Cross(Vector2 a, Vector2 b) { return a.x * b.y - b.x * a.y; } }
Unity中常用点乘和叉乘来计算两个物体之间的位置关系
例如:敌人在你身后的时候,叉乘可以判断你是往左转还是往右转更好的转向敌人,点乘得到你当前的面朝向的方向和你到敌人的方向之间的夹角
转向敌人代码实现
using UnityEngine; public class Test : MonoBehaviour { public Transform Player;//玩家 public Transform Enemy;//敌人 public float RotateSpeed = 20f; private void Start() { } private void Update() { //计算夹角 float dot = Vector3.Dot((Enemy.position - Player.position).normalized, Player.forward); ; float angle = Mathf.Acos(dot) * Mathf.Rad2Deg; //夹角不为0 if(angle != 0 && angle > 1f) { //**使Player一直朝向敌人** //计算方向 Vector3 direction = Vector3.Cross(Enemy.position - Player.position, Player.forward); if (direction.y < 0) { //左转 Player.Rotate(Player.up, RotateSpeed * Time.deltaTime); } else if (direction.y > 0) { //右转 Player.Rotate(Player.up, -RotateSpeed * Time.deltaTime); } } } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。