Unity基础(17)-四元数与欧拉角与矩阵
2018-07-09 本文已影响25人
元宇宙协会
Unity中表示旋转有三种方式:四元数,欧拉角,矩阵
一、四元数
1、概念
Quaternion中存放了x,y,z,w四个数据成员,可以用下标来进行访问,对应的下标分别是0,1,2,3
其实最简单来说:四元数就是表示一个3D物体的旋转,它是一种全新数学数字,甚至不是复数。
四元数其实就是表示旋转。
1、四元数的书写格式
q = w v 这里w是标量,v是向量
另一种表示格式
q = w(x,y,z) 看到这里我们就熟悉了。
一般我们在Unity中表示旋转的方式:
c.Rotate (new Vector3(10,0,0));
c.Rotate (Quaternion.identity * Vector3.left);
2、Unity中四元数API
- 1.来把角度转化为相应四元素
Quaternion rot=Quaternion.Euler(30,60,90);
旋转顺序是,先绕Z轴转动90度,再绕X轴转动30度,最后绕Y轴转动60度
- 2.绕指定轴旋转指定角度相应的四元素
Quaternion rot= Quaternion.AngleAxis(60, transform.forward);
意思为绕自身正方向转60度其相应的四元素,当然了,第一个参数可以是其他方向变量
- 3.两个四元素相乘,代表按顺序进行两次旋转
Quaternion rot1=Quaternion.Euler(0,30,0);
Quaternion rot2=Quaternion.Euler(0,0,45);
Quaternion rot=rot2*rot1;
意思是先绕y旋转30度再绕z旋转45度,所以,你要先绕哪个四元素先旋转就放最右边
- 4.四元素与向量相乘,得到的是将原向量旋转后的新向量
Vector3 to = Quaternion.AngleAxis(45, Vector3.up)* Vector3.forward
to是将Vector3.forward绕Vector3.up旋转45度后得到的新向量
- 5.已知两个向量,求从一个向量转到另一个向量的四元数:
Quaternion rot=Quaternion.FromToRotation(Vector3.up,Vector3.forward);
这的意思是创建一个从y轴正方向到z轴正方向的旋转角度所对应的四元数
例子:
Vector3 aimDirection=(targetTrans.position – transform.position).normalized;
Quaternion rot = Quaternion.FromToRotation(transform.up,aimDirection);
transform.rotation = rot * transform.rotation;
此游戏对象自身转向这个计算出来的偏转角所对应的四元数,如果将此至于Update中就可以做到不断对准目标
- 6.创建一个让Z轴正方向和Y轴正方向指向规定方向的旋转
Quaternion rot = Quaternion.LookRotation(Vector3.right, Vector3.down);
这的意思是创建一个让Z轴正方向指向世界坐标x轴正向,y轴正方向竖直向下的旋转角度所对应的四元数
Vector3 vr = new Vector3(1,0,0);
Quaternion q = Quaternion.LookRotation(vr);
void SetLookRotation(Vector3 view);
void SetLookRotation(Vector3 view,Vector3 up);
也是根据指定的向前和向上向量创建四元数,本质计算过程和LookRotation一样,
只不过LookRotation是Quaternion上的静态函数,而SetLookRotation则是Quaternion的成员函数。
- 7.已知两个由四元数代表的旋转角度,求出从一个角度渐变到另一个角度的增量
Quaternion rot=Quaternion.Euler(0,30,0)
Quaternion targetRot= rot*transform.rotation;
transform.rotation= Quaternion.RotateTowards(transform.rotation,targetRot,90*Time.deltaTime);
意思为游戏对象的角度会逐渐向targetRot以90*Time.deltaTime的角速度(90度每秒)逐渐逼近,因为这代码并不能够在一帧中完成所以要放于update中
- 8.两个四元数之间的线性插值lerp
transform.rotation=Quaternion.Lerp(transform.rotation,Vector3.up,0.5f);
第一个参数是起始的角度所对应的四元数
第一个参数是终点的角度所对应的四元数
第三个参数是这个过程需要多少秒
- 9.两个四元数之间的球形插值Slerp
transform.rotation=Quaternion.Slerp(transform.rotation,Vector3.up,0.5f);
第一个参数是起始的角度所对应的四元数
第一个参数是终点的角度所对应的四元数
第三个参数是这个过程需要多少秒
- 10.旋转轴和旋转角度算出四元数
Quaternion RotateTowards(Quaternion from,Quaternion to, float maxDegreesDelta);
以maxDegreesDelta作为角度步长计算从from到[to]
根据旋转轴和旋转角度算出四元数
- 11.四元数对应的三个轴向的欧拉角
Quaternion.eulerAngles
存放四元数对应的三个轴向的欧拉角,分别是绕x轴、y轴、z轴旋转的角度
Quaternion q3 = new Quaternion();
q3.eulerAngles = new Vector3(10, 30, 20);
Quaternion qx3 = Quaternion.AngleAxis(10,Vector3.right);
Quaternion qy3 = Quaternion.AngleAxis(30,Vector3.up);
Quaternion qz3 = Quaternion.AngleAxis(20,Vector3.forward);
Quaternion qxyz3 = qz3*qy3*qx3;
从这里可以看出unity中旋转顺序也是按先绕x轴旋转,然后y,最后z。unity中对向量应用旋转量使用的是向量右乘,即如下:
Vector3 newV = qxyz3*v=qz3*qy3*qx3*v;
二、欧拉角
1、概念
1-描述定点转动刚体的位形需要三个独立坐标变量,即x,y,z
2-描述定轴转动的刚体的位形只需要一个独立坐标变量即转角。
3-将定点转动的过程分解为三个相互独立的定轴转动,相应的二三个相互独立的转角,即欧拉角。
2、什么是欧拉角?
Roll 滚动角 Z轴不动
Pitch 俯仰角 X轴不动
Heading(Yaw) 偏航角 : 就是Y轴不动
Paste_Image.png那么使用欧拉角表示旋转矩阵
绕Z轴旋转
这里的角度是偏航角
绕Y轴旋转
这里的角度是俯仰角
绕X轴旋转
这里的角度是翻滚角 Paste_Image.png 最后乘出来
所以说:
3、局限性
欧拉角会产生万向锁bug
一旦选择pitch角为±90°,就被限制在只能绕垂直轴旋转
三、矩阵
1、概念
unity中仅仅提供了一个4×4的矩阵类Matrix4x4,它可以包含位移T、旋转R和伸缩信息。矩阵中的元素都对应一个mxy的公有成员变量,因而要访问单个元素的话可以直接访问其成员。同时也提供了下标访问,如下
public float this [int row, int column]
{
get
{
return this [row + column * 4];
}
set
{
this [row + column * 4] = value;
}
}
public float this [int index]
四元数和旋转矩阵之间的转换
unity中没有提供直接的四元数到旋转矩阵的转换,但是使用它们的一些成员函数可以实现两者之间的转换。
- 1 四元数到旋转矩阵
使用Matrix4x4的成员函数SetTRS
void SetTRS(Vector3 pos,Quaternion q,Vector3 s);
Quaternion q = Quaternion.LookRotation(new Vector3(0,0.5,1));
Matrix4x4 rot = new Matrix4x4();
rot.SetTRS(new Vector3(0,0,0),q,new Vector3(1,1,1));
- 2 旋转矩阵到四元数
使用Quaternion类的LookRotation函数
static Quaternion LookRotation(Vector3 forward,Vector3 upwards);
Matrix4x4 rot = new Matrix4x4();
rot.SetTRS(new Vector3(0,0,0),q,new Vector3(1,1,1));
Vector4 vy = rot.GetColumn(1);
Vector4 vz = rot.GetColumn(2);
Quaternion q = Quaternion.LookRotation(new Vector3(vz.x,vz.y,vz.z),new Vector3(vy.x,vy.y,vy.z));
- 3 矩阵的坐标转换
// 矩阵 从自身矩阵转成世界矩阵
Matrix4x4 ma = tf.localToWorldMatrix;
// 矩阵 从世界矩阵转成自身矩阵
Matrix4x4 ma1 = tf.worldToLocalMatrix;