Advertisement

三维旋转矩阵_三维旋转:欧拉角、四元数、旋转矩阵、轴角之间的转换

阅读量:

0 引言

来鹅厂实习了一段时间,因为没有什么特别紧急的需求(hahahahaha),所以主要花在了学习和捣鼓一些小工具上。有一个小需求是要实现鼠标拖动球体的转动,然后发现我不再能只用欧拉角来糊弄过去了。然后又发现,网上大部分资料的采用的欧拉角顺规都是xyz,然后我基于D3D11的辣鸡框架用了zxy,公式不太能直接套用,于是摸了两三天鱼,整理了一下几种三维旋转表示(欧拉角,四元数,旋转矩阵,轴角)与他们之间的相互转换的资料,并且加入了自己的一些推导,给出这些转换公式的推导思路和细节 ,这样子如果各位想使用其他欧拉角顺规和定义的时候,自己动手算一算就好了。

至于这几种三维旋转的表示形式随手百度Google都可以看到很多科普文的,这里着重说一下他们之间的转换 的细节吧(不少公式和推导,预警一波,如果有错误请指出~)
85089c4a0d2f2db8b42b6b58a1f9279d.png 图:下文介绍的几种转换路径


1 欧拉角(Euler Angle)与旋转矩阵(Rotation Matrix)

1.1 欧拉角 ---- > 旋转矩阵

D3D和OpenGL不同,用的坐标系是Y轴竖直向上的左手系,所以欧拉角的顺规是跟广大blog、OpenGL不一样的,那么博客上、甚至维基百科[2]上的各种基于右手系xyz顺规(分别对应roll, pitch,yaw)的看起来就不太能随随便便直接用了。

首先欧拉角旋转序列(Euler Angle Rotational Sequence)一共有12种顺规,6种绕三条轴的旋转(也叫Tait-Bryan Angle ,XYZ,XZY,YXZ,YZX,ZXY,ZYX),另外6种只绕两条轴的旋转(也叫Proper Euler Angle ,XYX,YXY,XZX,ZXZ,YZY,ZYZ)。如果相邻两次旋转是绕同一条轴,例如XXY,那么其实可以坍缩成XY。那么只绕一条轴旋转就根本不够自由度就不需要说了。也就是说,一共有12种基础旋转的组合顺序,它们可以旋转出三维的所有旋转状态。所以一共是12种旋转顺规(可以表示所有旋转的集合),DirectXMath库采用的是ZXY顺规 ,分别对应着Z-Roll,X-Pitch,Y-Yaw。
ca97ec1d9ba90c6e9ea2e8f11ec130bf.png 图:欧拉旋转与Yaw-Pitch-Roll的直观意义(网图魔改)

注意:那么下文我们都采用ZXY顺规来推导公式!采用列主向量(column major)!(但是注意DirectXMath API生成的矩阵其实是行主向量(row major)的)

参考一下维基百科的

[3]Euler Angle

Euler angles - Wikipediaen.wikipedia.org4457b5c4fb2f62ee6db54cbfb3120cd3.png

[4]Rotation Matrix

Rotation matrix - Wikipediaen.wikipedia.org9d24d3e837ef31abc88a7dda7e0cc97f.png

可以知道,欧拉角构造旋转矩阵就直接把三个Elemental Rotation Matrix乘在一起就好了(LaTeX扣得真累orz):
8807c37c-1e3f-eb11-8da9-e4434bdf6706.png

其中:
8907c37c-1e3f-eb11-8da9-e4434bdf6706.png

上面的欧拉角--->矩阵的结果与维基百科Euler Angles[3] 8b07c37c-1e3f-eb11-8da9-e4434bdf6706.png 给出的结果一致,那应该稳了:
cd9ef22f931c890cdd2c5091e880a77a.png 图:其实可以不用自己推的,维基百科把12种顺规乘出来的矩阵都写出来了

.

1.2 旋转矩阵---- > 欧拉角

参考一篇NASA的关于姿态描述的技术报告[1]的Appendix-A6和[5],我们可以用旋转矩阵元素的相乘、相除、反三角函数等操作去“凑”出欧拉角 。[5]给出了从XYZ顺规提取欧拉角的方法、步骤、思路,[1]则给出了全部12种顺规的欧拉角提取公式,但是没有给一些细节注意事项。所以总结一下,根据[1]、[5]、[7]《Real Time Rendering 3rd Edition》4.2.2和自己的推导,从ZXY顺规旋转矩阵提取欧拉角的公式是([1]原文下标似乎有点小问题):

  • Y axis yaw angle:
    8e07c37c-1e3f-eb11-8da9-e4434bdf6706.png

  • X axis pitch angle:
    9207c37c-1e3f-eb11-8da9-e4434bdf6706.png

  • Z axis roll angle:
    9407c37c-1e3f-eb11-8da9-e4434bdf6706.png

