学习笔记3

Unity中的欧拉角和四元数

笔记主要参考以下的博文

  Unity中的欧拉旋转 - Andrew的游戏世界 - CSDN博客

【Unity编程】Unity中关于四元数的API详解 - Andrew的游戏世界 - CSDN博客


Unity中的欧拉角

顺规

在经典力学里,时常用zxz顺规来设定欧拉角;照着第二个转动轴的轴名,简称为x顺规。另外,还有别种欧拉角组。合法的欧拉角组中,唯一的限制是,任何两个连续的旋转,必须绕着不同的转动轴旋转。因此,一共有12种顺规。

Unity的欧拉角定义

Unity文档中Transform.eulerAngles的定义,本身是一个Vector3,就是一个三维矢量, 分别含有xyz三个参数。

xyz代表了三个角度,它们定义了一组有序的旋转,即围绕z轴旋转z度,然后围绕x轴旋转x度,然后围绕y轴旋转y度。你应该只去读取或者直接设置这些数值,不要增加它们,因为当角度超过360度将会失败。应该使用Transform.Rotate去替代执行旋转操作。

在上述文档中定义了在Unity中欧拉旋转的顺规,即先围绕z轴旋转,后绕x轴,最后绕y轴。

Unity内部使用四元数去执行旋转,不会存储欧拉角的累计值,因此它说超过360度会失败是可以理解的,它用四元数执行完运算之后,会更新最后对应的欧拉角数值,而这个结果欧拉角只是代表了等值的旋转变化结果,却无法代表中间过程,由于欧拉角旋转Z轴361度与1度有一样的结果,它便最后只存储了1度,以便于我们观察和使用。

欧拉旋转的轴

Unity中的Transform文档有有这样一个函数

public void Rotate(Vector3 eulerAngles, Space relativeTo = Space.Self);

这个函数提供了一个可选的相对空间坐标系参数:

Space.Self 局部坐标系,意味着本次欧拉旋转以物体当前的局部坐标朝向为基础出发执行旋转。

Space.World 世界坐标系,意味着本次欧拉旋转以物体当前的世界坐标朝向为基础出发执行旋转。

最重要的倒不是它有可选的世界坐标系,一般而言,常用的旋转都是相对当前局部坐标系执行的。并且在本次欧拉旋转过程中,它的相对轴是始终不变的。

比如我们可以指定一组欧拉旋转(90,60,30),通过前述的顺规我们知道,先绕Z轴旋转30度,再绕X轴旋转90度,再绕Y轴旋转60度,虽然有这样的顺序,但是Z旋转后相对X轴、Y轴,都是执行本组欧拉旋转前的那个轴向,它没有发生变动,所以我称它为“当前轴”

而什么情况下是相对轴不变的呢?举个例子,指定(90,60,30)这组欧拉旋转,执行Transform.Rotate(new Vector3(90,60,30))    是执行了一次欧拉旋转,在这过程中它的相对轴保持不变,但如果是这样的旋转方式:

Transform.Rotate(new Vector3(0,0,30));

Transform.Rotate(newVector3(90,0,0));

Transform.Rotate(new Vector3(0,60,0));

这就是执行了三次欧拉旋转,在执行后两次时其相对轴都会发生变化,显然结果不是我们需要的(90,60,30)的欧拉角旋转。

总结

Unity中的欧拉旋转是按照Z、X、Y顺规执行的旋转,一组欧拉旋转过程中,相对的轴向不会发生变化。 Transform.Rotate(new Vector3(90,60,30)),它代表执行了一组欧拉旋转,它相对的是旋转前的局部坐标朝向。正是这种顺规和轴向的定义,导致了万向节死锁的自然形成。

Unity中的四元数

四元数实际上和矩阵类似,不同的只是它的表示方式以及运算方式。

那么在Unity里如何利用四元数进行旋转呢?

