- 简介
四元数在电脑图形学中用于表示物体的旋转,在unity中由x,y,z,w 表示四个值。
四元数是最简单的超复数。 复数是由实数加上元素 i 组成,其中i^2 = -1 ,。 相似地,四元数都是由实数加上三个元素 i、j、k 组成,而且它们有如下的关系: i^2 = j^2 = k^2 = ijk = -1 , 每个四元数都是 1、i、j 和 k 的线性组合,即:四元数一般可表示为
a + bi + cj + dk 。
- 注视旋转
function LookRotation (forward : Vector3, upwards : Vector3 = Vector3.up) : void
传入的两个参数分别代表前方盯着的方向以及自己的上方向。它可以让一个GameObject转动脑袋盯着另一个物体。
向量加减法
public Transform cube; // 位于(0, 3, 0)的一个cube
public Vector3 target; // cube的朝向目标, 初始值为(0, 3, 0)
void Update()
{
// 注意, 此处Vector3.up并不一定与target - cube.position垂直
cube.rotation = Quaternion.LookRotation(target - cube.position, Vector3.up);
Debug.DrawLine(Vector3.zero, cube.forward, Color.blue); // 绘制每根轴
Debug.DrawLine(Vector3.zero, cube.right, Color.red);
Debug.DrawLine(Vector3.zero, cube.up, Color.green);
}
运行例子, 调整target的值, 可见Scene视图中, cube以及绘制出来的局部坐标轴也相应地发生了变化。
LookAt()与LookRotation()的参数都相似,但前者是将游戏对象的z轴指向参数所表示的那个点,而后者是将游戏对象的z轴指向参数所表示的向量的方向;
- 角
static function Angle (a : Quaternion, b : Quaternion) : float
返回a和b两者之间的角度。
public class example : MonoBehaviour {
public Transform target;
void Update() {
float angle = Quaternion.Angle(transform.rotation, target.rotation);
}
}
Vector3.Angle
public static float Angle(Vector3 from, Vector3 to);
由from和to两者返回一个角度。形象的说,from和to的连线和它们一个指定轴向的夹角。
把脚本放到小立方体上面,当小立方体和球体之间的夹角小于5度时关门
public class example : MonoBehaviour {
public Transform target; //球体
void Update() {
Vector3 targetDir = target.position - transform.position;
Vector3 forward = transform.forward;
float angle = Vector3.Angle(targetDir, forward);
if (angle < 5.0F)
print("close");
else
print("open");
}
}
- 欧拉角
static function Euler (x : float, y : float, z : float) : Quaternion
返回一个旋转角度,绕z轴旋转z度,绕x轴旋转x度,绕y轴旋转y度(像这样的顺序)。
public class example : MonoBehaviour {
public Quaternion rotation = Quaternion.Euler(0, 30, 0);
}
- 球形插值
static function Slerp (from : Quaternion, to : Quaternion, t : float) : Quaternion
球形插值,通过t值from向to之间插值。可以理解为速度,通常取值为0< t <= 1
public class example : MonoBehaviour {
public Transform from;
public Transform to;
public float speed = 0.1F;
void Update() {
//可以把 speed * Time.time 理解成速度 * 时间 等于角位移
transform.rotation = Quaternion.Slerp(from.rotation, to.rotation, Time.time * speed);
}
}
四元数旋转有个重要的特性就是:到达终止方向的旋转角度为旋转方向
例如起始位置为(0,0,0),绕Y轴旋转200度到(0,200,0),物体会顺时针旋转160度而不是逆时针旋转200度。
首先在场景中创建三个cube,from表示要转换之前的样子,to表示转换之后的样子,change表示转的效果。如下图所示:
其中from和change 开始运行之前的transform是一样的。to 的transform如下图所示:
然后我们创建一个脚本Quat.cs,如下:
public class Quat : MonoBehaviour {
public Transform from;
public Transform to;
private float rotSpeed = 5.0f;
void Update () {
if (Input.GetMouseButtonDown(0))
{
rotSpeed += 4;
transform.rotation = Quaternion.Slerp(from.rotation, to.rotation, rotSpeed*Time.deltaTime);
}
}
}
我们把该脚本赋change,并且把from和to拖到相应的手槽里。然后运行时,我们点击鼠标左键,可以看到change 慢慢旋转成to的角度。如下所示:
点一次插入一个值,偏移一点点,直到和to的角度一样。
当枪管转动起来,子弹仍然沿着正确的朝向发射出去。
Bullet_2 bullet
=m_compPool
.takeUnit
<Bullet_2
>();
//发射时,将子弹的初始位置为枪口的当前位置
bullet
.m_transform
.position
=m_transform
.position
;
//将子弹的初始化旋转设置为指向当前枪口前方
bullet
.m_transform
.rotation
=Quaternion
.LookRotation(m_transform
.forward
);
- 插值
在 a 和 b 之间插入 t,然后对结果进行标准化处理。参数 t 被限制在 [0, 1] 范围内。
该方法比 Slerp 快,但如果旋转相距很远,其视觉效果也更糟糕。
using UnityEngine;
using System.Collections;
public class ExampleClass : MonoBehaviour {
public Transform from;
public Transform to;
public float speed = 0.1F;
void Update() {
transform.rotation = Quaternion.Lerp(from.rotation, to.rotation, Time.time * speed);
}
}
- 恒等式旋转
返回恒等式旋转(只读)。这个四元数对于“无旋转”:这个物体完全对齐于世界或父轴。
public class example : MonoBehaviour {
public void Awake() {
transform.rotation = Quaternion.identity;
}
}