1. 为什么我们需要这么多旋转表示法?
如果你刚开始接触3D图形编程,比如在Unity里摆弄一个角色,或者在Unreal Engine里调整摄像机,你可能会被一堆关于旋转的名词搞晕。最直观的,你肯定用过“旋转角度”这个功能,在Unity的Inspector面板里,一个GameObject的Rotation属性可能就是三个数字,比如 (30, 45, 0)。这就是欧拉角,它非常符合人类的直觉:上下看(Pitch)、左右转(Yaw)、歪头(Roll)。我刚开始做项目时,也最喜欢用它,调起来太方便了,所见即所得。
但很快你就会踩坑。比如,你写了一段代码让摄像机平滑跟随玩家,同时要避免穿墙,你可能会用Lerp去插值两个欧拉角。结果发现,当角色跑到头顶或脚下时,摄像机会突然发疯似的乱转,或者干脆卡在一个角度不动了。这就是传说中的“万向节死锁”。我第一次遇到时,调试了半天,以为是数学库的bug,后来才知道是欧拉角固有的缺陷。这就像你手里的一个三轴云台,当中间那根轴转到90度时,另外两个轴的旋转就“锁”在了一起,丢失了一个维度的自由度。
为了解决这个问题,前辈们发明了其他表示法。轴角的想法很直接:既然旋转就是绕着一根轴转一个角度,那我直接告诉你轴的方向(一个三维向量)和转了多少度(一个标量)不就行了?这个想法很美,但在实际计算中很不方便,比如你很难把两个轴角表示的旋转直接组合起来。于是,更强大的数学工具——四元数就登场了。它用四个数(一个标量加一个三维向量)来优雅地表示旋转,完美解决了万向节死锁,并且计算效率极高。最后,还有旋转矩阵,它是一个3x3的矩阵,是图形API(如OpenGL、DirectX)底层真正理解和使用的形式,任何旋转最终几乎都要转换成矩阵去驱动显卡。
所以,这几种方法没有绝对的好坏,只有适合的场景。理解它们的原理、优缺点和相互转换,就像你工具箱里有了不同型号的螺丝刀,遇到具体问题才知道该用哪一把。这篇文章,我就结合自己这些年做游戏和VR项目踩过的坑,带你彻底搞懂它们,并告诉你什么时候该用什么。
2. 直观但危险的欧拉角:从理解到陷阱
2.1 欧拉角到底是什么?
我们抛开教科书上复杂的静态定义,用一个最生活的例子来理解。想象你正在操作一架无人机。
- Pitch(俯仰角):你推拉遥控器的前进杆,无人机机头抬起或低下。这相当于绕它的X轴旋转。
- Yaw(偏航角):你扭动遥控器的方向,无人机原地左转或右转。这相当于绕它的Y轴旋转。
- Roll(翻滚角):你拨动副翼控制,无人机向左或向右侧翻。这相当于绕它的Z轴旋转。
在Unity中,一个物体的欧拉角 (x, y, z) 默认对应的就是 (Pitch, Yaw, Roll),但注意,这个顺序很重要!Unity内部使用的顺序是 Z-X-Y(即先Roll,再Pitch,最后Yaw)。不同的引擎、不同的领域(如航空航天)可能采用完全不同的顺序(如X-Y-Z, Y-Z-X等)。这是欧拉角的第一个大坑:你必须明确知道当前系统采用的旋转顺序,否则同样的三个数会得到完全不同的朝向。
// Unity C# 示例:直接设置欧拉角
transform.eulerAngles = new Vector3(30f, 45f, 0f);
这行代码会让物体绕X轴旋转30度,绕Y轴旋转45度,绕Z轴旋转0度。看起来很简单,对吧?
2.2 万向节死锁:欧拉角的“阿喀琉斯之踵”
这是欧拉角最著名也最让人头疼的问题。它不是程序bug,而是这种三维表示方法固有的数学缺陷。我们再用无人机比喻:假设你的无人机Pitch(抬头)了90度,此时机头笔直朝天。现在,你想让它Yaw(水平转向),但你会发现,在这个姿态下,你操作Yaw杆,无人机的实际运动变成了Roll(侧翻)!原本独立的Yaw和Roll两个自由度重合了,你失去了一个控制维度。
在数学上,当第二个旋转轴(在Unity默认顺序里是X轴)旋转到±90度时,第一次旋转(Z轴)和第三次旋转(Y轴)的旋转平面就变得相同,导致其中一个旋转失效。下面的代码模拟了一个可能导致问题的插值:
// 一个可能引发问题的平滑旋转示例(伪代码)
Vector3 startEuler = new Vector3(0f, 0f, 0f);
Vector3 endEuler =

245

被折叠的 条评论
为什么被折叠?