首先是创建四元数,Unity里提供了非常多的方式来创建一个四元数。例Quaternion.AngleAxis(float angle, Vector3 axis),它可以返回一个绕轴线axis旋转angle角度的四元数变换。我们可以一个Vector3和它进行左乘,就将得到旋转后的Vector3。在Unity里只需要用一个“ * ”操作符就可以进行四元数对向量的变换操作,相当于我们上述讲到的p′=qpq−1操作。如果我们想要进行多个旋转变换,只需要左乘其他四元数变换即可,例如

Vector3 newVector = Quaternion.AngleAxis(90, Vector3.up) * Quaternion.LookRotation(someDirection) * someVector;

Unity中提供了关于四元数旋转的API,即Quarternion类。Quaternion(四元数)用于计算Unity旋转。它们计算紧凑高效,不受万向节锁的困扰,并且可以很方便快速地进行球面插值。 Unity内部使用四元数来表示所有的旋转。四元数是基于复数的,因而理解起来难度很大,好在我们并不需要去给出参数的值,而是只需要获取和使用现有的旋转(例如来自“Transform”),或者用四元数来构造新的旋转(例如,在两次旋转之间平滑插入)即可。

一些常用的函数:

Quaternion.LookRotation   前方、上方标注矢量法创建四元数

Quaternion.Angle    计算两个四元数前方矢量之间的夹角度数

Quaternion.Euler  欧拉角表示创建四元数

Quaternion.Slerp  球面插值

Quaternion.FromToRotation  A向到B向相对旋转表示法创建四元数

Quaternion.identity  为单位四元数,即默认的无旋转状态

Quaternion 是一个结构体,本身成员变量相对简单,可以作为函数参数高效传递。

Unity的方向

Unity中使用左手坐标系,假如把世界坐标系跟东南西北进行结合起来看,大致如下图所示:

+x         东(右)                    +y         上                +z            前(北)

-x          西(左)                    -y          下                -z             后(南)

以自己身体为例,你站立在地面上,面朝北方,此时就是默认方向,也就是Unity中的方向就是面向+Z轴方向,那么此时+X轴在东方,+Y轴对应正上方。此时对应的欧拉角是(0,0,0),此时对应的前方矢量是(0,0,1),上方矢量是(0,1,0)。这里的上下左右的概念与Vector3类、Transform类中的相应的方向函数也是相对应的。

确定方向的方法

1.欧拉角表示法

Unity中的欧拉旋转方向为固定的zxy顺规。

2.前方、上方标定矢量法

根据对局部坐标轴的描述, 构造对应的代表旋转程度的四元数。

指的是从默认方向到LookRotation参数的变化量。例如   Quaternionq2 = Quaternion.LookRotation(Vector3.down ,Vector3.forward); 是指从Unity默认方向到这个的变化量,按照左手坐标系,绕x转90,从Z+到Y-。

3. 绕轴旋转界定法

使物体沿某一指定的轴向旋转一定的角度。这个方法也可以确定一个相对旋转,它以从默认方向(此时前方+Z,上方+Y)出发,沿着指定的轴向进行指定角度的旋转。旋转后的前方和上方是确定的,所以可以确定朝向。

4.A向到B向相对旋转表示法

从A向到B向的相对旋转,这种表示了一个旋转的相对变化。比如A为(0,1,0),B为(0,0,1),也就是相对旋转量代表原来的上方被旋转到了前方,这样的一个四元数也可以用欧拉角表示成(90,0,0),也就是沿着+X轴旋转了90度。

利用几种表示方法在Untiy中创建四元数

Quaternion q1=Quaternion.Euler(90, 0, 0);     //方法1—欧拉角表示

Quaternion q2 = Quaternion.LookRotation(Vector3.down ,Vector3.forward);  //方法2—前方上方标注矢量法

Quaternion q3 = Quaternion.AngleAxis(90,Vector3.right);  //方法3—绕轴旋转界定法 