.

注意到一点,注意到矩阵的每一个元素都是pitch angle 9607c37c-1e3f-eb11-8da9-e4434bdf6706.png 的函数…所以当 9907c37c-1e3f-eb11-8da9-e4434bdf6706.png9b07c37c-1e3f-eb11-8da9-e4434bdf6706.png 的时候,这时候其他的欧拉角提取表达式就凉凉了(分子分母都是0, arctan和atan2都没有意义了)….其实pitch angle 9e07c37c-1e3f-eb11-8da9-e4434bdf6706.png 恰好就是Gimbal Lock的位置。在Gimbal Lock的时候,旋转矩阵会退化为:
a107c37c-1e3f-eb11-8da9-e4434bdf6706.png

.

那么要进一步处理万向节死锁的corner case就需要分两种情况:
a407c37c-1e3f-eb11-8da9-e4434bdf6706.png
a607c37c-1e3f-eb11-8da9-e4434bdf6706.png

其中要给a807c37c-1e3f-eb11-8da9-e4434bdf6706.png或者 aa07c37c-1e3f-eb11-8da9-e4434bdf6706.png其中一个欧拉角赋值,另外一个就按等式计算出来。

.
ad07c37c-1e3f-eb11-8da9-e4434bdf6706.png
af07c37c-1e3f-eb11-8da9-e4434bdf6706.png

同样的,要给a807c37c-1e3f-eb11-8da9-e4434bdf6706.png或者 aa07c37c-1e3f-eb11-8da9-e4434bdf6706.png其中一个欧拉角赋值,另外一个就按等式计算出来。

.

从旋转矩阵提取欧拉角的公式跟欧拉角顺规的选取有关,因为旋转矩阵的元素会略有不同,但是思路都是一样的,就是根据旋转矩阵的解析表达式+反三角函数凑出来 23333。


2 四元数(Quaternion)与旋转矩阵

2.1 四元数---- >旋转矩阵

众所周知的是,欧拉旋转是有万向节死锁(Gimbal Lock)的问题的。幸好我们有四元数(Quaternion)这种数学工具可以避免这个情况。一般来说,我们都会用单位四元数 b707c37c-1e3f-eb11-8da9-e4434bdf6706.png 来表示旋转,其中 b907c37c-1e3f-eb11-8da9-e4434bdf6706.png 。那么给定一个单位四元数,可以构造旋转矩阵(column major)[1][4][8][14][15]:
bc07c37c-1e3f-eb11-8da9-e4434bdf6706.png

这个四元数构造的大概思路就是把四元数的旋转操作写成矩阵形式(注:给定一个用于旋转的单位四元数 b707c37c-1e3f-eb11-8da9-e4434bdf6706.png 和被旋转的三维向量 c207c37c-1e3f-eb11-8da9-e4434bdf6706.png ,那么要直接用四元数旋转这个向量,则我们首先要构造一个纯四元数 c707c37c-1e3f-eb11-8da9-e4434bdf6706.png ,设旋转后的向量为 cd07c37c-1e3f-eb11-8da9-e4434bdf6706.png ,旋转后的向量构造的纯四元数为 cf07c37c-1e3f-eb11-8da9-e4434bdf6706.png ,那么 d307c37c-1e3f-eb11-8da9-e4434bdf6706.png )。因为是用四元数来构造矩阵的,所以这个矩阵构造公式就没有欧拉角顺规的说法了。

.

2.2 旋转矩阵---- >四元数

那第一步肯定是判断3x3矩阵是一个正交矩阵啦(满足 d607c37c-1e3f-eb11-8da9-e4434bdf6706.png )。那么如果这个矩阵已经是一个合法的旋转矩阵了,要从旋转矩阵里提取四元数,也是可以像提取欧拉角那样,用参数化过的矩阵的表达式凑出来 。参考[8]《Real Time Rendering 3rd edition》Chapter4的思路,我们观察一下用四元数分量进行参数化的矩阵dc07c37c-1e3f-eb11-8da9-e4434bdf6706.png ,然后经过一顿操作,我们发现:
df07c37c-1e3f-eb11-8da9-e4434bdf6706.png

于是我们再凑出个实分量e307c37c-1e3f-eb11-8da9-e4434bdf6706.png ,就可以把四元数四个分量都用矩阵元素表示出来了。于是我们又机智地发现了一个等式:
e507c37c-1e3f-eb11-8da9-e4434bdf6706.png

