在游戏开发中,确定目标的方位,朝向,夹角等相关数据需要用到向量间的计算,其中最常用到的就是点乘和叉乘。
说实话,因为向量的运算在平时开发中不是经常使用,我也总弄混这两种运算的含义,所以这次好好区分一下,也给有同样困扰的朋友一点小小的帮助。
因为我们主要研究的是游戏开发中的3D世界向量,所以下面的介绍会以几何定义为主,不研究其代数定义。
1.点乘
定义
又称点积、数量积、标量积。
从几何角度看,点乘是两个向量的长度和它们的夹角余弦值的积。
从名称和定义上来看,点乘的结果是标量。
点乘的名称也源自于点乘的运算符号。
通过上面的公式,我们还可以得到如下公式。
也就是说如果给定了两个向量,那么我们就可以求出两个向量的夹角。
关于这里的计算需要插播一个点,当两个单位向量的长度都是1的时候,向量的点乘就是他们夹角的余弦值。在游戏开发中会有归一化的操作,然后直接求夹角的情况,如果对这个知识点没有了解,可能看不懂夹角计算的原理。
我们通过点积公式可以看出来a,b都是标量,都是正数,余弦值会根据角度有正负变化。
当(0-90)°的时候,余弦值是正数,整个点乘公式都是正的。
当90°的时候,余弦值为0,整个公式为0。
当(90-180)°的时候,余弦值是负数,整个公式为负的。
利用这个性质,我们可以根据点乘的正负,做一些判断了。
在Unity中的应用
下面会直接用代码解释如何使用Unity提供的数学库进行点乘相关运算
using UnityEngine;
public class Example : MonoBehaviour
{
// 红色方块为敌人
// 蓝色方块为自身
public Transform cubeRed;
public Transform cubeBlue;
private void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
CalculateDot();
}
}
private void CalculateDot()
{
// 先计算出敌人想对自身的位置信息
// 再使用自身正方向与相对方向两个向量做点乘的相关运算
Vector3 relativePosition = cubeRed.position - cubeBlue.position;
Vector3 cubeForward = cubeBlue.forward;
// 计算两个向量的点乘
// 如果大于0说明敌人在自身前面
// 如果小于0说明敌人在自身后面
// 如果等于0说明敌人在自身左右
float result = Vector3.Dot(cubeForward, relativePosition);
Debug.Log("点积的结果:" + result);
// 得到两个向量后,可以直接计算其夹角
float angle = Vector3.Angle(cubeForward, relativePosition);
Debug.Log("两个向量的夹角:" + angle);
// 这是前面说到的当两个向量的长度都为1时,点乘的结果就是夹角的余弦值
float cos = Vector3.Dot(cubeForward.normalized, relativePosition.normalized);
Debug.Log("余弦值:" + cos);
// 通过反余弦函数得到两个向量的角度
// 不过这里得到是弧度值,并不是角度值
float radians = Mathf.Acos(cos);
Debug.Log("通过余弦值求弧度:" + radians);
// 弧度值通过数据库转换成角度值
angle = radians * Mathf.Rad2Deg;
Debug.Log("把弧度转换成角度:" + angle);
}
}
得到的结果如图所示,当敌人在自身后方时,点乘的结果小于0,当敌人在自身前方时,点乘的结果大于0。
2.叉乘
定义
又称叉积、向量积
首先叉乘的结果是向量不是标量。
叉乘的名称也来源于符号
叉乘的公式定义稍微复杂一点。
叉乘最后的结果是一个向量,大小可以根据公式算出,但是方向要根据右手法则确定。
实际上Unity中用的是左手坐标系,所以确定方向的时候我们要用左手法则,最后得到的方向正好与右手法则相反。所以两个向量的叉乘并不是一个真向量,它受参照系的影响,这个在以后的计算中要注意我们使用的到底是哪种坐标系。
Unity官方API文档
几何意义
如果以向量a和b为边构成一个平行四边形,那么这两个向量的叉乘的模长与这个平行四边形的面积相等。
其实这个概念很好理解。我们不考虑叉乘方向的问题,叉乘的模长就是a*b*sinθ,其实也就是平行四边形面积公式中的底乘高。
在Unity中的应用
private void CalculateCross()
{
Vector3 relativePosition = cubeRed.position - cubeBlue.position;
Vector3 cubeForward = cubeBlue.forward;
Vector3 result = Vector3.Cross(cubeForward, relativePosition);
Debug.Log(result.y);
}
根据左手定则,y轴是法向量的方向,当y大于零的时候,敌人在我方右边,当y小于零的时候,敌人在我方左边。
在实际开发中,我们可以用叉乘来判断最优转向角,根据敌人的方位,判断我们应该向什么方向是最快的。
简单来说,在两个物体的位置关系判断中。
点乘可以判断出目标物体在我的前方还是后方。大于零在前方,小于零在后方。
叉乘可以判断出目标物体在我的左边还是右边。大于零在右方,小于零在左方。
在计算机图形学中。
点乘可以用来计算夹角余弦值。
叉乘可以用来计算平面法向量。