1. 从“拧螺丝”到“转陀螺”:为什么Unity里旋转这么麻烦?
刚接触Unity那会儿,我最头疼的就是旋转。我想让一个角色转头看向敌人,直觉告诉我,这不就是改改X、Y、Z三个角度的事儿吗?在Inspector面板里,Transform组件的Rotation确实显示着三个可爱的数字,我天真地以为,在代码里直接给transform.rotation.x赋值就能搞定。结果呢?要么纹丝不动,要么物体像抽风一样乱转,场面一度非常尴尬。
后来我才明白,我犯了一个几乎所有Unity新手都会犯的错误:把欧拉角(Euler Angles) 和四元数(Quaternion) 混为一谈。Inspector面板里显示的是欧拉角,是给我们人类看的,直观易懂。比如(0, 90, 0)就表示绕Y轴旋转了90度。但Unity底层,transform.rotation这个变量,它的真实类型是四元数。这东西有四个分量(x, y, z, w),它描述的是一种“轴-角”的旋转状态,而不是简单的三个角度。你可以把它想象成一个高级的、不会出错的“旋转陀螺仪”,而欧拉角更像是“拧三个不同方向的螺丝”来调整姿态。
为什么Unity要“自找麻烦”用四元数?这背后有两个关键原因,都是欧拉角的“硬伤”。第一是万向节死锁(Gimbal Lock)。简单说,当某个轴旋转到特定角度(比如90度)时,另外两个轴的旋转会突然“锁”在同一个平面上,丢失一个旋转自由度。你想让相机平滑地仰头再转头,结果它可能卡在一个奇怪的角度动弹不得。第二是插值困难。做动画时,我们经常需要计算两个旋转之间的中间状态(比如从A方向平滑转向B方向)。对欧拉角做线性插值,物体可能会沿着一条奇怪的、扭曲的路径运动,而不是最短的球面路径。而四元数通过球面线性插值(Slerp) 可以完美解决这个问题,让旋转又平滑又自然。
所以,在Unity里处理旋转,本质上就是学会在“人类友好”的欧拉角(Vector3)和“机器高效”的四元数(Quaternion)之间自如转换。这就像你既要知道怎么用扳手(欧拉角)去描述一个姿势,也要知道怎么用陀螺仪(四元数)去稳定和控制这个姿势。接下来,我就把自己踩过的坑和总结的技巧,毫无保留地分享给你。
2. 核心转换三板斧:代码怎么写,坑在哪里?
转换本身并不复杂,Unity提供了非常直接的API。但如果你只记代码,不搞懂背后的“脾气”,还是会掉坑里。我们先看最基础、最常用的两种转换。
2.1 四元数转欧拉角:.eulerAngles的“小脾气”
这是你最常用到的操作。比如你想知道当前物体到底旋转了多少度,或者想把旋转角度显示在UI上。
// 最标准的写法:从物体的rotation属性直接获取欧拉角
Vector3 currentEulerAngles = transform.rotation.eulerAngles;
Debug.Log("当前欧拉角: " + currentEulerAngles);
看起来很简单,对吧?但这里有个至关重要的细节:eulerAngles属性返回的每个角度值,范围是0到360度。比如,你旋转了-10度(即350度),它返回的就是350。这在大多数情况下没问题,但当你需要做角度差值计算时,就要小心了。比如,当前是350度,目标方向是10度,直接相减会得到-340度,这显然不是最短的旋转路径。你需要自己处理这个360度的循环问题。
更隐蔽的一个坑是设置与读取的不一致性。这是官方文档明确警告的。看下面这段代码:
Quaternion myRotation = Quaternion.identity;
myRotation.eulerAngles = new Vector3(150f, 35f, 45f);
Debug.Log("我设置的角度: (150, 35, 45)");
Debug.Log("实际读取的角度: " + myRotation.eulerAngles);
<

192

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