其中 e907c37c-1e3f-eb11-8da9-e4434bdf6706.png 是矩阵 ef07c37c-1e3f-eb11-8da9-e4434bdf6706.png 的迹(trace),也就是矩阵对角元素的和。因为这里用的是3x3矩阵,跟其他资料里面的表示有一点不同。所以我们可以把四元数的四个分量都用矩阵元素凑出来了:
f107c37c-1e3f-eb11-8da9-e4434bdf6706.png

有一点《Real Time Rendering》提到的, e307c37c-1e3f-eb11-8da9-e4434bdf6706.png 绝对值比较小的时候,可能会出现数值不稳定的情况,那么想要数值稳定的话就得用一种不用除法的方式来凑,在这不展开了,可以看一下RTR 2333。


3 欧拉角与四元数

3.1 欧拉角---- >四元数

首先提一下四元数的乘积:
f407c37c-1e3f-eb11-8da9-e4434bdf6706.png
f607c37c-1e3f-eb11-8da9-e4434bdf6706.png

参考维基百科[2]的思路,欧拉角构造四元数,跟欧拉角构造旋转矩阵一样,就是把三个基础旋转Elemental Rotation组合在一起。

Conversion between quaternions and Euler anglesen.wikipedia.orgdc24c00da5e1b68712a1efdd23db3160.png

那么用于旋转的四元数 fe07c37c-1e3f-eb11-8da9-e4434bdf6706.png 的表达式是:
0008c37c-1e3f-eb11-8da9-e4434bdf6706.png

这个我自己推导的结果跟[1]NASA Technical Report的Appendix A给出的结果对比过了

https://ntrs.nasa.gov/archive/nasa/casi.ntrs.nasa.gov/19770019231.pdfntrs.nasa.gov

([1]中四元数记号是 0508c37c-1e3f-eb11-8da9-e4434bdf6706.png ),看起来没什么问题。

.

3.2 四元数---- >欧拉角

本来我以为,从四元数提取欧拉角的思路可以跟旋转矩阵提取欧拉角类似,也是用四元数的元素运算和反三角函数凑出公式来。后来我发现这简直就是一个极其硬核的任务,展开之后每一项都是六次多项式,画面有一丢暴力且少儿不宜,直接强行凑的话画风大概是这样:
0908c37c-1e3f-eb11-8da9-e4434bdf6706.png
0e08c37c-1e3f-eb11-8da9-e4434bdf6706.png
1008c37c-1e3f-eb11-8da9-e4434bdf6706.png

这个结果跟欧拉角参数化的旋转矩阵的 1108c37c-1e3f-eb11-8da9-e4434bdf6706.png 的表达式是吻合的。但这还只是最好凑的那一个,惹不起惹不起。所以舒服的思路还是四元数-- >旋转矩阵-->欧拉角,想一步到位的话,把四元数分量参数化的旋转矩阵、欧拉角参数化的旋转矩阵结合在一起,参考下旋转矩阵转欧拉角的方法,替换下元素就完事了。这里就不把公式展开了,因为四元数直接转欧拉角 跟 旋转矩阵转欧拉角一样,依旧是要处理gimbal lock的corner case,还是那么麻烦,所以这里先鸽了23333


4 轴-角(Axis-Angle)

4.1 轴角---- >四元数

轴-角(Axis-Angle)顾名思义就是绕某条单位轴旋转一定角度,从这个意义上看,它构造四元数是非常舒服的,毕竟直观的几何意义有一点点类似,绕单位轴 1508c37c-1e3f-eb11-8da9-e4434bdf6706.png 旋转 1908c37c-1e3f-eb11-8da9-e4434bdf6706.png 的四元数是:
1d08c37c-1e3f-eb11-8da9-e4434bdf6706.png

.

4.2 轴角---- >旋转矩阵

Axis Angle转Rotation Matrix可以从[9]罗德里格斯旋转公式Rodrigues Rotation Formula开始推导。

https://en.wikipedia.org/wiki/Rodrigues'_rotation_formulaen.wikipedia.org![d15f725c3840f2055c3ee1480761b6ec.png](https://ad.itadn.com/c/weblog/blog-img/images/2025-05-02/dEyY9o0SjOR57F8shqmap6CePVB2.png)

Rodrigues' rotation formula

Rodrigues' rotation formulaen.wikipedia.orgd15f725c3840f2055c3ee1480761b6ec.png

c207c37c-1e3f-eb11-8da9-e4434bdf6706.png 是我们要旋转的单位向量,旋转轴为 2a08c37c-1e3f-eb11-8da9-e4434bdf6706.pngc207c37c-1e3f-eb11-8da9-e4434bdf6706.png2a08c37c-1e3f-eb11-8da9-e4434bdf6706.png 旋转角度 1908c37c-1e3f-eb11-8da9-e4434bdf6706.png ,那么旋转后的向量为:
3a08c37c-1e3f-eb11-8da9-e4434bdf6706.png

