美文网首页
四元数的理解(简单说就是旋转轴加旋转角)

四元数的理解(简单说就是旋转轴加旋转角)

作者: 送分童子笑嘻嘻 | 来源:发表于2019-11-08 16:08 被阅读0次

四元数介绍

旋转,应该是三种坐标变换——缩放、旋转和平移,中最复杂的一种了。大家应该都听过,有一种旋转的表示方法叫四元数。按照我们的习惯,我们更加熟悉的是另外两种旋转的表示方法——矩阵旋转和欧拉旋转。矩阵旋转使用了一个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′=qpq−1

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

  • 四元数乘法:q1q2=(v1→×v2→+w1v2→+w2v1→,w1w2−v1→⋅v2→)

  • 共轭四元数:q∗=(−v⃗ ,w)

  • 四元数的模:N(q) = √(x^2 + y^2 + z^2 +w^2),即四元数到原点的距离

  • 四元数的逆:q−1=q∗N(q)

它的证明这里不再赘述,有兴趣的可以参见这篇文章。主要思想是构建了一个辅助向量k,它是将p绕旋转轴旋转θ/2得到的。证明过程尝试证明wk∗=kv∗,以此证明w与v、k在同一平面内,且与v夹角为θ。

我们举个最简单的例子:把点P(1, 0, 1)绕旋转轴u = (0, 1, 0)旋转90°,求旋转后的顶点坐标。首先将P扩充到四元数,即p = (P, 0)。而q = (u*sin45°, cos45°)。求p′=qpq−1的值。建议大家一定要在纸上计算一边,这样才能加深印象,连笔都懒得动的人还是不要往下看了。最后的结果p` = ((1, 0, -1), 0),即旋转后的顶点位置是(1, 0, -1)。

如果想要得到复合旋转,只需类似复合矩阵那样左乘新的四元数,再进行运算即可。

我们来总结下四元数旋转的几个需要注意的地方:

  • 用于旋转的四元数,每个分量的范围都在(-1,1);
  • 每一次旋转实际上需要两个四元数的参与,即q和q*;
  • 所有用于旋转的四元数都是单位四元数,即它们的模是1;

下面是几点建议:

  • 实际上,在Unity里即便你不知道上述公式和变换也丝毫不妨碍我们使用四元数,但是有一点要提醒你,除非你对四元数非常了解,那么不要直接对它们进行赋值。
  • 如果你不想知道原理,只想在Unity里找到对应的函数来进行四元数变换,那么你可以使用这两个函数:Quaternion.EulerQuaternion.eulerAngles。它们基本可以满足绝大多数的四元数旋转变换。

和其他类型的转换

首先是轴角到四元数:

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

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

这个公式的推导过程上面已经给出。

欧拉角到四元数:

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

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)

它的证明过程可以依靠轴角到四元数的公式进行推导。

其他参考链接:

  1. Euler to Quaternion
  2. Quaternion To Euler
  3. AngleAxis to Quaternion
  4. Quaternion to AngleAxis

四元数的插值

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

设t是一个在0到1之间的变量。我们想要基于t求Q1到Q2之间插值后四元数Q。它的公式是:

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

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

四元数的创建

在了解了上述知识后,我们就不需要那么惧怕四元数了,实际上它和矩阵类似,不同的只是它的表示方式以及运算方式。那么在Unity里如何利用四元数进行旋转呢?Unity里提供了非常多的方式来创建一个四元数。例如Quaternion.AngleAxis(float angle, Vector3 axis),它可以返回一个绕轴线axis旋转angle角度的四元数变换。我们可以一个Vector3和它进行左乘,就将得到旋转后的Vector3。在Unity里只需要用一个“ * ”操作符就可以进行四元数对向量的变换操作,相当于我们上述讲到的p′=qpq−1操作。如果我们想要进行多个旋转变换,只需要左乘其他四元数变换即可。例如下面这样:

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

尽管欧拉角更容易我们理解,但四元数比欧拉角要强大很多。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;

关于Quaternion的其他函数,后面再补充吧,原理类似~

相关文章

  • 四元数的理解(简单说就是旋转轴加旋转角)

    四元数介绍 旋转,应该是三种坐标变换——缩放、旋转和平移,中最复杂的一种了。大家应该都听过,有一种旋转的表示方法叫...

  • [摘要]四元数

    《3D游戏编程大师技巧》 上册 4.10章节 1.四元数的思想来源于复数 1.5 用四元数表示旋转轴和旋转角度 2...

  • Vuex的使用详解及理解

    一、vuex的理解 vuex简单说就是全局状态管理的,项目中常常需要有几个参数所有组件都要用,或者同级组件之间的数...

  • 车旋

    又是半夜了啊,放下车刀不知道干嘛了……那就给各位小伙伴简单说一点关于车旋……加油! 像这种就是属于车旋里轴车削的一...

  • 吴博士说理解数:算术好为什么数学还是差?

    知道运算远远不够,理解操作才是正解 一, 什么是运算?我们对运算的理解的误区 1,被误导的运算概念 数与数之间的加...

  • 简就是加,佳就是减

    简单线条,增加无限乐趣 美好生活,减少无谓负重 简佳生活,你我都值得拥有的幸福生活

  • 欧拉角、旋转向量和旋转矩阵的相互转换

    欧拉角转旋转矩阵 对于两个三维点 ,,由点经过旋转矩阵旋转到,则有: 任何一个旋转可以表示为依次绕着三个旋转轴旋三...

  • cheat和cheat on

    cheat简单说就是骗,但是伴侣搞小三的那种骗一定要加on: If someonecheats ontheir h...

  • 什么是福利抵扣

    简单说,福利抵扣就是蚂蚁给的红包,买10000元,抵扣25元。少掏25元。 上周五,加10000再减一万,等于没加...

  • 解剖列车第二十四讲

    前臂 肱二头肌短头和旋后肌都与桡骨相连接。由于前臂的旋前圆肌与旋后肌一起控制桡骨及拇指的旋转角度,所以我们习惯将其...

网友评论

      本文标题:四元数的理解(简单说就是旋转轴加旋转角)

      本文链接:https://www.haomeiwen.com/subject/zixwbctx.html