三维数学 - Vector3
# 三维数学 - Vector3
- 向量
- 什么是向量
- 向量的形式
- 向量的大小
- 向量的方向
- 向量运算
- 向量相减
- 向量相加
- 向量与标量的乘除法
- 点乘
- 叉乘
- 三角函数
- 角的度量单位
- 三角函数
- 反三角函数
- 欧拉角
- 常用属性与方法
# 向量
# 什么是向量
- 一个数字列表,表示各维度上的有向位移。
- 一个有大小、方向的物理量
- 大小即为向量的模长
- 方向即为空间中向量的指向
- 可以表示物体的位置与方向
# 向量的形式
二维向量中的形式是(x,y),三维向量中的形式是(x,y,z)
# 向量的大小
- 向量各分量的平方和的平方根
- $\sqrt (x^2+y^2+z^2)$
- API:
float dis = vector.magnitude
- 模的平方
vector.sqrMagnitude
- 模的平方
# 向量的方向
- 获取向量方向也称“标准化向量”或者“归一化向量”
- 单位向量:大小为1的向量
- 几何意义:将该向量拉长/缩短,使模长等于1
- API:
Vector3 v = vector.normalized;
- v为vector的单位向量
# 向量相减
- 等于各分量相减
- 公式:[x1,y1,z1] - [x2,y2,z2] = [x1-x2,y1-y2,z1-z2]
- 几何意义:向量a与b相减,结果理解为
b的终点为起点,a的终点为终点,诞生一条新向量,方向由b指向a
- 应用:计算两点间的距离和相对方向,可以用于制作抛射物,如子弹发射
public GameObject g;
private Vector3 v;
void Start()
{
g = GameObject.Find("Cube");
v = (g.transform.position - transform.position)
}
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# 向量相加
- 等于各分量相加和
- 公式: [x1,y1,z1] + [x2,y2,z2] = [x1+x2,y1+y2,z1+z2]
- 几何意义:向量a与b相加,平移使b的起点与a的终点重合,结果为
以a的起点为起点,以b的终点为终点
# 向量的点乘
- 公式:各分量乘积和
- [x1,y1,z1]·[x2,y2,z2] = x1x2 + y1y2 + z1z2
- 几何意义: $ab=|a||b|cos(a,b)$
- 两个向量的单位向量相乘后,再乘以二者夹角的余弦值
- API:
float dot = Vector3.Dot(va,vb)
public float length_a,length_b;
public GameObject g;
void Start()
{
length_a = this.transform.position.magnitude;
length_b = g.transform.position.magnitude;
Debug.Log(Vector3.Dot(this.transform.position.normalized, g.transform.position.normalized));
Debug.Log("Angle is:"+Mathf.Acos((Vector3.Dot(this.transform.position, g.transform.position)) / (length_a * length_b))*Mathf.Rad2Deg);
}
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# 向量的叉乘
公式: [x1,y1,z1] * [x2,y2,z2] = [y1*z2 -z1*y2,z1*x2 - x1*z2, x1*y2 - y1*x2]
几何意义:结果为两个向量所组成的面的垂直向量,模长为两向量模长乘积再乘夹角的正弦值
API:
Vector v = Vector3.Cross(a,b)
应用
- 创建垂直于平面的向量
# 角的度量方式
角度与弧度换算: PI = 180° 1弧度 = 180° / PI 1角度 = PI / 180°
API: 弧度 = 角度 * Mathf.Deg2Rad 角度 = 弧度 * Mathf.Rad2Deg
# 三角函数
- 已知一边一角,求另一边长
- 对边: a, 角的对立边
- 临边: b, 角的相邻边
- 斜边: c, 角的斜边
- 公式:
- 正弦 sin(x) = a / c
- 余弦 cos(x) = b / c
- 正切 tan(x) = a / b
- API:
- Mathf.Sin(float radian)
- Mathf.Cos(float radian)
- Mathf.Tan(float radian)
# 欧拉角
- 使用三个角度保存方位
- X与Z沿自身坐标系旋转,Y沿世界坐标系
- 优点:
- 仅用三个数字表达方位,占空间小
- 沿坐标轴旋转的单位是角度,符合人类思维
- 任意三个数字都是合法的,不存在不合法的欧拉角
- 万向节死锁
- 游戏编译期间,代码操作X轴只能+-90°,当抵达极限值时,会发生万向节死锁
- 即,Y与Z沿同一轴旋转
- 范围:
- X: 90~-90
- Y: 0~360
- Z: 0~360
切记,Unity中的物体欧拉角通过
this.transform.eularAngles
获取,类型为Vector 3
,虽然与position
一样是Vector 3
类型,但欧拉角的x,y,z仅代表沿各轴旋转的角度,并没有方向的概念。
但由于欧拉角的X在转到+-90°时会发生万向节死锁,因此引入了一个新的概念 —— 四元数
# 四元数
Unity中提供了Quaternion
工具类用于操作四元数计算,最简单地,我们可以通过Quaternion.Euler(0,30,0)
表示为物体沿y轴旋转30°
我们在欧拉角计算中可以通过加法实现角度旋转,但我们并不能直接用欧拉角去加四元数
欧拉角加法
this.transform.eularAngles += new Vector3(1,0,0); 物体沿X轴旋转一度
四元数加法
this.transform.rotation *= Quaternion.Euler(1,0,0);
Quaternion r1 = Quaternion.Euler(0,30,0) * Quaternion.Euler(0,20,0)
Quaternion r2 = Quaternion.Euler(0,50,0)
r1的旋转与r2是一样的
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# 补充
有时,我们只想知道对比俩向量的长度,可以直接用sqrMagnitude
而不是magnitude
,相比后者,前者不需要开方,可以节省性能。
# 常用方法
# Angle
- 参数: 向量A,向量B
- 作用:求出两个向量相交角的角度
# Distance
- 参数: 向量A,向量B
- 作用: 求出两个向量间的长度
# Lerp
- 参数: 向量A,向量B,速度
- 作用: 求出A和B向量间的线性插值,可用于做减速运动
- 示例:
if (GUILayout.RepeatButton("按我"))
{
this.transform.position = Vector3.Lerp(this.transform.position, new Vector3(0, 0, 10),0.1f);
}
1
2
3
4
2
3
4
A会逐渐接近B,但永远无法到达B,从而实现肉眼上的减速运动。
# MoveTowards
- 参数: 向量A,向量B,速度X
- 作用: A每次向B移动X距离,作用与Lerp类似,但会抵达终点
- 示例:
if (GUILayout.RepeatButton("按我"))
{
this.transform.position = Vector3.MoveTowards(this.transform.position, new Vector3(0, 0, 10), 0.1f);
}
1
2
3
4
2
3
4
这是匀速啊,但我想实现开头慢中间快末尾慢该怎么办呢? 我们可以使用AnimationCurve实现这种想法
public AnimationCurve curve;
public float x;
private void OnGUI()
{
if (GUILayout.RepeatButton("按我"))
{
x += Time.deltaTime;
this.transform.position = Vector3.MoveTowards(this.transform.position, new Vector3(0, 0, 10), curve.Evaluate(x));
}
}
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10