这个公式的推导思路是这样子的,我们先对向量 c207c37c-1e3f-eb11-8da9-e4434bdf6706.png 进行正交分解,分解成投影到旋转轴 2a08c37c-1e3f-eb11-8da9-e4434bdf6706.png 的分量和垂直于 2a08c37c-1e3f-eb11-8da9-e4434bdf6706.png 的分量:
4308c37c-1e3f-eb11-8da9-e4434bdf6706.png

其中:
4608c37c-1e3f-eb11-8da9-e4434bdf6706.png
d3f096fa79562a3fb00bed8b4dd34461.png 图:魔性p图,假设k和v都在屏幕这个平面上吧

于是绕 2a08c37c-1e3f-eb11-8da9-e4434bdf6706.png 旋转向量 c207c37c-1e3f-eb11-8da9-e4434bdf6706.png 其实就是把上面正交投影后的向量分别旋转之后再加起来 。那么很明显的,投影到旋转轴上的部分 5008c37c-1e3f-eb11-8da9-e4434bdf6706.png 都跟旋转轴共享了,那么自然旋转之后的结果就没有变化了,于是我们只需要旋转和旋转轴垂直的部分 5408c37c-1e3f-eb11-8da9-e4434bdf6706.png 。那么这个5408c37c-1e3f-eb11-8da9-e4434bdf6706.png旋转后的表达式就是:
5708c37c-1e3f-eb11-8da9-e4434bdf6706.png

然后我们不按wikipedia里面坑爹的、不考虑下文的变形,自己推一波:
5808c37c-1e3f-eb11-8da9-e4434bdf6706.png

这里我们把旋转后向量的表达式变形得只剩下叉积(cross product),去掉点积(dot product)了 ,这样子我们才可以把这个绕轴旋转的表达式写成矩阵形式。怎么写呢?首先叉积可以写成矩阵形式:
5a08c37c-1e3f-eb11-8da9-e4434bdf6706.png

Cross product - Wikipediaen.wikipedia.org7405234a023764d53010fd468e3dae23.png

于是罗德里格斯旋转公式的变换就可以写成矩阵形式:
5f08c37c-1e3f-eb11-8da9-e4434bdf6706.png

展开之后就是:
6108c37c-1e3f-eb11-8da9-e4434bdf6706.png


罢工罢工!!LaTeX敲到我头皮发麻了!!

(不那么标准的)引用

[1]Henderson, D.M.. Euler angles, quaternions, and transformation matrices for space shuttle analysis[C]//NASA, Jun 09, 1977.

[2] https://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles#Euler_Angles_to_Quaternion_Conversion

[3] https://en.wikipedia.org/wiki/Euler_angles

[4] https://en.wikipedia.org/wiki/Rotation_matrix

[5] Slabaugh G G. Computing Euler angles from a rotation matrix[J]. 1999.

[6] Mike Day, Converting a Rotation Matrix to a Quaternion. https://d3cw3dd2w32x2b.cloudfront.net/wp-content/uploads/2015/01/matrix-to-quat.pdf

[7] Tomas K.M. , Eric H., Naty H.. Real Time Rendering 3rd Edition , p68-p69, 2008.

[8] Tomas K.M. , Eric H., Naty H.. Real Time Rendering 3rd Edition , p76-p77, 2008.

[9] https://en.wikipedia.org/wiki/Rodrigues'_rotation_formula

[10] https://en.wikipedia.org/wiki/Cross_product#Conversion_to_matrix_multiplication

[11] http://mathworld.wolfram.com/RodriguesRotationFormula.html

[12] https://zh.wikipedia.org/wiki/四元數

[13]

[14] Quaternion and Rotations, http://run.usc.edu/cs520-s12/quaternions/quaternions-cs520.pdf

[15] https://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation


往期精选

Unity3D游戏开发中100+效果的实现和源码大全 - 收藏起来肯定用得着

Shader学习应该如何切入?

喵的Unity游戏开发之路 - 从入门到精通的学习线路和全教程


声明:发布此文是出于传递更多知识以供交流学习之目的。若有来源标注错误或侵犯了您的合法权益 ,请作者持权属证明与我们联系,我们将及时更正、删除,谢谢。

作者:鸡哥

_原文:https://zhuanlan.zhihu.com/p/45404840_


More:【微信公众号】 u3dnotes
97336e2713b84173dc88cb912a50a460.png

全部评论 (0)

还没有任何评论哟~