Posts Tagged ‘Quaternion’

【Unity3D】关于Vector3向量与Quaternion四元数的转换与应用

星期二, 四月 7th, 2015 3,653 views

在Unity中大家对Vector3应该说是很熟悉了,这里就简单带过一下,Vector3表示一个三维向量(x,y,z),例如Vector3.forward等价于new Vectory(0,0,1),即x=0,y=0,z=1的一个向量。图就不画了,大家高中都学过。
而Quaternion表示一个四元数,何为四元数,例如ai+bj+ck+d这样一个超复数,篇幅有限高数这里也不多说了,我们只关注一下Unity的四元数类的使用就好。在Unity中Quaternion(四元数类)主要用来处理物体的旋转,其实数变量由x,y,z,w四个参数构成,区间[-1,1]。
例如绕y轴旋转180°写做(0,1,0,0),调用公式计算过程如下:

由欧拉旋转(X,Y,Z)转换为四元数(x,y,z,w)
—————————————————->
x = sin(Y/2)sin(Z/2)cos(X/2)+cos(Y/2)cos(Z/2)sin(X/2)
y = sin(Y/2)cos(Z/2)cos(X/2)+cos(Y/2)sin(Z/2)sin(X/2)
z = cos(Y/2)sin(Z/2)cos(X/2)-sin(Y/2)cos(Z/2)sin(X/2)
w = cos(Y/2)cos(Z/2)cos(X/2)-sin(Y/2)sin(Z/2)sin(X/2)
q = (x, y, z, w)
—————————————————->
X = 0
Y = 180
Z = 0
—————————————————->
x = 0
y = 1
z = 0
w = 0

在Unity中这一套转换可以直接调用方法Quaternion.Euler(0, 180, 0)或者transform.Rotate(0, 180, 0)完成。euler即欧拉角的意思,欧拉角可以用Vector进行表示,表示在x,y,z三轴上的旋转角度。
同时transform.rotation即是一个四元数,表示物体的旋转角度方向,我们可以通过Quaternion.Euler和Quaternion.eulerAngles(但这个方法在Unity4之后的版本已经过时)将欧拉角转换为四元数。

因此假设需要让一个物体的顺时针方向以y轴旋转90°有以下几种方法:

1
2
3
4
5
6
7
8
//用四元数的欧拉方法 旋转到90°
transform.rotation = Quaternion.Euler(new Vector3(0, 90, 0));

//用四元数的向量方法 Vector3(1, 0, 0) 表示1个90°方向的向量
transform.rotation = Quaternion.LookRotation(new Vector3(1, 0, 0));

//每一帧自旋转90°
transform.Rotate(new Vector3(0, 90, 0));

以上方法均可在一帧之内旋转顺时针绕y轴旋转90°。但通常游戏中有一个缓慢转动的过程,如果需要一步到位,而是慢慢旋转到90°应该如何去做呢。我们可以使用以下方法:

1
2
3
4
5
//使用四元数的球形差值方法 在每一帧中调整与目标四元数的差值
transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(new Vector3(1, 0, 0)), 10 * Time.deltaTime);

//使用Vector3的RotateTowards方法将一个向量转向另一个向量
transform.rotation = Quaternion.LookRotation(Vector3.RotateTowards(transform.forward, new Vector3(1, 0, 0), Time.deltaTime, Time.deltaTime));

从理论上来说球形差值Quaternion.Slerp的转向要平滑一些但相应的运算量大,每一帧都在出现误差值所以每一帧都在校调,而RotateTowards的方法要简洁但粗暴一些,但转向的平滑性不如前者好,特别是在多方向同时操作上,会出现一些不平滑的问题。
综上,建议在设计转向模块的时候,保留两种方案,在实际操作中对比两种方案的显示效果,择优选用。

本篇到此,欢迎大家补充新的方法,用以达到以上两端代码块同样的效果。

BeiTown
2015.04.07