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精华☀️ 哥哥,你会这么多「设计模式」,面试官会心疼你吧

Unity--------------------万向锁的概念

简单研究Unity中的万向锁和欧拉角以及四元数

四元数到达万向节锁

简单的研究了一下Unity的万向锁问题