Unity中的旋转:搞懂欧拉角与四元数
Unity中的旋转:彻底搞懂欧拉角与四元数
在 Unity 中,我们经常写出类似这样的代码:
transform.eulerAngles = new Vector3(0, 90, 0);
或者:
transform.rotation = Quaternion.Euler(0, 90, 0);
看似只是控制旋转的两种写法,其实背后隐藏着一个巨大的数学鸿沟:
欧拉角 (Euler Angles) 与 四元数 (Quaternion)。
这篇文章我们就把它讲清楚——不仅告诉你区别,还让你理解 Unity 为什么要用“四元数”这种反人类的方式来表示旋转。
一、欧拉角:人类友好的旋转
欧拉角是最直观的旋转方式。
它用三个角度(X、Y、Z)来描述物体分别绕三个坐标轴的旋转量。
举个例子:
| 含义 | 对应轴 | 例子 |
|---|---|---|
| Pitch(俯仰) | X轴 | 头上下点 |
| Yaw(偏航) | Y轴 | 左右转头 |
| Roll(滚转) | Z轴 | 头歪一边 |
在 Unity 中:
transform.eulerAngles = new Vector3(30, 90, 0);
表示物体先绕 X 轴转 30°,再绕 Y 轴转 90°,最后绕 Z 轴转 0°。
看起来很直观,但欧拉角有一个致命缺点——万向锁(Gimbal Lock)。
二、万向锁:旋转自由度的消失
万向锁是指在某些角度组合下,旋转的三个自由轴发生重叠,导致某一维度的旋转“失效”。
举个常见例子:
想象你拿着一个陀螺仪,它可以分别绕三个方向旋转。
如果你把它先绕 X 轴旋转 90°,那么 Y 轴和 Z 轴会重叠,结果你失去了一个旋转自由度——陀螺仪不能再独立转动那一维了。
在 Unity 中,这种情况就会导致:
- 插值(比如
Lerp)不连续; - 旋转动画出现“跳动”;
- 一些角度计算莫名其妙出错。
这就是为什么我们不能完全依赖欧拉角进行旋转计算。
三、四元数:机器友好的旋转
四元数是一种数学结构,形式上是四个数 (x, y, z, w)。
它可以完美描述三维旋转,而不会出现万向锁问题。
Unity 中的 Quaternion 类型,就是对四元数的封装。
比如:
transform.rotation = Quaternion.Euler(0, 90, 0);
其实内部是:
先把欧拉角
(0, 90, 0)转换成四元数,再存到rotation属性里。
四元数的优势:
-
不会万向锁
因为它不依赖顺序旋转三个轴,而是用一种“整体旋转”的方式表示。 -
插值平滑
Unity 的Quaternion.Lerp和Slerp可以实现平滑旋转,非常自然。 -
运算高效
四元数在旋转合成(比如多段旋转叠加)时,计算量更小且更准确。
缺点也很明显:
四元数几乎不可读。Quaternion(0.707, 0, 0.707, 0) 这样的数字完全没有直觉含义。
这就是为什么 Unity 同时保留了两个属性:
| 属性 | 类型 | 含义 |
|---|---|---|
transform.eulerAngles |
Vector3 | 可读可写的欧拉角(单位:度) |
transform.rotation |
Quaternion | 实际存储的四元数旋转 |
四、Unity源码中的 eulerAngles 实现
在 UnityEngine 的源码里,Transform.eulerAngles 是这样定义的:
public Vector3 eulerAngles
{
get => this.rotation.eulerAngles;
set => this.rotation = Quaternion.Euler(value);
}
这意味着:
- 当你读取
transform.eulerAngles时,Unity 会从内部的四元数rotation转换回欧拉角; - 当你赋值给
eulerAngles时,它会把你的人类角度再转换成四元数存回去。
换句话说:
Unity 一直用四元数在工作,只是给你提供了欧拉角的“友好界面”。
五、实际开发建议
-
在 Inspector 或编辑逻辑中用欧拉角
- 因为它直观。
- 例如手动调整角度、配置初始朝向。
-
在代码和运行时逻辑中用四元数
- 比如控制旋转、插值、合成等。
- 用
Quaternion.Lerp、Quaternion.LookRotation、Quaternion.Euler。
-
避免频繁在欧拉角和四元数间来回转换
- 转换不是完全可逆的,会有数值误差。
六、一个常见的坑:旋转叠加
很多人写出类似这样的代码:
transform.eulerAngles += new Vector3(0, 90, 0);
结果旋转越来越奇怪。
原因是每次取 eulerAngles 时,Unity 会重新把四元数转换成欧拉角(有可能产生不同的角度表示),于是误差就不断积累。
正确写法是:
transform.rotation *= Quaternion.Euler(0, 90, 0);
这才是真正意义上的“在原旋转基础上增加90°”。
七、总结一句话
| 概念 | 人类友好 | 数学友好 | 是否会万向锁 | 用途 |
|---|---|---|---|---|
| 欧拉角 (Euler Angles) | ✅ | ❌ | ✅ | 编辑器显示、初始设置 |
| 四元数 (Quaternion) | ❌ | ✅ | ❌ | 实际计算、插值、物理旋转 |
Unity 选择四元数并不是为了让开发者痛苦,而是为了让游戏世界稳定地旋转。
理解四元数,是理解三维空间的入门仪式。
一旦你跨过这一步,旋转再也不会让你晕头转向。
更多推荐


所有评论(0)