计算机图形学中的四元数(Quaternions)

本文介绍了计算机图形学中四元数的使用,旨在解决欧拉角旋转带来的万向节死锁和插值问题。首先阐述了欧拉角的基本概念和存在的问题,接着详细探讨了四元数的定义、乘法运算及其与三维旋转的关系。通过复数作为铺垫,解释了四元数如何作为一种高效表示和操作旋转的方法,特别是在解决路径偏移和摄像机抖动问题上起到重要作用。
摘要由CSDN通过智能技术生成

计算机图形学中的四元数(Quaternions)

前言

最近上课,又学到了四元数部分,毕竟三维空间生物理解四维事物确实太抽象了,于是下定决心写一篇总结,分享一下自己的理解,同时也是巩固一下自己对于四元数的认识。

欧拉角

欧拉角相对来说是比较容易理解的一种描述旋转的方式。学术地说,欧拉角是用来唯一地确定定点转动刚体位置的三个一组独立角参量,由章动角θ、进动角ψ和自转角φ组成,为L.欧拉首先提出(百度百科)。说人话就是,欧拉角是将三维空间中的旋转,分解为分别绕互相垂直的三个坐标轴依次进行的三次旋转(旋转顺序是不唯一的,但是显然旋转顺序会影响最终旋转的结果,一般情况下可以是x->y->z,但是unity中似乎是z->x->y)。绕这三个轴的旋转分别是pitch(绕x轴),yaw(绕y轴),roll(绕z轴),注意,这三个轴都是local的,即沿某轴发生旋转后,其它轴的轴向可能会发生改变。之所以能够将三维旋转这样分解,最主要的原因是,三次旋转相互独立,互不干扰(死锁情况除外),虽然旋转轴每次旋转都在发生着变化,但是旋转的效果不受影响。
在这里插入图片描述

欧拉角的万向节死锁(Gimbal Lock)与插值问题

  • 万向节死锁的直观解释
    首先,再次强调一下,欧拉角之所以能够通过三次分旋转来表示空间中任意旋转,是因为三次旋转的旋转轴有差异性。好比线性代数中,构成一个三维空间需要的是三个线性无关的向量,如果三个基向量中有两个线性相关了,就不能形成三维空间,而是一个二维平面。旋转中也是如此,若旋转过程中有两个旋转轴重合了,那么旋转相当于丧失了一个方向的自由度,显然就不能合适地表达所有旋转了。
    用这个非常经典的陀螺仪圆环来呈现:
    在这里插入图片描述

初始状态时,用三个圆环代表三个正交轴向的旋转,此时,沿任何轴转动,中间的转子都能够保持稳定轴。但是,当沿红色轴转动90°之后,会变成下图的情况:

在这里插入图片描述
此时,再沿蓝色轴转动,转子已经无法保持平衡。说明转子丧失了蓝色轴向的自由度。这时,就发生了万向节死锁。一个更生动形象的例子是:拿起自己的手机,假设z轴垂直于手机屏幕,x轴为手机短边,y轴为手机长边,原点为手机中心。现在,将手机平放在桌面上,使旋转顺序为z->y->x,先将手机绕z轴旋转任意角度,随后绕y轴旋转90°,再绕x轴旋转任意角度,你会发现,手机的z轴永远是平的,手机丧失了一个方向的自由度。换句话说,手机永远也不会立起来了,就像是被锁在了桌面上,这个现象就称为万向节死锁。然而,如果绕y轴旋转的角度不等于90°,1°也好,89°也好,只要选择适当的绕x和z的角度,我们都可以使手机指向三维空间中的任何一个方向。

  • 万向节死锁的数学解释
    可以参考冯乐乐女神的这一篇文章
  • 欧拉角在应用中的插值问题
    在游戏中,当角色旋转的动画触发时,角色就会做一系列连续的旋转变换,每一个变换都要用一组欧拉角来表示,但是不可能把每一帧每个方位的欧拉角都存起来传过去赋值,所以实际操作中,动画师制作关键帧动画,规定了一系列的关键帧并且指定每个关键帧时角色的旋转(欧拉角),然后工程师使用算法对关键帧之间角色的旋转进行插值,使角色的动作看起来连贯。
    以xyz旋转为例,当|pitch|不等于90°时,就不会出现万向节死锁现象,这时插值后的一系列欧拉角会比较正常,基本可以刻画出我们期望的路径,但是,当某个关键帧的pitch为90°时(动画师制作动画并不会考虑这些),就会发生万向节死锁。以上面的手机为例,此时,我们的手机只能在水平面上旋转,那么如果下一个关键帧的旋转还是在水平面,那么一切正常,但是若动画师k的下一个关键帧的旋转是手机立起来的方位,会发生什么情况呢?
    我们期望这个旋转可以是一个直线插值过去,但是实际上,因为发生了万向节死锁,我们丧失了能使手机立起来的那个旋转轴,因此我们需要改变每个轴的旋转才能使得手机立起来,关键帧的欧拉角数值也会体现如此。这样子,插值会得到一条曲线旋转,看起来会十分的诡异,方便更直观地理解可以参考这个视频。也就是说会发生《3D数学基础:图形与游戏开发》中提到的“路径偏移”和“摄像机抖动”。

四元数

