一、Unity中的Rotation
在unity中,旋转的表示的常用方法之一,是一个三维向量(x、y、z):
图1、Unity中的旋转
实际上这是欧拉角。这三个分量分别是绕x轴、y轴、z轴旋转的角度。
要对一个object进行旋转,还可以通过代码:
transform.Rotate(x, y, z);
这里,如果看过《坐标系》一文,就会产生以下两个疑问:
1)x轴、y轴、z轴指的是那组基?是世界坐标系下的xyz轴,还是本地坐标系下的xyz轴?
2)旋转的正方向是如何确定的?
下面分别讨论。
二、旋转轴:静态欧拉角和动态欧拉角
首先回答第一个问题:到底哪个是旋转轴。这又要分为 3种情况。
1、旋转轴:Editor 中 Transform的旋转数值
对这个情况来说,其显示的旋转轴既不是世界坐标系的坐标轴,也不是本地坐标系的坐标轴。Editor中transform的旋转轴是父节点的坐标轴。这点在editor中看的非常明显,因此不再赘述。
2、旋转轴:在script中使用 rotate 函数,在 Space.Self 中旋转
Rotate 函数有两个入参:
public void Rotate(Vector3 eulerAngles, Space relativeTo = Space.Self);
第二个入参的取值有两种:Space.Self 或者 Space.World。我们先看默认的 Self 的情况。使用下面的一段简单的代码来进行测试:
public class TestRotate : MonoBehaviour {
public Space rotateSpace;
// Update is called once per frame
void Update () {
if (Input.GetKeyDown(KeyCode.R))
transform.Rotate(new Vector3(0, 10, 0), rotateSpace);
}
}
场景中进行测试的是一个圆柱体,其父节点的旋转为(30,30,0),圆柱体初始的旋转为(30,0,0),每次按下R键,就会在Space.Self 下绕 Y轴旋转10度,则结果为:
图2、在Space.Self中旋转
可以看到,圆柱体是绕着本地坐标系的Y轴旋转的。使用Space.Self进行旋转,旋转轴就是本地坐标系的坐标轴。
3、在script中使用 rotate 函数,在 Space.World 中旋转
下面测试 Space.World
图3、在Space.World中旋转
注意到这里 Parent 的 Y轴并不是 world 的 Y 轴,而这里的圆柱体明显是绕着世界坐标系下的 Y 轴旋转的,所以如代码所述,使用Space.World旋转,旋转是绕着世界坐标系的坐标轴旋转的。
4、静态欧拉角和动态欧拉角
前面说到的旋转轴的问题,在数学上有对应的概念。这就是所谓的静态欧拉角和动态欧拉角。
所谓静态欧拉角,就是其旋转轴使用的是静止不动的参考系。动态欧拉角,使用的是刚体本身作为参考系,因而会随着刚体的旋转而旋转。
因此,再看看前面的三种情况,使用Space.World旋转,以及 Editor 中的旋转,是静态欧拉角;使用Space.self,是动态欧拉角。
代码示例:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TestRotate : MonoBehaviour {
private bool isTransRotate; //绕父部件旋转
private bool isSelfRotate; //绕自身旋转
private bool isWorldRotate; //绕世界坐标系旋转
private string transRotateInfo;
private string selfRotateInfo;
private string worldRotateInfo;
public float speed;
private GameObject objCylinder;
// Use this for initialization
void Start () {
isTransRotate = false;
isSelfRotate = false;
isWorldRotate = false;
transRotateInfo = "绕圆柱体旋转";
selfRotateInfo = "绕自身旋转";
worldRotateInfo = "绕世界坐标系旋转";
speed = 200;
objCylinder = GameObject.Find("Cylinder");
}
// Update is called once per frame
void Update () {
if (isTransRotate) {
//gameObject.transform.Rotate(0,Time.deltaTime*speed,0);
//gameObject.transform.Rotate(Vector3.up* Time.deltaTime * speed);
gameObject.transform.RotateAround(objCylinder.transform.position, Vector3.up, Time.deltaTime * speed);
}
if (isSelfRotate) {
gameObject.transform.Rotate(new Vector3(0,10,0), Time.deltaTime * speed, Space.Self);
}
if (isWorldRotate) {
gameObject.transform.Rotate(new Vector3(0,10,0), Time.deltaTime * speed,Space.World);
}
}
private void OnGUI()
{
if (GUILayout.Button(transRotateInfo, GUILayout.Height(50))) {
if (!isTransRotate)
{
isTransRotate = true;
transRotateInfo = "停止绕圆柱体旋转";
}
else {
isTransRotate = false;
transRotateInfo = "绕圆柱体旋转";
}
}
if (GUILayout.Button(selfRotateInfo, GUILayout.Height(50)))
{
if (!isSelfRotate)
{
isSelfRotate = true;
selfRotateInfo = "停止绕自身旋转";
}
else
{
isSelfRotate = false;
selfRotateInfo = "绕自身旋转";
}
}
if (GUILayout.Button(worldRotateInfo, GUILayout.Height(50)))
{
if (!isWorldRotate)
{
isWorldRotate = true;
worldRotateInfo = "停止绕世界坐标系旋转";
}
else
{
isWorldRotate = false;
worldRotateInfo = "绕世界坐标系旋转";
}
}
}
}