彻底搞懂四元数

提要

旋转的表达方式有很多种,有欧拉角,旋转矩阵,轴角,四元素等等,今天要学习的就是游戏开发中最常用的四元素。

从欧拉角和轴向角到四元数

在讲四元素之前,我们先来看下简单的欧拉角和轴向角。

欧拉角使用最简单的x,y,z值来分别表示在x,y,z轴上的旋转角度,其取值为0-360(或者0-2pi),一般使用roll,pitch,yaw来表示这些分量的旋转值。需要注意的是,这里的旋转是针对世界坐标系说的,这意味着第一次的旋转不会影响第二、三次的转轴。

欧拉角容易出现的问题是 1)不易在任意方向的旋转轴插值; 2)万向节死锁;3)旋转的次序无法确定。

轴角用一个以单位矢量定义的旋转角,再加上一个标量定义的旋转角来表示旋转。通常的表示[x,y,z,theta],前面三个表示轴,最后一个表示角度。表示非常直观,也很紧凑。

轴角最大的一个局限就是不能进行简单的插值,此外,轴角形式的旋转不能直接施于点或矢量,必转换为矩阵或者四元素。

四元素感觉上就是轴角的进化,也是使用一个3维向量表示转轴和一个角度分量表示绕此转轴的旋转角度,即(x,y,z,w), 其中

w = cos(theta/2)
x  = ax * sin(theta/2)
y  = ay * sin(theta/2)
z  = az * sin(theta/2)

其中(ax,ay,az)表示轴的矢量,theta表示绕此轴的旋转角度。四元数中的每个数都是经过“处理”的轴和角,轴角描述的“四元组”并不是一个空间下的东西,首先(ax,ay,az)是一个3维坐标下的矢量,而theta则是级坐标下的角度,简单的将他们组合到一起并不能保证他们插值结果的稳定性,因为他们无法归一化,所以不能保证最终插值后得到的矢量长度(经过旋转变换后两点之间的距离)相等,而四元数在是在一个统一的4维空间中,方便归一化来插值,又能方便的得到轴、角这样用于3D图像的信息数据,所以用四元数再合适不过了。相比于矩阵,四元素也只要存储4个浮点数,优势很明显。

四元素的相关计算

乘法

给定两个四元数p和q,分别代表旋转P和Q,则乘积pq表示两个旋转的合成(即旋转了Q之后再旋转P),并不是用加法。四元数的乘法定义如下,利用简单的分配律就是了:

q1 * q2 =
(w1*w2 - x1*x2 - y1*y2 - z1*z2) +
(w1*x2 + x1*w2 + y1*z2 - z1*y2) i +
(w1*y2 - x1*z2 + y1*w2 + z1*x2) j +
(w1*z2 + x1*y2 - y1*x2 + z1*w2) k

由于q = w + x i + y j + z k中可以分为纯量w与向量x i + y j + z k,所以为了方便表示,将q表示为(S, V),其中S表示纯量w,V表示向量x i + y j + z k,所以四元数乘法又可以表示为:
q1 * q2 = (S1 + V1)*(S2 + V2) = S1*S2 - V1.V2 + V1XV2 + S1*V2 + S2*V1

求模

N(q) = |q| = x2 + y2 + z2 + w2

单位化

Normalize( q ) = q/ | q | = q / (x2 + y2 + z2 + w2)

求共轭

q*=(-x, -y, -z, w)


求逆

对于向量逆的定义, q-1 =q*/|q|2

对于单位四元素,分母为1,q-1 = q* =(-x, -y, -z, w)

用四元数旋转矢量

给定一个矢量v,再给定一个旋转的单位四元素q,让v旋转q。

首先将v改写成四元素的形式v = (x, y ,z, 0),  接下来要旋转v须用q前乘以矢量v,再后乘以q-1

v‘ = qvq-1

当然用后面乘以共轭的q也是一样的,因为都是单位四元素。

对于旋转多个四元数,比如 R=R1R2R3. 则

注意顺序。

四元数的线性插值和球面线性插值

四元素的可以方便地进行插值是四元素最大的优势。线性插值最为简单,效率也很高。给定两个旋转四元素qa和qb代表旋转A和旋转B,找到旋转A到旋转B之间的 t 的旋转:

注意这里的 t 实际上是是沿弦上走了t,而不是在球面上走t,这样就会导致当 t 以恒定速度改变时,角度的变化并非恒定.

为了解决这个问题,就出现了球面线性插值。给定四元素q和q,

其中theta是两个四元素的夹角,

四元数的各种转换

四元素转欧拉角

欧拉角转四元素

四元素转旋转矩阵

参考

游戏引擎架构 第四章

Computer Graphics: 四元數與旋轉 - http://openhome.cc/Gossip/ComputerGraphics/QuaternionsRotate.htm

Quaternion(四元数)和旋转以及Yaw, pitch, roll 的含义 - - http://www.wy182000.com/2012/07/17/quaternion%E5%9B%9B%E5%85%83%E6%95%B0%E5%92%8C%E6%97%8B%E8%BD%AC%E4%BB%A5%E5%8F%8Ayaw-pitch-roll-%E7%9A%84%E5%90%AB%E4%B9%89/

时间: 2024-10-10 23:41:01

彻底搞懂四元数的相关文章

彻底搞懂oracle的标量子查询

