🟥 万向锁现象
我们认为,改变欧拉角x值,物体会绕着自身x轴旋转,改变y值,会绕着y旋转,z值同理(x)
但在某些情况下,unity物体并不会按照这个来,它会丢失一个自由度,比如下面情况:
当X轴角度为±90°时,
此时只有Z值是沿着自身Z轴旋转,且Y值旋转方向跟也是Z轴,丢失Y轴旋转自由度。
还比如这位博主讲的,丢失了一个自由度:传送门
这样的旋转,如果用改变Transform欧拉角来旋转,不一写一个错么
万向锁用专业术语讲就是:
万向锁,是在使用动态欧拉角表示三维物体的旋转时出现的问题。
在物体旋转中,物体丢失了一个旋转维度。
理不理解不重要,别人问就这样说!
🟧 产生万向锁的应用场景
比如骰子游戏:
不断旋转骰子,总会有机会使骰子旋转到万向锁角度,失去一个方向的自由度(x为90度+2π倍,此时改变y、z值,旋转方向相同)
若此时再使用动态欧拉角进行失去自由度方向的旋转,则注定不会起作用了。
🟨 Inspector面板欧拉角的旋转
为了解面板欧拉角的旋转,首先要先了解几个基础知识:
1、世界坐标系,是静态欧拉角,是不会变化的
2、物体本身坐标系,是动态欧拉角,会随着物体转动而转动
3、Unity官方提醒:
要仅使用物体的欧拉角来读取角度,并将其设置为固定值。不要增加它们。
因为当角度超过360度时会失败。应使用Transform.Rotate来执行旋转操作。
此处“角度超过360度时会失败”的理解是,Unity内部使用四元数去执行旋转,不会存储欧拉角的累计值,欧拉角只代表了等值的旋转变化结果,当旋转角度X超过360度时,存储的角度为X-360,例如,361度等同于1度。
同时,Unity API提醒我们不要单独设置一个欧拉角的参数(例如,Eulerangles.x=10;),这将导致错误的旋转,应当同时对x、y、z三个参数进行设置。
那么我们改变Unity物体层级面板上的欧拉角值,
物体绕的是世界坐标系旋转,还是物体本身坐标系旋转呢?
我们来测试看看:
1️⃣ 绘制世界坐标系
将下方脚本挂载在物体上,显示的就是不会变化的世界坐标系
方便我们观察。
using UnityEngine; public class WorldCoordinateSystem : MonoBehaviour { void OnDrawGizmos() { Gizmos.color = Color.red; Vector3 direction = Vector3.right * 2; //世界坐标系的 轴向x Gizmos.DrawRay(transform.position, direction); Gizmos.color = Color.green; direction = Vector3.up * 2; //世界坐标系的 轴向y Gizmos.DrawRay(transform.position, direction); Gizmos.color = Color.blue; direction = Vector3.forward * 2; //世界坐标系的 轴向z Gizmos.DrawRay(transform.position, direction); } }
现在下方显示的绿的长线,为Y轴,红色x、蓝色z。
2️⃣ 旋转测试
将模型调成Local模式,现在显示模型的自身坐标轴
将模型角度调成(45,45,45),方便我们测试观察:
好的,现在我们既能在视图中看到模型自身的坐标,也能看到不动的世界坐标。
现在就来转一下Inspector的欧拉角值,看看模型到底是绕着哪些轴旋转。
🚩 旋转Y轴
我们发现,旋转Y轴是绕着世界坐标系进行旋转的,并不是绕自身坐标系!
🚩 旋转x轴
为便于观察,将z值设为0。
我们发现:旋转x轴,是绕着自身坐标系旋转的,并不是绕着世界坐标系旋转!
现在就发现了,改变层级面板的值,竟然不是绕着同一个坐标系进行旋转?!
🚩 旋转z值
我们发现:旋转z值,是绕着自身坐标系旋转。
那我们现在来想一下:
如果绕着同一套坐标系旋转,肯定不会出现旋转面重合,共面现象
但绕着两套坐标轴旋转,肯定有机会出现旋转面共面情况,丢失一个旋转自由度啊!
丢失自由度后,可不就出现万向锁了么,怎么转都不按想要的方向来了。
有的小老弟可能用的不是上述角度,发现并不是按照上面说的轴旋转,那这是怎么回事呢?
首先了解:
unity 3D欧拉角的旋转顺序是:z-x-y
就是说,你所做的任何旋转,都受前面的角度影响。
比如你修改了Z值,那现在调整X值,肯定不会绕着自身坐标系x轴旋转。
但你新建一个父物体,将z值角度给父物体,自身z值为0,再旋转一下x,是不是就像预期一样啦?
🟩 自由度是怎样丢失的?
上面我们提到了,Unity的旋转顺序是:z-x-y,
这叫做Unity的顺归:传送门
物体旋转(x,y,z)度,是先旋转z轴,再旋转x轴,最后y轴。
那么,当x为90度时,物体z轴与世界坐标y轴同线,
y轴绕着世界坐标系y轴旋转,z轴绕着自身坐标系z轴旋转,一切都没问题,
但不管旋转y还是z,会发现只在一个平面上进行旋转,现在丢失了一个旋转方向,产生了万向锁。
若此时用 transform.localEulerAngles 去控制物体旋转,改变的是层级面板上的值,是无法转到想要的角度的
这也是 transform.localEulerAngles 控制骰子旋转,无法达到想要的角度的问题原因。
下一节,我们开始讲解怎样解决万向锁的四元数!