[转]Unity精华☀️二、到底是什么原因导致“万向锁”?旋转翻车的终极解析!

目录

🟥 万向锁现象

🟧 产生万向锁的应用场景

🟨 Inspector面板欧拉角的旋转

1️⃣ 绘制世界坐标系

2️⃣ 旋转测试

🚩 旋转Y轴

🚩 旋转x轴

🚩 旋转z值

🟩 自由度是怎样丢失的?


前几天跟大家说,面试时尴尬的名场面,

结果收到很多小老弟的留言,说是被说中了心声,心疼这些小老弟们。

那今天呢,咱来就来盘一盘面试时经常会问的一个问题:

什么是万向锁?

🟥 万向锁现象

我们认为,改变欧拉角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 控制骰子旋转,无法达到想要的角度的问题原因。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值