【Unity编程】四元数(Quaternion)与欧拉角
版权声明:本文为博主原创文章,欢迎转载。请保留博主链接:http://blog.csdn.net/andrewfan
欧拉旋转、四元数、矩阵旋转之间的差异
除了欧拉旋转以外,还有两种表示旋转的方式:矩阵旋转和四元数旋转。接下来我们比较它们的优缺点。
欧拉角
- 优点:三个角度组成,直观,容易理解。
- 优点:可以进行从一个方向到另一个方向旋转大于180度的角度。
- 弱点:死锁问题。 前面《【Unity编程】欧拉角与万向节死锁(图文版)》已经介绍过万向节死锁问题。
四元数
内部由四个数字(在Unity中称为x,y,z和w)组成,然而这些数字不表示角度或轴,并且通常不需要直接访问它们。除非你特别有兴趣深入了解四元数学,你只需要知道四元数表示三维空间中的旋转,你通常不需要知道或修改x,y和z属性。
- 优点:四元旋转不存在万向节锁问题。
- 优点:存储空间小,计算效率高。
- 弱点:单个四元数不能表示在任何方向上超过180度的旋转。
- 弱点:四元数的数字表示不直观。
矩阵旋转
- 优点:与四元数一样,不存在万向节锁问题
- 优点:可以表示围绕任意轴的旋转,四元数的旋转轴均为通过物体中心点的轴,矩阵则不受限
- 缺点:矩阵旋转使用4x4矩阵,记录16个数值,而四元数只需要4个数值。计算复杂,效率低。
- - -
由于Unity中的旋转使用四元数,因此本文重点就放在四元数数学上。矩阵还是某些场合需要用到,比如坐标变换。不过你几乎不需要手动去执行矩阵计算,除非你在做Shader编程,或者是某些需要极端提高效率的场合。后续我计划写一篇文章专门介绍矩阵变换。
四元数的数学
由于前面两篇文章均尽可能采用无数字计算的方式,为的是方便理解。而这里由于需要理解四元数的计算,我们还是需要理解一些复数和欧拉旋转计算方面的基本数学。
复数
首先了解一下复数,上图中,左右方向的轴(X轴)称为实数轴,上下的轴(Y轴)称为虚数轴。
任意一个二维矢量,都可以使用一个复数形式进行表示。也就是:e = a + bi
其中a是实数,i是虚数,i * i=-1。
至于什么是虚数,我的理解它就是个不同维度的后缀标记和符号而已。i标记了实数轴和虚数轴之间的差异,也就是旋转90度旋转的差别,乘以i意味着这种旋转关系。
为什么i * i=-1?也就是两个虚数i乘积又变成了实数-1?因为从实数轴(1表示)围绕上图中逆时针90度(1i)到达虚数轴(=i),再逆时针旋转90(1 i * i)就到达了负实数轴方向(=-1)。所以这里规定i * i=-1。
复数运算
- 加法: (a+bi)+(c+di)=(a+c)+(b+d)i
- 减法: (a+bi)-(c+di)=(a-c)+(b-d)i
- 乘法: (a+bi)(c+di)=ac+bci+adi+bdi^{2}=(ac-bd)+(bc+ad)i
更多复数相关知识,请参考“维基百科-复数_(数学)”
欧拉旋转定理
为了方便讨论旋转,我们避开矢量长度的影响,也就是假设问题是基于长度为1的矢量去讨论。由上图可以看出,当长度为1时,矢量落在长度为1的圆形上,此时实数轴上的a = cos(φ),虚数轴上的b = sin(φ),其中φ为旋转角度。
此时的表示形式为 e = cos(φ) + sin(φ)i
那么,使用这样一种形式到底有什么意义呢?数学从来都是工具,如果没有用处,它也就不会存在了。我们接下来看它的作用。
当圆上的一个矢量进行了连续的旋转时时,假设先旋转φ,再旋转θ,则结果应该是两个旋转的角的和的复数形式,即 e = cos(φ+θ)+sin(φ+θ)i
假设:
e1= cos(φ) + sin(φ)i (表示旋转了φ角度)
e2= cos(θ) + sin(θ)i (表示旋转了θ角度)
那么e和e1、e2之间的关系是怎样的?
- - -
根据和差公式可以得知
cos(φ+θ)+sin(φ+θ)i
= (cos(φ)cos(θ)-sin(φ)sin(θ))+(sin(θ)cos(φ)+cos(θ)sin(φ))i
= cos(φ)cos(θ)+cos(φ)sin(θ)i+cos(θ)sin(φ)i- sin(φ)sin(θ)
= (cos(φ) + sin(φ)i)(cos(θ) + sin(θ)i)
= e1 e2
=>
e = e1*e2
- - -
也就是说,连续的旋转(例如这里旋转φ再旋转θ),可以使用两个复数的乘积进行表示。在计算机运算中:
- 如果知道φ=30度,那么计算此单位矢量再旋转θ=40度是很容易的,只需要直接运算cos(φ+θ)和sin(φ+θ)即可。
- 如果知道一个矢量(a+bi),不知其φ值,要对其进行旋转θ=40度,那么也就有了快速的计算方法,即:
(a+bi) * (cos(40)+sin(40)i) = (a * cos(40)-b * sin(40)) + (b * cos(40) + a * sin(40))i
结果:二维向量 x = a * cos(40)-b * sin(40),y= b * cos(40) + a * sin(40)
可以快速计算出二维矢量结果,而不必先求φ。
因此这就是复数和欧拉旋转定理的作用,它可以使用复数很方便地表示出二维矢量的旋转变化。
四元数
相对于复数为二维空间,为了解决三维空间的旋转变化问题,爱尔兰数学家威廉·卢云·哈密顿把复数进行了推广,也就是四元数。
以下均为定义,所谓定义,就是我们人为设置的概念和计算方法,它们本身或许没有什么意义,但是如果按照这些概念和方法计算出某些有意义的结果,那么这些定义也就有了相应的意义。
四元数定义
四元数定义i、j、k三个虚数单位参与运算,并有以下运算规则:
i、j、k仍然理解为旋转,其中:
- i旋转代表X轴与Y轴相交平面中X轴正向向Y轴正向的旋转
- j旋转代表Z轴与X轴相交平面中Z轴正向向X轴正向的旋转
- k旋转代表Y轴与Z轴相交平面中Y轴正向向Z轴正向的旋转
- -i、-j、-k分别代表i、j、k旋转的反向旋转
一个普通四元数可以写成如下形式:
四元数的i、j、k之间乘法的性质与向量之间的叉积结果形式很类似,于是四元数有了另外一种表示形式:
加法定义
四元数加法,跟复数、矢量和矩阵一样,两个四元数之和需要将不同的元素加起来,加法遵循实数和复数的所有交换律和结合律:
格拉斯曼积定义
四元数的乘法有很多种,最常见的一种定义,与数学多项式乘法相同,称为格拉斯曼积。(注意,下面乘积的式子是由多项式形如a+bi+cj+dk的多项式进行多对多乘法(比如4项x4项=16项)计算后,使用矢量的点积和叉积替代部分计算项后形成):
把向量部分和实数部分分开,可以写成:
点积定义
叉积定义
四元数叉积:p × q
四元数叉积也称为奇积。它和矢量叉积等价,并且只返回一个矢量值:
共轭定义
四元数的共轭的定义。即实部相同,虚部相反。(与复数概念类似)
定义的推论
模的定义
四元数的模的定义。与矢量的模类似,都表示长度或者绝对值的意思。四元数的绝对值是四元数到原点的距离。
逆的定义
单位四元数的定义
所谓的单位量,都是指,任意原始量乘以单位量之后保持原始量不变。如对于实数而言,任意原始实数乘以实数1等于原始实数,因此1被定义为单位。
四元数的归一化
归一化也叫单位化,与矢量的概念一样,就是为了把长度调整到单位长度。现在单位四元数已经得知,其单位长度显然是1。我们也知道了模的计算方法,因此把四元数的归一化方法如下:
四元数映射_实数
我们可以将实数映射到四元数空间,所谓的映射,也就是说1对1的找到相应的存在,并且在不同空间施加施加相对应运算的法则时获得相同的结果。
例如,对应实数w,尝试进行如下映射:
四元数映射_矢量直接映射
与实数映射类似,我们也可以尝试将三维矢量映射到四元数。
四元数映射_矢量间接映射
同态
先考虑一个同态概念:假设M,M′是两个乘集,也就是说M和M′是两个各具有一个封闭的具有结合律的运算与的代数系统。φ是M射到M′的映射,并且任意两个元的乘积的像是这两个元的像的乘积,即对于M中任意两个元a,b,满足
φ(ab)=φ(a)φ(b);
也就是说,当a→φ(a),b→φ(b)时,ab→φ(a)φ(b),
那么这映射φ就叫做M到M′上的同态。我前面所解释的可以互相映射大致意思也就是同态。
四元数中的同态函数
为什么我们研究同态?因为这里涉及到我们希望出现的向量的旋转,一个三维空间的向量被旋转之后,它应该还是一个三维矢量。这个旋转函数应该满足以下要求:
接着,我们详细了解间接映射的步骤。如下图所示:
[此处还可以解释得更明确,不过太过复杂了]
旋转四元数
最后,给出旋转四元数,也就是一直在追求的φ()函数。
总结
四元数是高阶复数的数学,它用在游戏中的作用主要是计算三维矢量的旋转,它使用先将矢量映射到纯虚四元数,再应用旋转四元数的方式进行映射。最后可以达成旋转目的。
前面的四元数性质不甚了解也没有太大关系,大概了解到是如何映射的也就可以了。甚至在Unity编程过程中你对四元数的映射关系不了解都无所谓。后续文章中我再介绍具体的用法。
【Unity编程】四元数(Quaternion)与欧拉角的更多相关文章
- 【转】【Unity】四元数(Quaternion)和旋转
http://blog.csdn.net/candycat1992/article/details/41254799
- 【Unity编程】Unity中关于四元数的API详解
本文为博主原创文章,欢迎转载,请保留出处:http://blog.csdn.net/andrewfan Unity中关于四元数的API详解 Quaternion类 Quaternion(四元数)用于计 ...
- [Unity Quaternion]四元数Quaternion的计算方式
什么是Quaternion四元数 1843年,William Rowan Hamilton发明了四元数,但直到1985年才有一个叫Ken Shoemake的人将四元数引入计算机图形学处理领域.四元数在 ...
- 学习和研究下unity3d的四元数 Quaternion
学习和研究下unity3d的四元数 Quaternion 今天准备学习和研究下unity3d的四元数 Quaternion 四元数在电脑图形学中用于表示物体的旋转,在unity中由x,y,z,w 表示 ...
- unity3d的四元数 Quaternion
原地址:http://www.cnblogs.com/88999660/archive/2013/04/02/2995074.html 今天准备学习和研究下unity3d的四元数 Quaternion ...
- 【Unity编程】Unity中的欧拉旋转
欧拉角的定义 在写这篇博客之前,我搜索了网上很多关于欧拉角的定义,发现大部分引用自维基百科的定义,我这里也引述一下: 维基百科定义 莱昂哈德·欧拉用欧拉角来描述刚体在三维欧几里得空间的取向.对于任何参 ...
- 四元数Quaternion的基本运算
技术背景 在前面一篇文章中我们介绍了欧拉角死锁问题的一些产生背景,还有基于四元数的求解方案.四元数这个概念虽然重要,但是很少会在通识教育课程中涉及到,更多的是一些图形学或者是工程学当中才会进行讲解.本 ...
- Unity编程标准导引-3.4 Unity中的对象池
本文为博主原创文章,欢迎转载.请保留博主链接http://blog.csdn.net/andrewfan Unity编程标准导引-3.4 Unity中的对象池 本节通过一个简单的射击子弹的示例来介绍T ...
- Unity编程标准导引-3.1 Component 组件脚本及其基本生命周期
本文为博主原创文章,欢迎转载,请保留出处:http://blog.csdn.net/andrewfan 3.1组件 Component 组件是Unity中最核心的一个概念,它是一切编程的基础.没有组件 ...
随机推荐
- 分享一些免费的MD5解密网站
最近下载了几个mdb文件,里面几万条md5和几千条sha512(居然还有站长用512直接放在库中的,尼玛多占空间啊),我用C#写了个工具暴 力了一小部分,大概不到3%吧, 花了我两天,电脑卡得要死,效 ...
- WinForm DataGridView控件、duck布局
1.DataGridView控件 显示数据表 (1)后台数据绑定: List<xxx> list = new List<xxx>(); dataGridView1.DataSo ...
- java版二叉树算法实现
import java.util.ArrayList; class BinaryTree { private static class TreeNode { int data; TreeNode le ...
- 法国总统放大招,用“分身术”竞选总统 全息3d 网
编辑:大熊 [摘要]法国总统采用全息技术实现"分身"演讲,可谓是一次演讲,全面覆盖! 全息3d网讯:众所周知,欧美国家的总统是通过公开竞选得到的,所以能更直接.更广泛的近距离接触民 ...
- vs生成配置release自动恢复成debug无法配置的问题
软件为visual studio 2015,右键单个项目选属性,设置“生成配置”release,保存后,再次右键属性,却发现又自动恢复成debug,怎么回事?是无法配置吗?点击生成试试,果然2b了. ...
- indexOf()--数组去重
@(JavaScript) 数组去重方法有多中,这里列举出自己认为比较容易理解的方法. 思路: 创建一个新的空数组,用来存放去重后的新数组. 利用for循环循环遍历需要去重的数组. 利用indexOf ...
- 11 Python+selenium对下拉框(select)进行处理
[环境信息] Python3.4+IE+windows2008 [Select下拉框处理] 1.对于如图1的下拉框,可以用selenium自带的Select类进行选择. 2.定位示例: from se ...
- python解释器的安装;python2与python3同时在环境变量中时的解决方案
新文档 html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,addres ...
- css中的text-overflow
css中的text-overflow HTML中: <body><div class="clip">此处中多余的文字直接被切掉,不显示</div> ...
- [Kafka] - Kafka内核理解:消息的收集/消费机制
一.Kafka数据收集机制 Kafka集群中由producer负责数据的产生,并发送到对应的Topic:Producer通过push的方式将数据发送到对应Topic的分区 Producer发送到Top ...