翻译-在Unity3D中的旋转和方向

作者: 三梦子 | 来源:发表于2017-07-13 16:02 被阅读1197次

    概述

    在3D软件中旋转通常用四元数或者欧拉角来表示,各有优缺点。Unity内部存储使用四元数,但是为了方便我们编辑,在面板上显示成对应的欧拉角的值。

    Euler Angles 欧拉角

    欧拉角简单的理解就是有三个角度X,Y,Z,然后按顺序在对应的轴上进行旋转,最后物体的方向就是这个欧拉角。

    • 优点:容易直观的理解值的意义
    • 缺点:会导致万向节锁。我理解是,当依次旋转时,会出现有个轴无法旋转,即旋转失效 ,详细可查看

    Quaternions 四元数

    四元数也可以用来表示物体的旋转或者方向,顾名思义,是由四个数组成,在Unity3D中是x,y,z,w。不过,这些数字并不是表示角度和旋转轴,而且你绝不会直接使用它们。除非你特别想知道四元数的原理,否则仅仅知道它在3D世界中表示旋转即可,完全不用理解这四个数的意义或者尝试修改它。如果你确实想了解四元数的前世今生,详细可查看,作者写的特别详细。

    好比一个Vector(矢量)可以表达位置或者方向(从坐标原点看),一个四元数也可以同时表示指向或者旋转角度(从世界坐标系的原点或者特定坐标系的原点作为参考点)。因为旋转是这么计算的-从一个方向到另一个方向,所以一个四元数无法表示一个超过180度的旋转。

    • 优点:无万向节锁
    • 缺点:单一四元数无法表示任何方向上超过180度的旋转
    • 缺点:四元数的四个数字无法直观的理解

    权衡利弊后,在Unity里,所有游戏物体旋转状态都是以四元数的方式存储的

    不过在Transform的面板中,还是用欧拉角的方式展示数据,因为这种方式还是更易于理解和编辑。每当输入一个旋转的值,都会在后台被转存为一个新的四元数。

    副作用就是,有可能在旋转面板上输入“X: 0, Y: 365, Z: 0”。这个欧拉角不可能以四元数来表示,所以当你点击"Play",你会看到面板上的值变成了" X: 0, Y: 5, Z: 0 "(左右)。这是因为365度是无法用四元数表示的,所以简单的用前面的结果取代了它。

    脚本相关

    当你在脚本中处理旋转时,你应该用到Quaternion类以及它的方法去创建和修改旋转相关的参数。有一些场景需要合理的使用欧拉角,但是你要记住:你应该使用Quaternion类以及方法去处理欧拉角,获取,修改和重复使用欧拉值会出现无意的副作用。

    直接创建和操作四元数

    Unity的Quaternion类有许多创建和操作旋转的方法,这些完全不必用到欧拉角。比如:

    • 创建
      1. Quaternion.LookRotation
      2. Quaternion.AngleAxis
      3. Quaternion.FromToRotation
    • Manipulating:
      1. Quaternion.Slerp
      2. Quaternion.Inverse
      3. Quaternion.RotateTowards
      4. Transform.Rotate & Transform.RotateAround

    不过,有时在你的脚本里使用欧拉角时合适的。但是需要格外留心的是,用新的变量保存角度,仅仅在需要改变物体旋转时使用下欧拉角。同时也有可能从四元数里获取当前的欧拉角,当你获取,修改,重使用欧拉角时,问题就出现了。因为值会在转化成四元数时会进行角度的变化。比如360度和0度之类。。。
    以下是一些错误事例,假设每秒钟让一个物体绕X轴旋转10度。这是是我们需要避免的:

    1. 错误一
      直接修改Quaternion的x值,但是这个值并不是表示角度,所以就不会产生预期的结果
        void Update () {
        
            var rot = transform.rotation;
            rot.x += Time.deltaTime * 10;
            transform.rotation = rot;
            
        }
    
    1. 错误二
      读、写和修改一个Quaternion中的欧拉值.因为这些值都是从Quaternion中计算得出,所以每一次新的旋转可能会产生极不相同的欧拉角,这有可能引发万向节锁。
        void Update () {
            
            var angles = transform.rotation.eulerAngles;
            angles.x += Time.deltaTime * 10;
            transform.rotation = Quaternion.Euler(angles);
    
        }
    
    1. 正确示例
      正确的在脚本中使用欧拉角进行旋转。我们使用一个类成员变量存储了当前的欧拉角,并且只在赋值给Quaternion时使用,并且不会从Quaternion中读取这个值。
        float x;
        void Update () {
            
            x += Time.deltaTime * 10;
            transform.rotation = Quaternion.Euler(x,0,0);
    
        }
    

    相关文章

      网友评论

        本文标题:翻译-在Unity3D中的旋转和方向

        本文链接:https://www.haomeiwen.com/subject/itowhxtx.html