四元数(Quaternion)和旋转 & Unity中的旋转

四元数本质上是一种高阶复数,是一个四维空间,相对于复数的二维空间。我们高中的时候应该都学过复数,一个复数由实部和虚部组成,即x = a + bii是虚数单位,如果你还记得的话应该知道i^2 = -1。而四元数其实和我们学到的这种是类似的,不同的是,它的虚部包含了三个虚数单位,ijk,即一个四元数可以表示为x = a + bi + cj + dk

 

Unity里,tranform组件里面的rotation,它的类型就是四元数。

 

使用矩阵哪儿不好:

旋转其实只需要知道一个向量+一个角度,一共4个值的信息,但矩阵法却使用了16个元素;

而且在做乘法操作时也会增加计算量,造成了空间和时间上的一些浪费;

 

欧拉旋转哪儿不好:

万向节锁问题https://v.youku.com/v_show/id_XNzkyOTIyMTI=.html?debug=flv

 

一个四元数可以表示为q = w + xi + yj + zk,使用q = ((x, y, z)w) = (v, w),其中v是向量,w是实数,这样的式子来表示一个四元数。

 

我们先来看问题的答案。我们可以使用一个四元数q=((x,y,z)sinθ2, cosθ2) 来执行一个旋转。

 

Quaternion.EulerQuaternion.eulerAngles。它们基本可以满足绝大多数的四元数旋转变换。

 

 

和其他类型的转换

 

轴角到四元数:

 

给定一个单位长度的旋转轴(x, y, z)和一个角度θ。对应的四元数为:

q=((x,y,z)sinθ2, cosθ2) 
 

 

 

欧拉角到四元数:

 

给定一个欧拉旋转(X, Y, Z)(即分别绕x轴、y轴和z轴旋转XYZ度),则对应的四元数为:

 

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)

 

 

四元数的插值

 

这里的插值指的是球面线性插值。

 

t是一个在01之间的变量。我们想要基于tQ1Q2之间插值后四元数Q。它的公式是:

Q3  = (sin((1-t)A)/sin(A))*Q1 + (sin((tA)/sin(A))*Q2)

Q = Q3/|Q3|,即单位化

 

 

 

四元数的创建

 

Unity里如何利用四元数进行旋转呢?Unity里提供了非常多的方式来创建一个四元数。例如

 

static Quaternion AngleAxis(float angle,Vector3 axis)

 

它可以返回一个绕轴线axis旋转angle角度的四元数变换。我们可以一个Vector3和它进行左乘,就将得到旋转后的Vector3。在Unity里只需要用一个“ * ”操作符就可以进行四元数对向量的变换操作,

 Vector3 newVector = Quaternion.AngleAxis(90, Vector3.up) * Quaternion.LookRotation(someDirection) * someVector;  

其中:

static Quaternion LookRotation(Vector3 forward);
static Quaternion LookRotation(Vector3 forward,Vector3 upwards);
使用指定的向前方向和向上方向来创建四元数,跟SetLootRotation差不多,区别是可以返回一个Quaternion 

 

 

尽管欧拉角更容易我们理解,但四元数比欧拉角要强大很多。Unity提供了这两种方式供我们选择,我们可以选择最合适的变换。

例如,如果我们需要对旋转进行插值,我们可以首先使用Quaternion.eulerAngles来得到欧拉角度,然后使用Mathf.Clamp对其进行插值运算。

最后更新Quaternion.eulerAngles或者使用Quaternion.Euler(yourAngles)来创建一个新的四元数。

 

又例如,如果你想要组合旋转,比如让人物的脑袋向下看或者旋转身体,两种方法其实都可以,但一旦这些旋转不是以世界坐标轴为旋转轴,比如人物扭动脖子向下看等,那么四元数是一个更合适的选择。Unity还提供了transform.forward, transform.right and transform.up 这些非常有用的轴,这些轴可以和Quaternion.AngleAxis组合起来,来创建非常有用的旋转组合。例如,下面的代码让物体执行低头的动作:

transform.rotation = Quaternion.AngleAxis(degrees, transform.right) * transform.rotation;  

 

 

Unity3D与旋转相关的函数(C#)

 

1void Rotate(Vector3 eulerAngles, float relativeTo)
应用一个欧拉角的旋转角度,eulerAngles.z度围绕z轴,eulerAngles.x度围绕x轴,eulerAngles.y度围绕y轴(这样的顺序)。
如果relativeTo留空或者设置为Space.Self 旋转角度被应用围绕变换的自身轴。(当在场景视图选择物体时,xyz轴显示)如果是Space.World 旋转角度被应用围绕世界的xyz轴。

 

2void SetFromToRotation (Vector3 fromDirection, Vector3 toDirection)
把物体的fromDirection旋转到toDirection

3
void SetLookRotation(Vector3 view);
void SetLookRotation(Vector3 view,Vector3 up);

这个函数根据指定的向前和向上向量创建四元数,建立一个旋转使z轴朝向view, y轴朝向up

4static Quaternion AngleAxis(float angle,Vector3 axis)
物体沿指定轴向axis旋转角度angle

5Quaternion.eulerAngles
存放四元数对应的三个轴向的欧拉角,分别是绕x轴、y轴、z轴旋转的角度

6static Quaternion FromToRotation(Vector3 fromDirection,Vector3 toDirection);
根据两个向量计算出旋转量,计算出来的旋转量为从fromDirection旋转到toDirection的旋转量,跟SetFromToRotation差不多,区别是可以返回一个Quaternion。通常用来让transform的一个轴向(例如 y)toDirection在世界坐标中同步。 

7
static Quaternion LookRotation(Vector3 forward);
static Quaternion LookRotation(Vector3 forward,Vector3 upwards);

使用指定的向前方向和向上方向来创建四元数,跟SetLootRotation差不多,区别是可以返回一个Quaternion 

8
static Quaternion RotateTowards(Quaternion from,Quaternion to, float maxDegreesDelta);
maxDegreesDelta作为角度步长计算从fromto之间的旋转量

9static Quaternion Slerp (Quaternion from : Quaternion to, float t)
球形插值, from转换到to,移动距离为t。当两个quaternion接近时,转换的速度会比较慢。

10static Quaternion Lerp (Quaternion a, Quaternion b, float t)
Slerp相似,且比Slerp快,.但是如果旋转角度相距很远则会看起来很差

11static Quaternion Inverse (Quaternion rotation) : 
返回与rotation相反的方向 

12
static float Angle (Quaternion a, Quaternion b)
计算两个旋转之间的夹角。跟Vector3.Angle() 作用一样。 

13
static Quaternion Euler (float x, float y, float z)
把旋转角度变成对应的Quaternion

 

14void ToAngleAxis (out float angle, out Vector3 axis)
返回物体的旋转角度(物体的z轴和世界坐标z轴的夹角)和三维旋转轴的向量到变量out angle out axis

你可能感兴趣的:(unity,算法)