Quaternion q4 = Quaternion.FromToRotation(Vector3.up, Vector3.forward);   // 方法4—A向到B向相对旋转表示法

成员变量

eulerAngles 欧拉角,返回当前四元数所对应的欧拉角

this[int] 可以使用类似数组和下标的形式从四元数中获取四个四元数参数

四元数的具体参数x,y,z,w分量一般不手动设置,易出错。

identity 单位四元数,也就是默认的无旋转状态,此时与世界坐标相同,前方指向+Z,上方指向+Y

成员函数

静态函数

1.static float Angle(Quaternion a, Quaternion b)   计算两个四元数前方矢量之间的夹角度数

2.static Quaternion AngleAxis(float angle, Vector3 axis)   构建一个四元数,它表示沿着一个轴旋转固定角度,即上述表示法3

3.static float Dot(Quaternion a, Quaternion b)   计算两个四元数之间的点积,返回一个标量,这个函数一般用不到

4.static Quaternion Euler(float x, float y, float z)  构建一个四元数,用欧拉角度表示

5.static Quaternion FromToRotation(Vector3 fromDirection, Vector3 toDirection)  构建一个四元数,它表示从指向fromDirection方向到指向toDirection方向的相对旋转量,见上述表示法4

6.static Quaternion Inverse(Quaternion rotation)  构建一个四元数,它是指定的四元数的逆,也就是逆向旋转,比如原四元数表示相对+X轴旋转了90度,那么此函数结果就是相对+X轴旋转了-90度

7.static Quaternion Lerp(Quaternion a, Quaternion b, float t)    构建一个四元数,表示从四元数a到b的球面插值,所谓的插值也就是中间旋转量,从a作为起点,此时对应t为0,到b为终点,此时对应t为1。当t取0-1之间的小数时,就代表了中间的插值结果。这个方法与Slerp相同,计算速度快,但是精度低,如果相对旋转变化量很小,则效果不理想

8.static Quaternion LerpUnclamped(Quaternion a, Quaternion b, float t)  与Lerp相同,区别是,Lerp的t值会被钳制在[0,1]之间,而此方法则不会,t允许超出计算

9.static Quaternion LookRotation(Vector3 forward, Vector3 upwards = Vector3.up)  构建一个四元数,使用前方上方矢量确定朝向,也就是上述表示法2

10.static Quaternion RotateTowards(Quaternion from, Quaternion to, float maxDegreesDelta)  构建一个四元数,表示从一个四元数from(的前方)向着另外一个四元数(的前方)旋转,但不能超出指定的角度,也就是如果两个前方矢量夹角超过指定角度,则旋转到达指定角度时就停止,若是夹角本身不足的话,则结果直接为目标四元数to,与上述表示法4的意思很接近

11.static Quaternion Slerp(Quaternion a, Quaternion b, float t)  球面插值,与Lerp功能相同,t值也被钳制,计算精度高,但是速度相对较慢

12.static Quaternion SlerpUnclamped(Quaternion a, Quaternion b, float t)  与Slerp功能相同,只是t值不被钳制,允许超出计算

13.static Quaternion operator * (Quaternion lhs, Quaternion rhs)  乘法运算符重载,当表示两个连续的旋转时,可以使用lhs * rhs的形式得出连续旋转的结果,lhs为左值,rhs为右值。注意左值是先进行的旋转,叠加右值旋转。用法示例:lhs = lhs * rhs;

14.static Vector3 operator *(Quaternion rotation, Vector3 point)  乘法运算符重载,表示对一个矢量point施加旋转rotation,得出旋转后的结果矢量。用法示例:Vector3 result=rotation * point

对于一些方法的详细描述可以参考

Unity中的四元数类详解【详解】 - qq_36684665的博客 - CSDN博客

Unity3D入门篇——Quaternion类 - u014086857的专栏 - CSDN博客

Unity中四元数的使用

Unity 如何使用四元数_百度经验

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容