为了解决欧拉角旋转带来的上述不便,四元数开始被用来解决三维旋转的问题。

  • 复数
    在讨论四元数以及三维旋转之前,先从复数(Complex Number)以及2维旋转入手也许会好一些。对任意一个复数 z = a + b i z = a + bi z=a+bi , a 称为这个复数的实部(Real Part),b 称为这个复数的虚部(Imaginary Part)。 z = a + b i z = a + bi z=a+bi可以看作是{1,i}这个基的线性组合,所以也可以用向量来表示复数: z = [ a b ] z =\begin{bmatrix}a \\ b\end{bmatrix} z=[ab]可以用复平面上的一个点来表示该复数,横坐标为实部,纵坐标为虚部。
    在这里插入图片描述
    关于复数的一些基本定义和概念,这里将不再提及,这里稍微提一下复数的乘法与矩阵。如果有两个复数 z 1 = a + b i , z 2 = c + d i , z_1 = a + bi , z_2 = c + di, z1=a+bi,z2=c+di,可以计算他们的乘积如下: z 1 z 2 = ( a + b i ) ( c + d i ) = a c + a d i + b c i + b d i 2 = a c − b d + a d i + b c i = a c − b d + ( b c + a d ) i . \begin{aligned} z_1z_2 &= (a + bi)(c +di)\\&=ac + adi +bci + bdi^2\\&=ac-bd+adi+bci\\&=ac-bd+(bc+ad)i. \end{aligned} z1z2=(a+bi)(c+di)=ac+adi+bci+bdi2=acbd+adi+bci=acbd+(bc+ad)i.
    前面说过复数可以用向量表示,于是将上述 z 2 z_2 z2写成 [ c d ] \begin{bmatrix}c\\ d\end{bmatrix} [cd]的向量形式,于是可以很容易地发现,上述复数相乘的结果实际上也是一个矩阵与向量相乘的结果:
    z 1 z 2 = ( a + b i ) ( c + d i ) = a c − b d + ( b c + a d ) i = [ a − b b a ] [ c d ] . \begin{aligned} z_1z_2 &= (a + bi)(c +di)\\&=ac-bd+(bc+ad)i\\&=\begin{bmatrix}a & -b\\ b & a\end{bmatrix} \begin{bmatrix}c \\ d\end{bmatrix}. \end{aligned} z1z2=(a+bi)(c+di)=acbd+(bc+ad)i=[abba][cd].
    可以发现,复数相乘运算,与 [ a − b b a ] \begin{bmatrix}a & -b\\ b & a\end{bmatrix} [abba]这个矩阵代表的变换是等价的,那么复数与复数相乘代表的变换可以写作矩阵形式:
    z 1 z 2 = [ a − b b a ] [ c − d d c ] = [ a c − b d − ( b c + a d ) b c + a d a c − b d ] \begin{aligned} z_1z_2 &= \begin{bmatrix}a & -b\\ b & a\end{bmatrix} \begin{bmatrix}c & -d\\ d& c\end{bmatrix} \\&=\begin{bmatrix}ac-bd& -(bc+ad)\\ bc+ad& ac-bd\end{bmatrix} \end{aligned} z1z2=[abba][cddc]=[acbdbc+ad(bc+ad)acbd]
    且,复数乘法是满足交换律的,所以 z 1 z 2 与 z 2 z 1 z_1z_2与z_2z_1 z1z2z2z1是 等价的:
    z 2 z 1 = [ c − d d c ] [ a − b b a ] = [ a c − b d − ( b c + a d ) b c + a d a c − b d ] = z 1 z 2 \begin{aligned} z_2z_1 &= \begin{bmatrix}c & -d\\ d& c\end{bmatrix} \begin{bmatrix}a & -b\\ b & a\end{bmatrix} \\&=\begin{bmatrix}ac-bd& -(bc+ad)\\ bc+ad& ac-bd\end{bmatrix} \\&=z_1z_2 \end{aligned} z2z1=[cddc][abba]=[acbdbc+ad(bc+ad)acbd]=z1z2
    回到 z = a + b i z = a + bi z=a+bi对应的变换矩阵 [ a − b b a ] \begin{bmatrix}a & -b\\ b & a\end{bmatrix} [abba],这种变换代表什么呢?实际上如果对这个矩阵进行一些数学上的处理,就会发现:
    [ a − b b a ] = a 2 + b 2 [ a a 2 + b 2 − b a 2 + b 2 b a 2 + b 2 a a 2 + b 2 ] \begin{bmatrix}a & -b\\ b & a\end{bmatrix} = \sqrt{a^2 + b^2}\begin{bmatrix}\frac{a}{\sqrt{a^2 + b^2}} & \frac{-b}{\sqrt{a^2 + b^2}} \\\frac{b}{\sqrt{a^2 + b^2}} &\frac{a}{\sqrt{a^2 + b^2}} \end{bmatrix} [abba]=a2+b2 [a2+b2 aa2+b2 ba2+b2 ba2+b2 a]
    注意 a a 2 + b 2 \frac{a}{\sqrt{a^2 + b^2}} a2+b2 a实际上是复数 z z z的模长,有着下图的关系:
    在这里插入图片描述
    可以发现, a a 2 + b 2 = cos ⁡ θ , a a 2 + b 2 = sin ⁡ θ \frac{a}{\sqrt{a^2 + b^2}} = \cos\theta ,\frac{a}{\sqrt{a^2 + b^2}} = \sin\theta a2+b2
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值