Mathf

Mathf和Math

Math是C#自带的工具类,在包含在system中

Mathf是unity封装的类,包含math中的方法,多了一些适用于游戏开发的方法

一般情况下,我们在游戏开发中使用mathf进行数学计算

Mathf中的常用方法

圆周率:

1
print(Mathf.PI);

取绝对值

1
print(Mathf.Abs(-10));

向上取整

1
print(Mathf.CeilToInt(1.01f));

向下取整

1
print(Mathf.FloorToInt(1.6f));

钳制函数

1
2
int a = Random.Range(5, 30);
print(Mathf.Clamp(a,10,20));

获取最大(小)值

1
2
print(Mathf.Max(1,2,3,4,5,6));
print(Mathf.Min(1,2,3,4,5,6));

一个数的n次幂

1
print(Mathf.Pow(4, 2));

一个数的平方根

1
Print(Mathf.Sqrt(4));

四舍五入

1
print(Mathf.RoundToInt(4.2f));

判断一个数是否是2的n次方

1
print(Mathf.IsPowerOfTwo(4));

判断正负

1
print(Mathf.Sign(-10));

插值运算

1
float result = Mathf.Lerp(start, end, t);

也就是result = start + (end - start) * t;

用法一

1
2
3
4
5
private float start;
void Update()
{
start = Mathf.Lerp(start, 10, Time.deltaTime);
}

接近速度先快后慢,位置无限接近

用法二

1
2
3
4
5
6
7
8
private float time;
private float result;
private float start;
void Update()
{
time += Time.deltaTime;
result = Mathf.Lerp(start, 10, time);
}

匀速变化,t>=1时得到结果

三角函数

弧度、角度相互转化

令,rad = 1;则anger = rad*57.29578……

弧度转角度

1
2
float rad = 1;
float anger = rad * Mathf.Rad2Deg;

角度转弧度

1
2
float anger = 1;
float rad = anger * Mathf.Deg2Rad;

三角函数

1
2
print(Mathf.Sin(30*Mathf.Deg2Rad));
print(Mathf.Asin(0.5f));

坐标系

世界坐标系

transform.position/rotation/eulerAngles的变化会影响一个物体的世界坐标

物体坐标系

物体的右方为x轴,前方为z轴,上方为y轴

transform.localPosition/LocalRotation/localScale的变化会影响一个物体的局部坐标

屏幕坐标系

原点:屏幕左下方

向右为x轴正方向,向上为y轴正方向

视口坐标系

类似屏幕坐标系,左下角为(0,0),右上角为(1,1)

坐标转换

世界转本地

transform.InverseTransformDirection等方法

本地转世界

transform.TransformDirection等方法

世界转屏幕

camera.main.WorldToScreenPoint

屏幕转世界

camera.main.ScreenToWorldPoint

世界转视口

Camera.main.WorldToViewportPoint

视口转屏幕

Camera.main.ViewportToScreenPoint

向量

默认你已经有向量的数学基础

点积

用点积判断物体位置

1
2
3
4
5
6
7
private Vector3 _target;
void Update()
{
Debug.DrawLine(transform.position,transform.position+transform.forward,Color.red);
string dotResult = Vector3.Dot(transform.forward, _target - transform.position)>0?"前方":"后方";
Debug.Log(dotResult);
}

用点积求得角度

1
2
3
4
5
6
[SerializeField]private Transform _target;
void Update()
{
float result = Vector3.Dot(transform.forward, (_target.position - transform.position).normalized);
Debug.Log($"此物体与目标物体的夹角为{Mathf.Acos(result)*Mathf.Rad2Deg}度");
}

虽然我们可以直接用Vector3.Angle获得角度

叉乘

叉乘的几何意义

详见线性代数的本质 | 紫地丁的个人博客 (purpleditine.top)

叉乘计算

1
Debug.Log(Vector3.Cross(transform.forward,target.position-transform.position));

向量插值运算

线性插值

1
Vector3.Lerp(start,end,t);

球形插值

61D2FCFE005D0155ADBE91E2E169FDCB(1)

1
Vector3.Slerp(start,end,t);

四元数!!!

为何要使用四元数

欧拉角旋转约定

heading-pitch-bank

也就是先绕y再x再z旋转

unity中的欧拉角

transform.eulerAngles得到的就是欧拉角

欧拉角的优缺点

优点:直观易理解,储存空间小,可以从一个方向到另一个方向旋转超过180度

缺点:同一旋转的表示不唯一,万向节死锁

无伤理解欧拉角中的“万向死锁”现象_哔哩哔哩_bilibili

四元数是什么

概念

四元数由实数和三个虚数组成,用于在三维空间中表示旋转

构成

一个四元数包含一个标量和一个3D向量

[w,v],w为标量,v为3D向量

任意一个四元数表示一个三维空间中的旋转

轴-角对

在3D空间中,任意旋转都可以表示绕着某个轴旋转一个旋转角得到

对于给定旋转,假设为绕着n轴,旋转b度,n轴为(x,y,z)

那个可以构成四元数

Q = [cos(b/2),sin(B/2)n] ,或

Q = [cos(b/2),sin(B/2)x,sin(B/2)y,sin(B/2)z]

Unity中的四元数

初始化

1
2
Quaternion q = new Quaternion(Mathf.Sin(30*Mathf.Deg2Rad),0,0,Mathf.Cos(30*Mathf.Deg2Rad));
Quaternion q2 = Quaternion.AngleAxis(60, Vector3.right);

四元数和欧拉角相互转化

欧拉角转四元数

Quaternion.Euler(x,y,z)

四元数转欧拉角

Quaternion q;
q.eulerAngles

四元数常用方法

单位四元数

单位四元数没有旋转量(角位移)

Quaternion.identity

插值运算

在四元数中Lerp和Slerp差别不大,由于算法不同,Slerp的效果会好一些,慢一些

1
A.rotation = Quaternion.Slerp(A.rotation, B.rotation, t);

向量指向转四元数

1
Quaternion q = Quaternion.LookRotation(B.position - A.position);

四元数计算

四元数相乘

两个四元数相乘得到一个新的四元数,代表两个旋转量的叠加,旋转相对的是局部坐标

四元数乘向量

四元数乘向量返回一个原向量旋转后的新向量