Unity四元数和旋转
四元数介绍
旋转,应该是三种坐标变换——缩放、旋转和平移,中最复杂的一种了。大家应该都听过,有一种旋转的表示方法叫四元数。按照我们的习惯,我们更加熟悉的是另外两种旋转的表示方法——矩阵旋转和欧拉旋转。矩阵旋转使用了一个4*4大小的矩阵来表示绕任意轴旋转的变换矩阵,而欧拉选择则是按照一定的坐标轴顺序(例如先x、再y、最后z)、每个轴旋转一定角度来变换坐标或向量,它实际上是一系列坐标轴旋转的组合。
那么,四元数又是什么呢?简单来说,四元数本质上是一种高阶复数(听不懂了吧。。。),是一个四维空间,相对于复数的二维空间。我们高中的时候应该都学过复数,一个复数由实部和虚部组成,即x = a + bi,i是虚数单位,如果你还记得的话应该知道i^2 = -1。而四元数其实和我们学到的这种是类似的,不同的是,它的虚部包含了三个虚数单位,i、j、k,即一个四元数可以表示为x = a + bi + cj + dk。那么,它和旋转为什么会有关系呢?
在Unity里,tranform组件有一个变量名为rotation,它的类型就是四元数。很多初学者会直接取rotation的x、y、z,认为它们分别对应了Transform面板里R的各个分量。当然很快我们就会发现这是完全不对的。实际上,四元数的x、y、z和R的那三个值从直观上来讲没什么关系,当然会存在一个表达式可以转换,在后面会讲。
大家应该和我一样都有很多疑问,既然已经存在了这两种旋转表示方式,为什么还要使用四元数这种听起来很难懂的东西呢?我们先要了解这三种旋转方式的优缺点:
- 矩阵旋转
- 优点:
- 旋转轴可以是任意向量;
- 缺点:
- 旋转其实只需要知道一个向量+一个角度,一共4个值的信息,但矩阵法却使用了16个元素;
- 而且在做乘法操作时也会增加计算量,造成了空间和时间上的一些浪费;
- 欧拉旋转
- 优点:
- 很容易理解,形象直观;
- 表示更方便,只需要3个值(分别对应x、y、z轴的旋转角度);但按我的理解,它还是转换到了3个3*3的矩阵做变换,效率不如四元数;
- 缺点:
- 四元数旋转
- 优点:
- 可以避免万向节锁现象;
- 只需要一个4维的四元数就可以执行绕任意过原点的向量的旋转,方便快捷,在某些实现下比旋转矩阵效率更高;
- 可以提供平滑插值;
- 缺点:
- 比欧拉旋转稍微复杂了一点点,因为多了一个维度;
- 理解更困难,不直观;
四元数和欧拉角
基础知识
N(q)=1,即q−1=q∗。右边表达式包含了四元数乘法。相关的定义如下:
- 四元数乘法:q1q2=(v1→×v2→+w1v2→+w2v1→,w1w2−v1→⋅v2→)
- 共轭四元数:q∗=(−v⃗ ,w)
- 四元数的模:N(q) = √(x^2 + y^2 + z^2 +w^2),即四元数到原点的距离
- 四元数的逆:q−1=q∗N(q)
- 用于旋转的四元数,每个分量的范围都在(-1,1);
- 每一次旋转实际上需要两个四元数的参与,即q和q*;
- 所有用于旋转的四元数都是单位四元数,即它们的模是1;
- 实际上,在Unity里即便你不知道上述公式和变换也丝毫不妨碍我们使用四元数,但是有一点要提醒你,除非你对四元数非常了解,那么不要直接对它们进行赋值。
- 如果你不想知道原理,只想在Unity里找到对应的函数来进行四元数变换,那么你可以使用这两个函数:Quaternion.Euler和Quaternion.eulerAngles。它们基本可以满足绝大多数的四元数旋转变换。
和其他类型的转换
y = sin(Y/2)cos(Z/2)cos(X/2)+cos(Y/2)sin(Z/2)sin(X/2)
z = cos(Y/2)sin(Z/2)cos(X/2)-sin(Y/2)cos(Z/2)sin(X/2)
w = cos(Y/2)cos(Z/2)cos(X/2)-sin(Y/2)sin(Z/2)sin(X/2)
q = ((x, y, z), w)
四元数的插值
四元数的创建
- Vector3 newVector = Quaternion.AngleAxis(90, Vector3.up) * Quaternion.LookRotation(someDirection) * someVector;
又例如,如果你想要组合旋转,比如让人物的脑袋向下看或者旋转身体,两种方法其实都可以,但一旦这些旋转不是以世界坐标轴为旋转轴,比如人物扭动脖子向下看等,那么四元数是一个更合适的选择。Unity还提供了transform.forward, transform.right and transform.up 这些非常有用的轴,这些轴可以和Quaternion.AngleAxis组合起来,来创建非常有用的旋转组合。例如,下面的代码让物体执行低头的动作:
- transform.rotation = Quaternion.AngleAxis(degrees, transform.right) * transform.rotation;
补充:欧拉旋转
欧拉旋转是怎么运作的
- 绕坐标系E下的Z轴旋转α,绕坐标系E下的Y轴旋转β,绕坐标系E下的X轴旋转r,即进行一次旋转时不一起旋转当前坐标系;
- 绕坐标系E下的Z轴旋转α,绕坐标系E在绕Z轴旋转α后的新坐标系E'下的Y轴旋转β,绕坐标系E'在绕Y轴旋转β后的新坐标系E''下的X轴旋转r, 即在旋转时,把坐标系一起转动;
- transform.Rotate(new Vector3(0, 30, 90));
原模型的方向和执行结果如下:
- // First case
- transform.Rotate(new Vector3(0, 30, 0));
- transform.Rotate(new Vector3(0, 0, 90));
- // Second case
- // transform.Rotate(new Vector3(0, 0, 90));
- // transform.Rotate(new Vector3(0, 30, 0));
两种情况的结果分别是:
数学模型
万向节锁
- transform.Rotate(new Vector3(0, 0, 40));
- transform.Rotate(new Vector3(0, 90, 0));
- transform.Rotate(new Vector3(80, 0, 0));
我们只需要固定中间一句代码,即使Y轴的旋转角度始终为90°,那么你会发现无论你怎么调整第一句和最后一句中的X或Z值,它会像一个钟表的表针一样总是在同一个平面上运动。
数学解释
Unity四元数和旋转的更多相关文章
- 【转】Unity四元数和向量相乘作用及其运算规则
作用:四元数和向量相乘表示这个向量按照这个四元数进行旋转之后得到的新的向量. 比如:向量vector3(0,0,10),绕着Y轴旋转90度,得到新的向量是vector3(10,0,0). 在unity ...
- 四元数和旋转(Quaternion & rotation)
四元数和旋转(Quaternion & rotation) 本篇文章主要讲述3D空间中的旋转和四元数之间的关系.其中会涉及到矩阵.向量运算,旋转矩阵,四元数,旋转的四元数表示,四元数表示的旋转 ...
- Unity复杂的旋转-欧拉角和四元数
一.欧拉角欧拉角最容易表示,用三个变量X,Y,Z可以直观的表示绕着某个轴的旋转角度. 在Unity里就是Transform组件的Rotation里的X Y Z三个变量代表了欧拉角 二.四元数四元数相比 ...
- Unity四元数小问题整理
1.Unity中,四元数不能保存超过360度的旋转,所以如此大范围的旋转不能直接两个四元数做插值(当你用0度和721度的四元数做插值,它只会转1度,而不会转两圈). 2.要把旋转设置成某个方向,用Lo ...
- 关于Unity四元数相乘先后顺序的问题
在unity中四元数和向量相乘在unity中可以变换旋转.四元数和四元数相乘类似矩阵与矩阵相乘的效果. 矩阵相乘的顺序不可互换,只有特殊条件矩阵才可互换.四元数相乘类似,今天就因为这个问题掉进坑里了, ...
- Unity脚本-Rotate旋转相关知识点
1,Transform旋转 transform.Rotate(X, Y, Z);//分别绕X,Y,Z轴旋转,可写为绕某个轴旋转,栗子transform.Rotate(0, 90, 0); tr ...
- unity 欧拉旋转
欧拉旋转 在文章开头关于欧拉旋转的细节没有解释的太清楚,而又有不少人询问相关问题,我尽量把自己的理解写到这里,如有不对还望指出. 欧拉旋转是怎么运作的 欧拉旋转是我们最容易理解的一 ...
- Unity检测面板旋转值超过180度成负数的离奇bug
问题描述: 无意中在检视面板上对游戏物体的tansform进行旋转,结果发现旋转超过180度成负数的离奇bug 解决方案: 创建个新的unity工程,进行如上操作,一切正常…… 怀疑问题根源是配置出现 ...
- unity 设置屏幕旋转
只允许竖屏: Portrait √ Portrait Upside Down √ Landscape Right × Landscape Left ...
随机推荐
- UNIX网络编程读书笔记:poll函数
poll函数提供的功能与select类似,不过在处理流设备时,它能够提供额外的信息. poll函数原型 #include <poll.h> int poll(struct pollfd * ...
- Python图像处理(15):SVM分类器
快乐虾 http://blog.csdn.net/lights_joy/ 欢迎转载,但请保留作者信息 在opencv中支持SVM分类器.本文尝试在python中调用它. 和前面的贝叶斯分类器一样,SV ...
- Android API Guides---Tasks and Back Stack
一个应用程序通常包括多个活动.每一个活动应环绕行动的用户能够运行,而且能够启动其它活动的特定种类进行设计.比如,电子邮件应用程序可能具有一个活动,以显示新的消息的列表.当用户选择一个信息.一个新的活动 ...
- eclipse maven Cannot change version of project facet Dynamic web module to 3.0
eclipse maven Cannot change version of project facet Dynamic web module to 3.0 (eclipse 修改maven项目的 ...
- 具有SSM框架的CRUD与多条件查询
概述 居于ssm版本的crud跟多添加查询, 并带分页的demo 详细 代码下载:http://www.demodashi.com/demo/13653.html 一.功能展示 部门CRUD: 员工C ...
- 基于canvas的仪表盘效果
概述 基于Canvas实现的仪表盘及效果.通过配置参数,可以任意修改仪表盘颜色,刻度,动画过渡时间等,满足不同场景下的使用.同时使用原生的Canvas,也是学习Canvas的很好的例子. 详细 代码下 ...
- 【微信开发】JS和PHP分别判断当前浏览器是否微信浏览器
1.PHP端 //判断是否微信浏览器 -xzz1125 function is_weixin() { if (strpos($_SERVER['HTTP_USER_AGENT'], 'MicroMes ...
- 由于link顺序错误导致的undefined reference
其实我之前就遇到过这个问题,也强调过,GNU-G++在link阶段是依赖输入的.o或者.a文件的顺序的.如果顺序错误会导致undefined reference错误 见这篇随笔:http://www. ...
- 使用JSTL的xml:parse标签(或者说x:parse)出现异常NoSuchMethodError,找不到doc的setter method
症状: 如题 <c:import var="hz" url="/xyz/abc.xml" charEncoding="UTF-8"/& ...
- Django接受ajax传过来的数组
$.ajax({ cache: false, type: "POST", url: "/userdelete/", traditional:true, //加上 ...