oracle标量子查询和自定义函数有时用起来比较方便,而且开发人员也经常使用,数据量小还无所谓,数据量大,往往存在性能问题. 以下测试帮助大家彻底搞懂标量子查询. SQL> create table a (id int,name varchar2(10)); Table created. SQL> create table b (id int,name varchar2(10)); Table created. SQL> insert into a values (1,'a1'); 1

猎豹MFC--使用向导快速进行MFC程序设计--不需要全部搞懂,只把重要的几个搞懂即可

新建MFC项目  单文档 文档视图: 如上,向导会为我们自动生成4个类. 每个类中有很多代码,不需压迫我们全部搞懂,我们只把重要的几个搞懂即可. 以前是在窗口中画显示要在视图中画: 所有的显示都是在视图类中: 在视图类属性中添加  paint消息: 记住要在视图对象上添加消息而不是像以前那样在窗口对象上添加. 在视图类上再添加  鼠标单击消息: 来自为知笔记(Wiz)

分分搞懂c#中的委托

分分搞懂c#中的委托: 不说废话,不来虚的概念,不管代码是否有意义,看我的优化之路,你会理解委托了: 源代码1 public class test { //我们不管代码是否有意义,我们直接看代码重构和一步步优化的过程 int flage = 1; public void show(int a) { if (flage == 1) { do1(a); } else if (flage == 2) { do2(a); } else if (flage == 3) { do3(a); } else i

【白话篇】10分钟搞懂字符编码

如上图所示为常见的,让人看了头晕的 几个种编码. 看懂下面几条规则,你就明白他们的关系了. [1]有些人说,GBK严格来说是字符集,而utf-8则是编码,这种区分已经相当模糊了,他们都是"字节到字符的映射关系",所以下面都用编码来说吧. [2] ISO-8859-1 这种编码是单字节编码,衍生于ASCII,表示范围0-255,只要按照ASCII的规则设计的编码,不管是几字节的,都可以和ISO-8859-1兼容. [3]比如说,GBK编码(双字节)能转化成ISO-8859-1编码,是因为

彻底搞懂字符编码(unicode,mbcs,utf-8,utf-16,utf-32,big endian,little endian...)[转]

最近有一些朋友常问我一些乱码的问题,和他们交流过程中,发现这个编码的相关知识还真是杂乱不堪,不少人对一些知识理解似乎也有些偏差,网上百度, google的内容,也有不少以讹传讹,根本就是错误的(例如说 unicode编码是两个字节),各种软件让你选择编码的时候,常常是很长的一个选单,让用户不知道该如何选.基于这样的问题,我就写下我的理解吧,一方面帮助一些需要帮助的人纠正认识,一方面作为自己以后备查的资料. 1. ASCII(American Standard Code for Informati

阶梯博弈(没怎么搞懂)

首先是对阶梯博弈的阐述...博弈在一列阶梯上进行...每个阶梯上放着自然数个点..两个人进行阶梯博弈...每一步则是将一个集体上的若干个点( >=1 )移到前面去..最后没有点可以移动的人输.. 如这就是一个阶梯博弈的初始状态 2 1 3 2 4 ... 只能把后面的点往前面放...如何来分析这个问题呢...其实阶梯博弈经过转换可以变为Nim..把所有奇数阶梯看成N堆石子..做nim..把石子从奇数堆移动到偶数堆可以理解为拿走石子..就相当于几个奇数堆的石子在做Nim..( 如所给样例..2^3

零基础搞懂智能机之手机参数怎么看

欢迎转载opendevkit文章, 文章原始地址: http://www.opendevkit.com/?e=53 手机参数, 基本能反映一款机器到底好还是不好.本篇带领大家阅读Samsung Galaxy S5的参数, 让大家购机心里有底. 这里要提醒: 不是硬件参数好, 系统体验就一定好的.当然好的软件, 要用好的硬件支撑. 笔者觉得, 参数差不多就好, 外形, UI, 发热, 安全性比较重要. 曝光日期 2014年 手机类型 4G手机,3G手机,智能手机,拍照手机,平板手机 运营商定制 中

五个小例子教你搞懂 JavaScript 作用域问题

众所周知,JavaScript 的作用域和其他传统语言(类C)差别比较大,掌握并熟练运用JavaScript 的作用域知识,不仅有利于我们阅读理解别人的代码,也有助于我们编写自己的可靠代码. 下面笔者将使用五个小例子来给大家分析下 JavaScript 的作用域要注意的问题. 感谢 例子的来源 (这5个例子我做错了2个 [嘿嘿,尽情鄙视吧],笔者就是要 死磕自己,奉献大家!) 先给出五个例子: 每个例子旁边都会给出答案的链接,如果你全部都正确了,你可以忽略这篇短文,并深深的鄙视下笔者. 例一:

完全搞懂傅里叶变换和小波(6)——傅立叶级数展开之函数项级数的性质

完全搞懂傅里叶变换和小波(6)——傅立叶级数展开之函数项级数的性质 上一小节中我们介绍了函数项级数的概念,这一节我们来讨论函数项级数的性质.傅立叶 级数是一种函数项(三角函数)级数,本质上来说,一幅图像(或者一组信号)就是一个函数,我们研究图像的傅立叶变换,就是要探讨如何将图像函数用三角函数 进行展开.所以如果要彻底搞清楚傅里叶变换,那么讨论函数项级数的性质是非常有必要的.在此基础上,我们将引入傅立叶级数的概念. 如果你对本文涉及的基础问题不甚了解,那么建议你阅读本文前面的部分.希望读者能日积月