简介
Quaternion又称四元数,由x,y,z和w这四个分量组成,是由爱尔兰数学家威廉·卢云·哈密顿在1843年发现的数学概念。四元数的乘法不符合交换律。从明确地角度而言,四元数是复数的不可交换延伸。如把四元数的集合考虑成多维实数空间的话,四元数就代表着一个四维空间,相对于复数为二维空间。
四元数不存在欧拉角的万向锁问题,旋转大小角问题,以及旋转不唯一(同一个旋转结果,可以有多个旋转顺序及角度定义)问题,用起来简单。
在Unity中,用Quaternion来存储和表示对象的旋转角度。Quaternion的变换比较复杂,对于GameObject一般的旋转及移动,可以用Transform中的相关方法实现。
最常用的功能为:Quaternion.LookRotation, Quaternion.Angle, Quaternion.Euler, Quaternion.Slerp, Quaternion.FromToRotation, Quaternion.identity
Quaternion类属性
静态属性
- identity 单位四元数,没有角位移。
属性
- eulerAngles 返回或设置该旋转四元数代表的欧拉旋转。Unity内部是使用四元数进行存储的,设置或获取欧拉角时,内部会进行四元数的转换。又因为有欧拉角旋转不唯一,所以可能获取的欧拉角,和你刚才设置的值完全不同。所以,当需要渐进的旋转时,不要读取eularAngles,进行操作,建议用四元数乘法。
- normalized 返回大小时1的四元数。不改变四元数本身,而是返回新的四元数。
- x,y,z 旋转轴,不建议直接修改该值。
- w 转转角度,不可以直接修改该值。
构造函数
-
public Quaternion(float x, float y, float z, float w);
构造一个四元数。
方法
-
public void Set(float newX, float newY, float newZ, float newW);
修改四元数。
-
public void SetFromToRotation(Vector3 fromDirection, Vector3 toDirection);
构建一个从fromDirectoion到toDirection的旋转。
-
public void SetLookRotation(Vector3 view, Vector3 up = Vector3.up);
view:观察方向
up:定义向上的方向
用向上和向前的方向构建旋转。
如果用来确定Transform的朝向,则Z轴是forward,Y轴是upwards。如果forward的方向(view)是0,会报错。
-
public void ToAngleAxis(out float angle, out Vector3 axis);
将旋转,转换成轴角对。这里角是角度。
静态方法
-
public static float Angle(Quaternion a, Quaternion b);
计算两个旋转之间的角度。
-
public static Quaternion AngleAxis(float angle, Vector3 axis);
创建一个围绕 axis 轴旋转 angle 度的旋转。
-
public static float Dot(Quaternion a, Quaternion b);
计算两个旋转的点积。目前使用场景不详。
点积也叫做欧几里得内积,四元数的点积等同于一个四维矢量的点积。点积的值是p中每个元素的数值与q中相应元素的数值的乘积的和。
-
public static Quaternion Euler(float x, float y, float z);
根据欧拉角生成四元数。旋转顺序按照z->y->z。
-
public static Quaternion FromToRotation(Vector3 fromDirection, Vector3 toDirection);
构建从fromDirection到toDirection的旋转。
通常用来旋转 transform 来保证其一个轴朝向世界空间中的toDirection。例如:
设置对象的Y轴朝向z轴(绕x轴旋转90度)
transform.rotation = Quaternion.FromToRotation(Vector3.up, transform.forward);
-
public static Quaternion Inverse(Quaternion rotation);
反向旋转。数学实现时,可以是旋转轴取反,也可以是w值取反。
测试Unity是对旋转轴取反来实现的。
-
public static Quaternion Lerp(Quaternion a, Quaternion b, float t);
在2个旋转之间进行线性插值。
该旋转要比Slerp快,但是当两个旋转差别比较大时,效果不好。
如果是渐进式的更新旋转,确定两个旋转差别比较小时,可以用这个来提升效率。
-
public static Quaternion LerpUnclamped(Quaternion a, Quaternion b, float t);
功能同上,只是,允许t<0或t>1
-
public static Quaternion Slerp(Quaternion a, Quaternion b, float t);
在两个旋转之间进行球面插值。0<=t<=1
-
public static Quaternion SlerpUnclamped(Quaternion a, Quaternion b, float t);
功能同上,允许t<0或t>1
-
public static Quaternion LookRotation(Vector3 forward, Vector3 upwards = Vector3.up);
根据forward和upwards的方向,创建旋转。
该旋转的Z轴对齐forward,X轴对齐forward和upwards的叉积向量,Y轴对齐Z和X轴的叉积。
-
public static Quaternion Normalize(Quaternion q);
将四元数转成方向不变,但是四元数长度为1的四元数(模)。
该方法会改变参数四元数。
-
public static Quaternion RotateTowards(Quaternion from, Quaternion to, float maxDegreesDelta);
旋转四元数(比如旋转朝向)。当旋转角度大于maxDegreesDelta,仅旋转maxDegreesDelta。比如,保持跟另一个对象朝向一致:
transform.rotation = Quaternion.RotationTowards(transform.rotation,target.rotation,rotSpeed*Time.deltaTime);
运算符
-
public static Quaternion operator *(Quaternion lhs, Quaternion rhs);
组合2个旋转。可以认为旋转效果相加:
transform.rotation = Quaternion.AngleAxis(rotSpeedTime.deltaTime, Vector3.up);
欧拉角
欧拉角,用分别三个轴上的旋转,来表示一个完整的3D空间的旋转,Unity以Z->X->Y轴的顺序依次执行旋转,该顺序非常重要,因为同样的旋转,不同的顺序,结果是不同的。