type
status
date
slug
summary
tags
category
icon
password

二维旋转矩阵

notion image
考虑两个向量,设旋转矩阵为,就需要满足:
因此可以得出,旋转矩阵是一种正交矩阵,满足:
并且满足:
为什么旋转矩阵的行列式为1?这是因为行列式本质是一种缩放因子,而旋转矩阵是一种变换坐标基的操作,所以也就是相当于旋转了坐标系,因此并没有发生缩放,所以值就是1。
另外,任何旋转矩阵都可以写成反对称矩阵A的指数:
反对称矩阵是一种转置矩阵和自身加法逆元相等的矩阵,简单来讲:
维空间内,上述结论仍然成立,这里不展开证明了(非常简单)
那具体在二维情况下旋转矩阵的值是多少呢?
二维情况下,旋转矩阵是一种关于旋转角度的函数(矩阵是可以定义为函数的,类似于透视函数):
证明如下:
notion image
假设从旋转到
从而推出:
写成线性变换的形式:
这就是二维旋转矩阵了,可以验证这个矩阵满足行列式为1.

三维旋转矩阵

三维旋转的复杂度会大大提高,主要是需要确定旋转轴。在二维上的旋转,只有绕z轴旋转(这里暂时不引入OpenGL的标架)的情况。但在三维,会有饶x、y、z轴旋转的情况。其实推导很简单,就是类似于二维旋转。
并且,三维旋转可以细分为旋转矩阵表示、欧拉角表示和四元数表示。

旋转矩阵表示

如果用旋转矩阵表示,需要分三种情况:饶x、y、z轴旋转的情况

欧拉角

如果用欧拉角表示,则需要定义三个欧拉角roll()、pitch()和yaw():
notion image
在三维情况下旋转可以用欧拉角表示。可分为动态欧拉角和静态欧拉角,两者均有万向节死锁问题。
欧拉角的定义基于旋转矩阵,它规定了物体的旋转次序只能有xyz的组合,即:xyz,xzy,yzx,yxz,zxy,zyx。这里举的例子是xyz。

静态欧拉角

静态欧拉角是根据世界坐标系的三个坐标轴xyz为基准进行旋转的,这三个坐标轴是不会变化的,始终是相互正交的,因此可以这样描述静态欧拉角:
计算得出:
一个有趣的数学现象,所有静态欧拉角的旋转矩阵,如果我们把矩阵的列单独拿出来看,可以发现矩阵的三个列分别对应了旋转之后的xyz轴分别在原本的xyz轴上的映射的分量。

万向节死锁

那为什么静态欧拉角会发生万向节死锁呢?坐标轴不是固定的吗?按理来说不应该出现自由度消失的情况。
其实我们一直都理解错了。欧拉角一个重要的概念就是,他每次的旋转变换都是以最初的姿态为初始状态变换的。我们从数学上和本质上去理解为什么会出现万向节死锁。
  • 数学
假设先沿着x轴旋转,然后沿着y旋转90度,最后绕z轴旋转,其欧拉角用旋转矩阵表达为:
这里比较直观的发现,最后的结果不包括了,这说明我旋转的情况和z轴无关,我仅仅通过x和y就能得到这样的结果。
  • 本质
欧拉角一个重要的概念就是,他是一个完整的变换。也就是每次变换,都要经过的乘法操作。什么意思呢?假如初始状态顶点坐标为,三个欧拉角为,我们要旋转到,那么就需要一个个操作,操作次序也就是:
可以发现被变换对象一直都是,说明不是在原有的基础位姿上变换的!
然后旋转到,也是同样的道理:
然后我们会发现每一个操作,都要先重新绕x轴旋转一次。虽然很冗余,但这是欧拉角旋转的定义。并且这也间接的告诉我们接下来的关键问题。
旋转到,操作次序:
看出来了?其实不是在你原有的欧拉角基础变换后的位置计算旋转,他要重新通过你最初始的姿态计算一遍。这个时候我们发现,假设,我们是在y调整之前,先调整的x旋转。也就是当y的角度还没到90度的时候,先调整的x。这和我们预期不符合,最终姿态看样子像是绕着z轴旋转了(因为经过y轴旋转90度之后的z轴和原来的x轴重合了)。这就是万向节死锁。
操作次序只是为了方便理解,让你知道欧拉角旋转始终是从初始姿态计算的,实际上程序直接计算最后一步。
下面是两个简单的解释:
简单来说,你以为旋转的结果是:X(10)Y(90)X(10)
实际上的游戏引擎计算的结果却是:
X(10)X(10)Y(90)
或者:
X(20)Y(10)
(这里的XYZ不是R_XR_YR_Z,只是表达一下直觉上的感受)
你想要的顺序:X1→Y→Z→X2 实际顺序:X1→X2→Y→Z 欧拉角本身不是问题,用欧拉角这个状态表示方式去表示了过程才导致了问题

