微信公众号:老牛同学
春节期间,老牛同学学习使用 Cocos Creator 研发了一款 3D 小游戏。开发过程中遇到了一些全新概念和用法,虽然借助大模型最终完成了小游戏功能的开发,但对这些概念却一知半解。
其中,在需要 3D 组件旋转的功能中,“欧拉角”和“四元数”就是研发过程中遇到的一个全新的概念。如下代码是大模型帮忙实现的“左右水平滑动”功能:
本文将对“欧拉角”和“四元数”进行尽可能详细的总结,尽可能不涉及数学证明公式,希望能给像我一样有困惑的朋友一些帮助:
- 基本概念:为什么对于 3D 物体旋转,大家都采用欧拉角和四元数来表示?为什么 1 个概念还不够,还需要 2 个?他们分别解决什么主要问题?
- 如何应用:在不同场景下,欧拉角和四元数如何应用旋转?它们如何应用到物体旋转?
- 实际应用:最后,用一个“让立方体的对角线垂直于地面并旋转”功能,演示如何让物体旋转后并不停的旋转起来。
本文代码和小游戏源代码均可免费下载:打开“老牛同学”微信小程序->点击“更多”Tab->“源代码”获取下载链接。
【源代码:“老牛同学”微信小程序->点击“更多”Tab->“源代码”下载】
欧拉角和四元数存在的意义是什么?
首先,欧拉角和四元数都是用于描述三维空间中物体旋转的常用工具,它们只是工具,核心就是三维和旋转。
欧拉角最早由瑞士数学家莱昂哈德·欧拉(Leonhard Euler)于 18 世纪提出,他认为:三维空间中物体的任意姿态,都可以通过三个连续的旋转角度来描述(即:第一步绕某个轴旋转,第二步绕另一个轴旋转,第三步绕第三个轴旋转)。用 3 个数就可以表示旋转姿态,确实一种非常直观且易于理解的方法。
那么,对应到游戏开发中,欧拉角的就是我们最常见的X 轴、Y 轴和Z 轴旋转属性来表示了。如下所示,把一个长方体按照 X/Y/Z 旋转后的姿态:
注意的是,在三维空间中,我们一般用姿态或位姿来表示物体的当前旋转,它有两层含义:
- 物体方向,或者朝向
- 物体局部坐标系相当于世界坐标系的偏移量
四元数由爱尔兰数学家**威廉·罗文·汉密尔顿(William Rowan Hamilton)**于 1843 年提出。汉密尔顿希望找到一种用于描述三维空间旋转的数系。据说,汉密尔顿有一次在散步时突然想到了四元数的基本公式,并将其刻在了一座桥上。
四元数由一个实部和三个虚部组成,形式为:Q = W + Xi + Yj + Zk
,其中W
,X
,Y
,Z
是实数,i
,j
,k
是虚数单位。
既然欧拉角表示旋转已经足够优秀了,为什么还需要引入四元数呢?
原因在于,欧拉角虽然简单直观,但存在三个问题:万向锁问题(Gimbal Lock)、旋转过程中插值困难、计算效率较低的问题。
接下来,老牛同学根据自己的理解,逐一介绍欧拉角的这几个问题,同时看看四元数是如何解决的。
什么是旋转,什么是坐标系?
在介绍欧拉角和四元数之前,先了解一下旋转和坐标系。
旋转是指物体在三维空间中绕某个轴进行角度变化的运动:
- 轴:在三维空间中,我们一般 X 轴、Y 轴和 Z 轴表示。
- 角度:通常用角度或弧度来表示。
- 运动方向:分为右手坐标系或者左手坐标系。Cocos 3D 使用右手坐标系,Unity 3D 使用左手坐标系。默认情况下,轴默认配置:X 轴向右为正,Y 轴 向上为正,Z 轴朝屏幕外为正。
右手坐标系旋转方向:伸出右手,大拇指指向轴的正方向(如:围绕 X 轴旋转+30°,则大拇指指向 X 轴的正方向);弯曲四指,四指弯曲的方向为旋转正方向(如:+30°),反过来手背方向便是负方向。
左手坐标系旋转方向:类似于右手坐标系,伸出左手即可。
世界坐标系: 三维空间的参考框架,所有物体的参考标准,它是固定不变的。
本地坐标系: 每个物体都有的自己的坐标系,用于描述其自身的姿态。
一般情况下,我们所说的旋转指的是局部坐标系,当然也可以相对于全局坐标系。
万向锁问题和解法
万向节常用在汽车动力传输上,它是汽车驱动系统关节,它可以围绕不同方向旋转:
在解释万向锁问题之前,有三个非常重要的概念必须理解:
- 无论是欧拉角还是四元数,它们表示的是物体旋转后的姿态,是一个描述,它不是一个连续的动作。比如:欧拉角
(90,0,0)
代表围绕 X 轴旋转+90°,它表示的是这个物体旋转+90° 后的姿态,而不是表示物体围绕 X 轴,从 0°->1°->2°->……->90° 这个过程。因此,这里的“旋转”它不是指一个连续的动作! - 物体姿态与旋转的顺序密切相关,相同的角度,不同的旋转顺序,物体的姿态是不相同的。我们可以拿个快递盒子,做个简单的实验就能明白。如:围绕 X 轴旋转 90°,Y 轴 45°,X→Y→Z旋转顺序,和Y→X→Z旋转顺序,快递盒子的姿态是不同的。
- 物体按照某个顺序依次旋转,前面的轴旋转时,会带动后面的轴一同旋转,而后面轴旋转却不会影响前面的轴。如:X→Y→Z 旋转顺序,当围绕 X 轴旋转时,本地坐标系 Y 轴和 Z 轴一同旋转;当围绕 Y 轴旋转时,Z 轴会一同旋转,但 X 轴是不动的;最后,当围绕 Z 轴旋转时,X 轴和 Y 轴都不会动!
第 3 点感觉非常的诡异,老牛同学就被这个不可思议的概念折磨了好久,直到彻底理解了第 1 点:永远记住,欧拉角和四元数这些表示旋转的工具,它们只是描述旋转后的姿态,并不是旋转动作(旋转在这里当名称理解),它没有动作过程,只是最终的瞬时的姿态!
如果大家理解了第 1 点,那么可以退一步想:X→Y→Z 旋转顺序,如果围绕 Y 轴旋转时,X 轴也跟着旋转,那么 X 轴最初的旋转不就白费了吗?
如果第 3 点无法理解的话,那么万向锁的问题是无法理解,因为它就是万向锁产生的前提!
至此,大家也可以到网上看看数学推导公式,在此老牛同学就不列举了!
万向锁定义:当两个旋转轴重合时,原本三个独立的旋转轴(X、Y、Z)变成了两个,导致自由度减少的现象。
我们先来看看,万向锁发生的场景:物体的任意旋转顺序(如:X→Y→Z,Y→X→Z 等),当围绕第 2 个轴旋转的角度为 ±90° 时,那么第 3 个轴就会和第 1 个轴就会重合。这样当物体围绕第 1 个轴旋转或者第 3 个轴旋转,姿态都是一样的,无法区分,这种现象就是“万向锁”问题。