Unity四元数和旋转

Posted 凉城旧巷旧少年

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Unity四元数和旋转相关的知识,希望对你有一定的参考价值。

四元数介绍

 

旋转,应该是三种坐标变换——缩放、旋转和平移,中最复杂的一种了。大家应该都听过,有一种旋转的表示方法叫四元数。按照我们的习惯,我们更加熟悉的是另外两种旋转的表示方法——矩阵旋转和欧拉旋转。矩阵旋转使用了一个4*4大小的矩阵来表示绕任意轴旋转的变换矩阵,而欧拉选择则是按照一定的坐标轴顺序(例如先x、再y、最后z)、每个轴旋转一定角度来变换坐标或向量,它实际上是一系列坐标轴旋转的组合。

 

那么,四元数又是什么呢?简单来说,四元数本质上是一种高阶复数(听不懂了吧。。。),是一个四维空间,相对于复数的二维空间。我们高中的时候应该都学过复数,一个复数由实部和虚部组成,即x = a + bi,i是虚数单位,如果你还记得的话应该知道i^2 = -1。而四元数其实和我们学到的这种是类似的,不同的是,它的虚部包含了三个虚数单位,i、j、k,即一个四元数可以表示为x = a + bi + cj + dk。那么,它和旋转为什么会有关系呢?

 

在Unity里,tranform组件有一个变量名为rotation,它的类型就是四元数。很多初学者会直接取rotation的x、y、z,认为它们分别对应了Transform面板里R的各个分量。当然很快我们就会发现这是完全不对的。实际上,四元数的x、y、z和R的那三个值从直观上来讲没什么关系,当然会存在一个表达式可以转换,在后面会讲。

 

大家应该和我一样都有很多疑问,既然已经存在了这两种旋转表示方式,为什么还要使用四元数这种听起来很难懂的东西呢?我们先要了解这三种旋转方式的优缺点:

  • 矩阵旋转
    • 优点:
      • 旋转轴可以是任意向量;
    • 缺点:
      • 旋转其实只需要知道一个向量+一个角度,一共4个值的信息,但矩阵法却使用了16个元素;
      • 而且在做乘法操作时也会增加计算量,造成了空间和时间上的一些浪费;

  • 欧拉旋转
    • 优点:
      • 很容易理解,形象直观;
      • 表示更方便,只需要3个值(分别对应x、y、z轴的旋转角度);但按我的理解,它还是转换到了3个3*3的矩阵做变换,效率不如四元数;
    • 缺点:
      • 之前提到过这种方法是要按照一个固定的坐标轴的顺序旋转的,因此不同的顺序会造成不同的结果;
      • 会造成万向节锁(Gimbal Lock)的现象。这种现象的发生就是由于上述固定坐标轴旋转顺序造成的。理论上,欧拉旋转可以靠这种顺序让一个物体指到任何一个想要的方向,但如果在旋转中不幸让某些坐标轴重合了就会发生万向节锁,这时就会丢失一个方向上的旋转能力,也就是说在这种状态下我们无论怎么旋转(当然还是要原先的顺序)都不可能得到某些想要的旋转效果,除非我们打破原先的旋转顺序或者同时旋转3个坐标轴。这里有个视频可以直观的理解下;
      • 由于万向节锁的存在,欧拉旋转无法实现球面平滑插值;

  • 四元数旋转
    • 优点:
      • 可以避免万向节锁现象;
      • 只需要一个4维的四元数就可以执行绕任意过原点的向量的旋转,方便快捷,在某些实现下比旋转矩阵效率更高;
      • 可以提供平滑插值;
    • 缺点:
      • 比欧拉旋转稍微复杂了一点点,因为多了一个维度;
      • 理解更困难,不直观;
 
 

四元数和欧拉角

 
 

基础知识

 
 
前面说过,一个四元数可以表示为q = w + xi + yj + zk,现在就来回答这样一个简单的式子是怎么和三维旋转结合在一起的。为了方便,我们下面使用q = ((x, y, z),w) = (v, w),其中v是向量,w是实数,这样的式子来表示一个四元数。
 
我们先来看问题的答案。我们可以使用一个四元数q=((x,y,z)sinθ2, cosθ2) 来执行一个旋转。具体来说,如果我们想要把空间的一个点P绕着单位向量轴u = (x, y, z)表示的旋转轴旋转θ角度,我们首先把点P扩展到四元数空间,即四元数p = (P, 0)。那么,旋转后新的点对应的四元数(当然这个计算而得的四元数的实部为0,虚部系数就是新的坐标)为:

p=qpq1
 
其中,q=(cosθ2, (x,y,z)sinθ2) ,q1=qN(q),由于u是单位向量,因此
N(q)=1,即q1=q。右边表达式包含了四元数乘法。相关的定义如下: