Unity在旋转时出现万向节锁的解决方案

关于万向节锁在Unity官方文档中有这样的描述:

欧拉角

在变换坐标中,Unity 使用矢量属性Transform.eulerAngles X、Y 和 Z 显示旋转。与法线矢量不同,这些值实际上表示绕 X、Y 和 Z 轴旋转的角度(以度为单位)。

欧拉角旋转围绕三个轴执行三个单独的旋转。Unity 依次围绕 z 轴、x 轴和 y 轴执行欧拉旋转。这种旋转方式就是外旋转;旋转发生时原始坐标系不会改变。

要旋转游戏对象,您可以在变换组件中输入您希望每个轴旋转多远的角度值。要使用脚本旋转游戏对象,请使用Transform.eulerAngles如果您转换为欧拉角来进行计算和旋转,则可能会出现万向节锁定问题。

万向节锁

当 3D 空间中的物体失去一定的自由度并且只能在二维空间内旋转时,称为万向节锁。如果两个轴平行,则欧拉角可能会发生万向节锁定。如果您不在脚本中将旋转值转换为欧拉角,则使用四元数应该可以防止万向节锁定。

如果您确实遇到万向节锁定问题,则在用于旋转时可以避免欧拉角Transform.RotateAround您还可以Quaternion.AngleAxis在每个轴上使用并将它们相乘(四元数乘法依次应用每个旋转)。

四元数

四元数为 3D 空间中空间方向和旋转的独特表示提供数学符号。四元数使用四个数字来编码 3D 中绕单位轴旋转的方向和角度。这四个值是复数而不是角度或度数。您可以研究四元数的数学以获取更多信息。

Unity 将旋转值转换为四元数来存储它们,因为四元数旋转计算高效且稳定。Unity 编辑器不会将旋转显示为四元数,因为单个四元数无法表示绕任何轴大于 360 度的旋转。

如果使用Quaternion类就可以直接使用四元数如果您使用脚本进行旋转,则可以使用四元数类和函数来创建和更改旋转值。您可以将值作为欧拉角应用于旋转,但需要将它们存储为四元数以避免出现问题。

具体的可以参考文档:Unity 中的旋转和方向(https://docs.unity3d.com/cn/current/Manual/QuaternionAndEulerRotationsInUnity.html)

 

所以尽量避免使用Transform.eulerAngles进行计算旋转,举个例子,鼠标控制相机的旋转你可能会这样写

    void CameraRotate(float speed)
    {
        Vector3 rot = transform.eulerAngles;
        rot.z = 0;
        rot.y -= Input.GetAxis("Mouse X") * speed * Time.deltaTime;
        rot.x += Input.GetAxis("Mouse Y") * speed * Time.deltaTime;
        transform.eulerAngles = rot;
    }

  

放到Update每帧调用时,你观察Inspector面板会发现在x轴接近90度时,z轴居然不是0,出现这种现象也就是上面所说的万向节锁

那么该怎么避免呢,官方文档也给出了方案,定义一个全局的Vector3,在Start的时候,给Vector3赋值:

    Vector3 currentEulerAngles;
    void Start()
    {
        currentEulerAngles = transform.eulerAngles;
    }
    void CameraRotate(float speed)
    {
        currentEulerAngles.z = 0;
        currentEulerAngles.y -= Input.GetAxis("Mouse X") * speed * Time.deltaTime;
        currentEulerAngles.x += Input.GetAxis("Mouse Y") * speed * Time.deltaTime;
        transform.eulerAngles = currentEulerAngles;
    }

  

这样通过累加currentEulerAngles就可以避免出现万向节锁,当然如果你想用Transform.Rotate之类的方法旋转也是可以的,

当时一定不要每帧都去获取transform.eulerAngles,而是定义一个全局的字段,去进行旋转计算赋值等操作

具体的文档可以参考:https://docs.unity3d.com/cn/current/ScriptReference/Transform-eulerAngles.html

https://docs.unity3d.com/cn/current/ScriptReference/Transform.Rotate.html

原创不易,如果觉得有用,留下你的足迹吧,你的鼓励我的动力

posted on 2024-03-27 12:11  Jason_c  阅读(210)  评论(0编辑  收藏  举报