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

概述

在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中的旋转和方向)