写在前面
阅读该文章之前,首先需要知道:
1.不同坐标系(世界坐标系、物体坐标系、惯性坐标系)之间的联系和区别;可参考博客坐标系详解
2.同一个物体基于不同的坐标系进行旋转所得结果不一样;

本文的目的是探究游戏引擎Unity3D不同的旋转API的表现,我们都知道,在Unity3D中有多种刚体旋转的API:①有对localRotation进行赋值修改的方式达到旋转的目的;②有通过Rotate方法(Space.Self)进行旋转的;③对应还有通过Rotate方法(Space.World)进行旋转的。按照网上一些教程的解释,①就是在父节点坐标系下进行旋转,②和③则分别是绕物体坐标系和世界坐标系的轴进行旋转。

在理解世界坐标系、物体坐标系和惯性坐标系的基础上,非常有必要明确各个API定义的刚体旋转到底是如何进行的,是基于世界坐标系还是基于世界坐标系平移之后的惯性坐标系;基于父节点的局部坐标系进行旋转,是否需要将父节点的物体坐标系平移到本物体坐标系原点之后再进行旋转。

这部分的内容在其他的博客或者资料中是没有详细讲解的,通常默认大家是已知的,但是这种不明确容易造成对API理解不深而使用错误的情况。这篇博客主要探究这部分的问题。

(一)Unity 3D绕轴旋转

本文之后的示例都将使用下图中的实例,以研究小臂这一段刚体为代表,去研究刚体在Unity中的旋转。

值得注意的是,人体关节刚体与普通的几何物体刚体在物体坐标系上有一定的差别。常见的几何刚体(例如立方体,球体,圆柱体)的物体坐标系的原点都在几何刚体的中心点,而人体关节刚体的物体坐标系原点一般在关节的某一端。例如,小臂关节的物体坐标系的原点就在肘关节,大臂关节的物体坐标系的原点在肩关节附近。

此处选用物体坐标系原点位于物体某一端点的例子去讨论,更加直观。

Unity UI坐标转化世界坐标 unity 以自定义坐标系旋转_Unity 3D

1.transform.localRotation属性控制刚体旋转

API手册中Description 描述
The rotation of the transform relative to the parent transform’s rotation.
该变换的旋转角度相对于父级变换的旋转角度。
·
Unity stores rotations as Quaternions internally. To rotate an object, use Transform.Rotate. Use Transform.localEulerAngles for modifying the rotation as euler angles.
Untiy使用四元数来存储旋转角度。要旋转一个物体,可以使用Transform.Rotate,也可以使用Transform.localEulerAngles为设置作为欧拉角的旋转角度。

这个API解释对不熟悉Unity3D和图形学的同学来说,看到就会觉得什么都说了,什么都没说。看懂了也不太会用。下面来做具体的测试看看到底这个API是怎么在父坐标系下控制刚体旋转的。

通过以下代码控制人物:

GameObject upperarm_l;
    GameObject lowerarm_l;
    public float Local_X =0.0f;
    public float Local_Y = 0.0f;
    public float Local_Z = 30.0f;

    // Use this for initialization
    void Start () {
        upperarm_l = GameObject.Find("upperarm_l");
        lowerarm_l = GameObject.Find("lowerarm_l"); 
    }

    // Update is called once per frame
    void Update () {
        lowerarm_l.transform.localRotation = Quaternion.Euler(Local_X, Local_Y, Local_Z);
    }
}

Unity UI坐标转化世界坐标 unity 以自定义坐标系旋转_世界坐标系_02


从图中可以看出结论,rotation of the transform relative to the parent transform's rotation的意思就是子物体的物体坐标系相对于平移之后父物体物体坐标系之间的旋转角度。读起来可以很绕,解释以下主要是两个点。首先,父物体的物体坐标系要平移,使得父子两个物体坐标系的坐标原点重合;然后,旋转rotation是父子两个物体坐标系之间的关系,也就是说,欧拉角(或者四元数)描述的是如何旋转父物体坐标系,会使得其与子物体坐标系重合。以上就是API手册中英文解释的全部意思。

当然,把父物体的坐标系作为参考系,localRotation这个属性也描述了子物体坐标系的旋转角度。所以,通过给这个属性赋值,可以达到控制刚体旋转的目的。

2.transform.Rotate()中的Space.Self和Space.World

transform.Rotate是正儿八经用来控制刚体旋转的方法,其参数除了欧拉角之外,还有一个可选参数Space.Self/Space.World,默认是前者。在API手册中对这两个的解释也不是特别清晰。下面我们来进行简单的梳理和理解。
下面两张图片载自大佬博客,可以通过看图直观理解Space.Self和Space.World的区别和联系。联系就是两者都是将自身的物体坐标系进行旋转。区别在于旋转的参考系不一样。前者(Space.Self)的参考系是旋转前一刹那时的自身物体坐标系;而后者(Space.World)是评议之后的世界坐标系。此处注意仍然是平移之后的世界坐标系(经过平移,与物体坐标系坐标原点重合的世界坐标系又称惯性坐标系),不懂可以参考博客坐标系详解

左图和右图都是绕Y轴进行旋转。左图是Space.Self参数控制下的情况,可以看到圆柱体是绕本地坐标系的Y轴进行旋转的。右图是Space.World参数控制下的情况,可以看出圆柱体是绕惯性坐标系(平移之后的世界坐标系)进行旋转的。

Unity UI坐标转化世界坐标 unity 以自定义坐标系旋转_Unity 3D_03

Unity UI坐标转化世界坐标 unity 以自定义坐标系旋转_刚体旋转_04

(二)结论总述

1.在Unity 3D中控制刚体旋转的主要方法可以分为三个类别:①以父物体的物体坐标系为参考系进行旋转;②以世界坐标系为参考系进行旋转;③以自身物体坐标系为参考系进行旋转。当然还有绕点旋转和绕轴旋转,这些此处暂不讨论。

2.不论是以哪一个坐标系为参考系进行旋转,都需要在旋转之前把参照系平移,使得参照系与带旋转物体的物体坐标系坐标原点重合

3.旋转的欧拉角是两个坐标系之间的旋转角度,具体来说就是将参照系旋转到和物体坐标系重合需要的欧拉角。