Unity精华☀️到底是什么原因导致“万向锁”?旋转翻车的终极解析!
Posted 橙子SKODE
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Unity精华☀️到底是什么原因导致“万向锁”?旋转翻车的终极解析!相关的知识,希望对你有一定的参考价值。
哈喽大家好,你的橙哥突然出现~
本系列博客地址:传送门
前几天跟大家说,面试时尴尬的名场面,
结果收到很多小老弟的留言,说是被说中了心声,心疼这些小老弟们。
那今天呢,咱来就来盘一盘面试时经常会问的一个问题:
什么是万向锁?
一、万向锁现象
我们认为,改变欧拉角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的欧拉角值,看看模型到底是绕着哪些轴旋转。
1、旋转Y轴
我们发现,旋转Y轴是绕着世界坐标系进行旋转的,并不是绕自身坐标系!
2、旋转x轴
为便于观察,将z值设为0。
我们发现:旋转x轴,是绕着自身坐标系旋转的,并不是绕着世界坐标系旋转!
现在就发现了,改变层级面板的值,竟然不是绕着同一个坐标系进行旋转?!
3、旋转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 控制骰子旋转,无法达到想要的角度的问题原因。
下一节,我们开始讲解怎样解决万向锁的四元数!
国际惯例,一键三连走一波~
如果你有技术上的问题或困扰
可以随时给我发私信
和我聊一聊你的困扰🧡
以上是关于Unity精华☀️到底是什么原因导致“万向锁”?旋转翻车的终极解析!的主要内容,如果未能解决你的问题,请参考以下文章
Unity精华☀️ 哥哥,你会这么多「设计模式」,面试官会心疼你吧
Unity精华☀️ 哥哥,你会这么多「设计模式」,面试官会心疼你吧