动态欧拉角

动态欧拉角是根据自身物体的坐标轴为基准实现的旋转。可以用陀螺仪表示:
notion image
陀螺仪的三个环表示三个轴,他们不是始终固定的,根据物体的姿态调整,这就意味着存在两个环可能会重叠(平行)。另外外环会带动内环旋转,这与旋转次序是类似的。
notion image
在随着物体转动的坐标系下描述该问题非常方便。正如上面的石雕所示,我们取y,x,z的顺序依次绕轴旋转:
  • 首先是绕y轴旋转任意角度,可以认为是原地转圈
  • 接着绕着x轴旋转 90 度或者 -90 度,变成躺平或者俯瞰的姿势
  • 这时候z轴就和最初的y轴重合了
我们称丢失了一个自由度。这种视角看物体的旋转十分便于我们想象,但是比较难用数学方式表达,因为旋转轴是变化的。

动态欧拉角与静态欧拉角互相转换(代数意义上)

接下来的问题,如何转换动态欧拉角的旋转公式?可以根据静态欧拉角转换出来。
设动态欧拉角绕自身旋转为,假设是按照x→y→z旋转的,那么就有:
即绕自身x转动,等价于绕世界x轴转动;绕y轴转动,得先撤销之前x的转动,然后绕世界y轴变换,再应用之前x的转动;绕z轴转动也是同理,先撤销y然后撤销x,应用绕世界z轴变换,再应用xy。
然后就能得到:
所以,动态欧拉角变换和静态欧拉角变换是相互反过来的!也就是自身旋转xyz,相当于绕世界转zyx。
因为静态欧拉角有万向节死锁,因为等式成立,所以动态欧拉角也有万向节死锁问题。

绕任意轴旋转矩阵(Rodrigues旋转表达 - 罗德里格旋转)

轴的方向向量为,满足(单位向量),绕旋转轴旋转的向量为,旋转后的向量为,逆时针(绕旋转轴)的旋转角度为。由旋转的模长不变性知道
分解为方向(垂直于和平行于),不难得到如下关系:
构建一个新的标架,将该问题转换为在标架的旋转问题。我们假设空间是右手坐标系,那么规定并计算可得到标架
考虑到:
绕旋转轴逆时针旋转得到的向量,将其分别分解为(其中平面,有上,有)。
由几何关系,可以得到:
代入,可以得到旋转后向量的垂直分量表达式:
因此旋转后的向量:
整理得到:
这是Rodrigues旋转的向量表示。为了得到Rodrigues旋转的矩阵表示,我们做如下的操作。
,为了求解矩阵元,我们可以采用特殊值的方法,令,且:
先计算得到:
于是:
同理,令,能够得到最终的旋转矩阵:

四元数

四元数由两部分组成:一个向量以及一个旋转角度。几何意义是表示以这个向量为轴所旋转的角度度数,如下图所示,一个四元数由向量v和标量s组成,表示以向量v为轴,旋转s角度;另外一套符号系统则是用θ表示旋转角度和u来表示旋转轴。这两个表示都是等价的:
notion image
如果我们将向量u/v的xyz三个分量拆开来写,就可以得到四个标量:这就是四元数的名字的由来:
notion image
有些地方喜欢将四元数写成:
本质上都是一样的,ijk在这里就是用来表示旋转的轴。
四元数加法很少用,只有在后面的插值才会有一定的使用。
四元数乘法代表了旋转顺序,按照顺序旋转进行前乘,例如如果先进行q1,再进行q2,那么总的旋转q就是:

为什么四元数可以解决万向节死锁

欧拉旋转的本质是将绕任意轴旋转最终分解为绕x,y,z轴的旋转,才会导致万向节死锁。而用四元数旋转可直接表示为绕任意轴旋转。通过四元数的表示方法就可以看出

四元数插值

四元数插值的方式相对比较特殊,我们不能直接简单的线性插值,按照比例将两个单位四元数加在一起:
这样的结果就是导致q(t)的长度不再是1,结果会在这条虚线上移动:
notion image
哪怕我们重新再把它的长度变回1,这个运动也不是随着角度而平滑运动的。所以我们需要用另一个方式进行插值,我们设下面的公式:
我们现在就是要接出来,此时我们将沿着两个向量的方向进行分解,设是两个四元数之间的夹角:
notion image
根据相似三角形:
由于所有四元数都是单位四元数,长度都是1,所以:
也就是说四元数完整插值的公式是:
 
傅里叶变换基于物理的渲染
  • Twikoo