欧拉角
使用物体在三个旋转轴上的旋转角度来保存方位
API:
Transform.eulerAngles:返回或设置物体的欧拉角
优点:
1.仅使用三个数字表达方位,占用空间小
2.沿坐标轴旋转的单位为角度,符合人的思考方式
3.任意三个数字都是合法的,不存在不合法的欧拉角
缺点:
1.方位的表达方式不唯一:对于一个方位,存在多个欧拉角描述,因此无法判断多个欧拉角代表的角位移是否相同
例如:
- 角度(0,5,0)与角度(0,365,0)
- 角度(0,-5,0)与角度(0,355,0)
- 角度(250,0,0)与角度(290,180,180)
为了保证任意方位都只有独一无二的表示,Unity引擎限制了角度范围,即沿X轴旋转限制在-90~90之间,沿Y与Z轴旋转限制在0~360之间
2.万向节死锁:
- 物体沿X轴旋转±90度,自身坐标系Z轴与世界坐标系Y轴将重合,此时再沿Y或Z轴旋转时,将失去一个自由度
- 在万向节死锁情况下,规定沿Y轴完成绕竖直轴的全部旋转,即此时Z轴旋转为0
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EulerDemo : MonoBehaviour
{
private void OnGUI()
{
if (GUILayout.RepeatButton("沿x轴旋转"))
{
Vector3 pos = this.transform.position;
//有方向(从世界原点指向当前位置),有大小(当前位置到世界原点的间距)
//向量x,y,z,表示各个轴向上的有向位移
Vector3 euler = this.transform.eulerAngles;
//是向量类型,但没有方向和大小
//欧拉角x,y,z表示各个轴上的旋转角度
//各分量相加,欧拉角x增加1度
this.transform.eulerAngles += new Vector3(1, 0, 0);
}
if (GUILayout.RepeatButton("沿y轴旋转"))
{
//this.transform.eulerAngles+=new Vector3(0,1,0);
this.transform.eulerAngles += Vector3.up;
}
if (GUILayout.RepeatButton("沿z轴旋转"))
{
this.transform.eulerAngles += new Vector3(0, 0, 1);
this.transform.eulerAngles += Vector3.forward;
}
}
}
四元数
Quaternion在3D图形学中代表旋转,由一个三维向量(X/Y/Z)和一个标量(W)组成
旋转轴为V,旋转弧度为0,如果使用四元数表示,则四个分量为:
- x=sin(0/2)*V.x
- y=sin(0 /2)*V.y
- z=sin(0 /2)*V.z
- w=cos(0 /2)
X、Y、Z、W的取值范围是-1~1
//旋转轴
Vector3 axis = Vector3.up;
//旋转弧度
float rad = 50 * Mathf.Deg2Rad;
Quaternion qt = new Quaternion();
qt.x = Mathf.Sin(rad / 2) * axis.x;
qt.y = Mathf.Sin(rad / 2) * axis.y;
qt.z = Mathf.Sin(rad / 2) * axis.z;
qt.w = Mathf.Cos(rad / 2);
this.transform.rotation = qt;
以上代码可简化为
//旋转轴
Vector3 axis = Vector3.up;
//旋转弧度
float rad = 50 * Mathf.Deg2Rad;
this.transform.rotation = Quaternion.Euler(0, 50, 0);
API:
Quaternion.Euler(float x, float y, float z): 返回一个围绕z轴旋转z度、围绕x轴旋转 x度、围绕y轴旋转y度(按该顺序应用)的旋转
private void OnGUI()
{
if (GUILayout.Button("沿x轴旋转"))
{
this.transform.rotation *= Quaternion.Euler(1, 0, 0);
//this.transform.Rotate(1, 0, 0);
}
if (GUILayout.Button("沿y轴旋转"))
{
this.transform.rotation *= Quaternion.Euler(0, 1, 0);
}
if (GUILayout.Button("沿z轴旋转"))
{
this.transform.rotation *= Quaternion.Euler(0, 0, 1);
}
}
其中
this.transform.rotation *= Quaternion.Euler(1, 0, 0);
等同于
this.transform.Rotate(1, 0, 0);
优点:避免万向节死锁
缺点:
- 难于使用,不建议单独修改某个数值
- 存在不合法的四元数
基本运算
1.与向量相乘:四元数左乘向量,表示将该向量按照四元数表示的角度旋转
Vector3 point = new Vector3(0, 0, 10);
Vector3 newPoint = Quaternion.Euler(0, 30, 0) * point;
2.与四元数相乘:两个四元数相乘可以组合旋转效果
Quaternion rotation01 = Quaternion.Euler(0, 30, 0) * Quaternion.Euler(0, 20, 0);
等同于
Quaternion rotation02 = Quaternion.Euler(0, 50, 0);
常用API
Quaternion.LookRotation(Vector3 forward, Vector3 upwards= Vector3.up) :
forward | 要查看的方向 |
upwards | 定义向上方向的向量 |
原理:Z轴将与forward对齐,X轴与forward和upwards之间的交叉乘积对齐,Y轴与Z和X之间的交叉乘积对齐
public Transform target;
//当前物体注视target旋转
Vector3 dir = target.position - this.transform.position;
this.transform.rotation = Quaternion.LookRotation(dir);
//this.transform.LookAt(target);
Quaternion.Lerp(Quaternion a, Quaternion b, float t):
a | 起始值,当 t = 0 时返回 |
b | 结束值,当 t = 1 时返回 |
t | 插值比率 |
public Transform target;
//差值旋转
Quaternion dir = Quaternion.LookRotation(target.position - this.transform.position);
this.transform.rotation = Quaternion.Lerp(this.transform.rotation, dir, 0.1f);
if (Quaternion.Angle(this.transform.rotation, dir) < 0.1f)
{
this.transform.rotation = dir;
}
Quaternion.FromToRotation(Vector3 fromDirection, Vector3 toDirection) :创建一个从fromDirection旋转到toDirection的旋转
public Transform target;
//x轴注视旋转
//this.transform.right = target.position - this.transform.position;
Quaternion dir = Quaternion.FromToRotation(Vector3.right, target.position - this.transform.position);
this.transform.rotation = dir;
Quaternion.AngleAxis(float angle, Vector3 axis):创建一个围绕axis旋转angle度的旋转
public Transform target;
//轴/角旋转
this.transform.rotation = Quaternion.AngleAxis(50, Vector3.up);