我之前研读了一些关于unity旋转相关的博客,一直想抽个时间写个总结,但是由于实习太忙一直没有写,趁着今天请了假晚上有时间把这段时间一些学习心得写出来。
Unity inspector面板中的Rotation
在unity中,想必大家最先接触到的关于旋转的知识便是inspector面板中的Rotation属性。有人问,关于这个物体的Rotation属性还有什么好学的吗?他的X,Y,Z属性不就是关于绕着父节点的X轴、Y轴、Z轴旋转的角度吗?
确实,Rotation属性代表物体旋转的欧拉角,只是在面板上随便改变物体的Rotation属性是一件非常简单的事情。但是当你在改变物体Rotation的X值为90度时候,去调整Y和Z的值,就会发生一些非常有意思的事情。
比如下面的三个图:
(图1)
(图2)
(图3)
图二非常好理解,模型的欧拉角为(90,90,0),代表着物体沿着X轴向前旋转了90度,然后再沿着Y轴向左旋转了90度。
但是为什么图三并没有按着我们想象中的沿着X轴向前旋转了90度,然后在沿着Z轴旋转了90度呢?而是最终和图二中模型的方向一样呢。
其实这就涉及到了物体旋转以什么坐标系的坐标轴按什么样的顺序进行旋转以及传说中的万向锁问题。
Unity旋转中的坐标系以及旋转顺序
对于一个物体而言,与相关的坐标系有两个,第一个便是世界坐标系,第二个则是它自身的本地坐标系。
在最初始的状态下,两个坐标系的坐标轴是相对应的。
(图4)
当旋转物体后,物体自身的本地坐标系会进行相应的旋转。
(图5)
既然提到了坐标系,那么也要在这里提一句,Unity中的世界坐标系和本地坐标系都是左手坐标系,在旋转的时候都遵循左手定则,即将大拇指指向旋转轴正向,握拳方向即为旋转方向。
(图6)
我们首先以静态欧拉角(以世界坐标系进行旋转)的角度来探索这个问题,使物体沿着世界坐标系进行旋转。下面的一段代码来探究一下物体旋转顺序对于物体最终朝向的影响。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ModelRotate : MonoBehaviour {
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
}
private void OnGUI()
{
if (GUI.Button (new Rect (0, 10, 200, 100), "沿X轴旋转90度"))
transform.Rotate (new Vector3 (90, 0, 0), Space.World);
if(GUI.Button(new Rect(0,150,200,100), "沿Y轴旋转90度"))
transform.Rotate(new Vector3(0,90,0),Space.World);
if(GUI.Button(new Rect(0,300,200,100), "恢复原状"))
transform.rotation=Quaternion.identity;
}
}
(图7)
如果物体先沿世界坐标系X轴旋转90度,再沿世界坐标系Y轴旋转90度,则结果如图8所示:
(图8)
如果物体先沿世界坐标系Y轴旋转90度,再沿世界坐标系X轴旋转90度,则结果如图9所示:
(图9)
可以观察到图8、图9物体最终旋转的结果不一样,这是因为旋转实际上是通过乘以变化矩阵实现的,而矩阵乘法不满足交换律,旋转的顺序不能交换。在Unity中,物体旋转的顺序是Z-X-Y顺规,即先旋转Z轴,再旋转X轴,再旋转Y轴。所以图2的结果对应图8。
对于动态欧拉角来说(即以自身坐标系进行旋转),同样存在着不能交换旋转方向的顺序的情况。每次使用Space.self进行旋转时,都是以此时刻的坐标轴进行旋转。
对于静态欧拉角和动态欧拉角而言,在Space.World中旋转以 Z-X-Y 归顺旋转角度(x、y、z),等价于在Space.Self中分别顺次旋转(0,y,0)、(x,0,0)、(0,0,z)。
万向锁问题
我们了解Unity中欧拉角以及相关坐标系的知识后,我们可以回来探索为什么会出现图2和图3中的情况。
在Unity的Inspector中,旋转采用的是静态欧拉角,为什么对于旋转X轴和Z轴的图3会出现不符合想象中的情况呢?
前面提到过静态欧拉角下旋转顺规是Z-X-Y,等同于动态欧拉角下Y-X-Z顺规,如果将物体沿着X轴旋转90的度,此时如图10所示,本地坐标系下Z轴与世界坐标系下Y轴重合(方向相反),所以最后导致了图3的情况。
对于规划中间的坐标轴旋转90度的话,就会出现万向锁问题,如例子中的X轴。为了避免出现万向锁问题,应该采用四元数进行旋转,这样可以完全解决万向锁问题,如果有时间,我会再写一篇博客总结下这段时间关于四元数的学习。