Unity入门学习(四)3D数学(4)之四元数Quaternion

发布于:2025-05-21 ⋅ 阅读:(23) ⋅ 点赞:(0)

目录

一、什么是四元数

二、和欧拉角的关联以及为什么会出现四元数

三、四元数的基本组成

Unity中的表示:

四、四元数Quaternion这个类中具有的属性和方法

常用属性

核心方法

五、四元数之间的计算

1. 叉乘(组合旋转)

2. 点积(相似度)

六、总结

四元数 Quaternion 属性与方法总结

详细说明

1. 属性

2. 方法

3. 运算符与静态方法


一、什么是四元数

定义
        四元数(Quaternion)是一种数学工具,用于表示三维空间中的旋转。它由四个分量组成:一个实部(w)和三个虚部(x, y, z),数学表达式为:
                                        q=w+xi+yj+zk
其中 

                                i^{2} + j^{2} + k^{2} = ijk = -1

        你可以想象四元数是一个“方向标记”,而欧拉角是“分解成三个步骤的转动角度”。四元数通过一种紧凑的数学形式直接描述方向,避免了欧拉角的分步旋转可能导致的万向节死锁问题。

Unity中的应用        
        在Unity中,所有Transform组件的旋转底层均由四元数实现。虽然开发者通常通过欧拉角(如Inspector面板中的Rotation)调整物体朝向,但Unity会自动将其转换为四元数存储。

二、和欧拉角的关联以及为什么会出现四元数

欧拉角的局限性
        万向节死锁(Gimbal Lock):当绕某一轴旋转90度时,另外两个轴的旋转会重合,导致丢失一个自由度。就是说当你转到90度时,你想单独再沿着某一条轴进行旋转,发现怎么都不可以
例如:飞机俯仰90度后,偏航和滚转将绕同一轴旋转,无法独立控制。
插值不平滑:直接对欧拉角插值会导致旋转路径不自然(如抖动或突变)。

四元数的优势
无万向节死锁:四元数通过四维空间描述旋转,避免了三维欧拉角的轴顺序问题。
平滑插值:支持球面线性插值(Slerp),保证旋转路径的最短性和平滑性。
计算高效:旋转合成和逆运算更高效,适合实时计算。

关联
转换关系:欧拉角可通过Quaternion.Euler()转换为四元数,反之通过Quaternion.eulerAngles属性获取。
 

三、四元数的基本组成

四元数构成
一个四元数包含一个标量和一个3D向量
[w,v],w为标量,v为3D向量
[w,(x,y,z)]
对于给定的任意的一个四元数:
表示3D空间中的一个旋转量

轴-角对
在3D空间中 任意旋转都可以表示 绕着某个轴旋转一个旋转角得到

注意:该轴并不是空间中的xyz中轴 而是任意一个轴
对于给定旋转 假设为绕着n轴 旋转β角度 n轴为(x,y,z)
那么可以构成的四元数为:
四元数Q = [cos(β/2),sin(β/2)n]
四元数Q = [cos(β/2,sin(β/2)x,sin(β/2)y,sin(β/2)z]

四元数Q则表示绕着轴n,旋转β度的旋转量

单位四元数
单位四元数表示没有旋转量(角位移)
当角度为0或者360度时
对于给定的轴都会得到单位四元数

[1,(0,0,0)]和[-1,(0,0,0)]都是单位四元数
表示没有旋转量

Unity中的表示:

Quaternion q = new Quaternion(x, y, z, w);
// 注意:Unity的构造函数参数顺序为(x, y, z, w)

例如:绕Y轴旋转90度的四元数:

Quaternion rotation = Quaternion.Euler(0, 90, 0);
// 等效于手动计算:
float angle = 90 * Mathf.Deg2Rad;
Quaternion q = new Quaternion(0, Mathf.Sin(angle/2), 0, Mathf.Cos(angle/2));

四、四元数Quaternion这个类中具有的属性和方法

常用属性
属性 说明
identity 单位四元数(无旋转)。
eulerAngles 转换为欧拉角(只读)。
核心方法
方法 说明 示例
AngleAxis 创建绕指定轴旋转角度的四元数。 Quaternion.AngleAxis(90, Vector3.up)
Euler 将欧拉角转换为四元数。 Quaternion.Euler(0, 90, 0)
Slerp 球面线性插值(平滑旋转)。 Quaternion.Slerp(a, b, t)
Lerp 线性插值(速度更快,但路径非最短)。 Quaternion.Lerp(a, b, t)
Inverse 返回反向旋转的四元数。 Quaternion.Inverse(rotation)
LookRotation 生成朝向某个方向的旋转。 Quaternion.LookRotation(direction)

详细解释:

属性:

(1)identity:单位四元数(无旋转)
表示“不旋转”的状态,常用于初始化旋转或重置物体方向。

using UnityEngine;

public class QuaternionExample : MonoBehaviour
{
    void Start()
    {
        // 将物体旋转重置为初始状态(无旋转)
        transform.rotation = Quaternion.identity;
    }
}


(2)eulerAngles:将四元数转换为欧拉角
返回当前四元数对应的欧拉角(只读属性),常用于调试或显示直观角度。

using UnityEngine;

public class QuaternionExample : MonoBehaviour
{
    void Update()
    {
        // 实时输出物体的欧拉角
        Debug.Log("当前欧拉角:" + transform.rotation.eulerAngles);
        
        // 注意:直接修改 eulerAngles 可能导致问题,应通过 Quaternion.Euler() 设置
        // transform.eulerAngles = new Vector3(0, 90, 0); // 不推荐
    }
}

方法:

(1) AngleAxis:绕指定轴旋转指定角度
创建绕某个轴旋转一定角度的四元数,常用于自由轴旋转。

using UnityEngine;

public class QuaternionExample : MonoBehaviour
{
    public float rotateSpeed = 90f; // 每秒旋转90度

    void Update()
    {
        // 绕Y轴旋转(按每秒 rotateSpeed 度旋转)
        float angle = rotateSpeed * Time.deltaTime;
        Quaternion rotation = Quaternion.AngleAxis(angle, Vector3.up);
        transform.rotation = rotation * transform.rotation;
    }
}

(2) Euler:欧拉角转四元数
将欧拉角转换为四元数,避免直接操作 eulerAngles 导致的问题。

using UnityEngine;

public class QuaternionExample : MonoBehaviour
{
    void Start()
    {
        // 设置物体绕Y轴旋转90度
        Quaternion targetRotation = Quaternion.Euler(0, 90, 0);
        transform.rotation = targetRotation;
    }
}

(3) Slerp:球面线性插值
沿球面最短路径平滑插值,适合摄像机跟踪或自然旋转。

using UnityEngine;

public class QuaternionExample : MonoBehaviour
{
    public Transform target; // 拖入目标物体
    public float speed = 0.5f;

    void Update()
    {
        // 计算目标方向
        Vector3 direction = target.position - transform.position;
        Quaternion targetRotation = Quaternion.LookRotation(direction);
        
        // 使用Slerp平滑旋转
        transform.rotation = Quaternion.Slerp(
            transform.rotation, 
            targetRotation, 
            speed * Time.deltaTime
        );
    }
}
//先快后慢
//A.rotation = Quaternion.Slerp(A.rotation,target.rotation,Time.deltaTime);

//匀速变化
//time += Time.deltaTime;
//B.rotation = Quaternion.Slerp(start,target.rotation,time);

效果:物体会平滑转向目标物体,路径无抖动。 

(4) Lerp:线性插值
快速插值但路径非最短,适合对平滑性要求不高的场景。

using UnityEngine;

public class QuaternionExample : MonoBehaviour
{
    public Transform target;
    public float speed = 1f;

    void Update()
    {
        Quaternion targetRotation = Quaternion.LookRotation(target.position - transform.position);
        transform.rotation = Quaternion.Lerp(
            transform.rotation, 
            targetRotation, 
            speed * Time.deltaTime
        );
    }
}

(5) Inverse:反向旋转
获取当前旋转的逆旋转,常用于坐标系转换或相对旋转。

using UnityEngine;

public class QuaternionExample : MonoBehaviour
{
    public Transform otherObject;

    void Update()
    {
        // 计算当前旋转的逆旋转
        Quaternion inverseRotation = Quaternion.Inverse(transform.rotation);
        
        // 将另一个物体的旋转设置为当前物体的逆旋转
        otherObject.rotation = inverseRotation;
    }
}

效果otherObject 会始终与当前物体保持反向旋转。 

(6) LookRotation:朝向某个方向
使物体正面朝向指定方向,常用于控制角色或摄像机。

using UnityEngine;

public class QuaternionExample : MonoBehaviour
{
    public Vector3 targetDirection = Vector3.forward; // 默认朝前

    void Update()
    {
        // 动态让物体朝向 targetDirection 方向
        Quaternion targetRotation = Quaternion.LookRotation(targetDirection);
        transform.rotation = targetRotation;
    }
}

效果:物体正面始终指向 targetDirection(可修改为鼠标或目标位置)。 

完整臻享版:

using UnityEngine;

public class QuaternionDemo : MonoBehaviour
{
    public Transform target;
    public float rotateSpeed = 90f;
    public float slerpSpeed = 0.5f;

    void Start()
    {
        // 初始化无旋转
        transform.rotation = Quaternion.identity;
    }

    void Update()
    {
        // 1. AngleAxis 持续绕Y轴旋转
        float angle = rotateSpeed * Time.deltaTime;
        Quaternion rotation = Quaternion.AngleAxis(angle, Vector3.up);
        transform.rotation = rotation * transform.rotation;

        // 2. LookRotation 朝向目标
        if (target != null)
        {
            Vector3 direction = target.position - transform.position;
            Quaternion targetRot = Quaternion.LookRotation(direction);
            transform.rotation = Quaternion.Slerp(transform.rotation, targetRot, slerpSpeed * Time.deltaTime);
        }

        // 3. 输出当前欧拉角
        Debug.Log("当前欧拉角:" + transform.rotation.eulerAngles);
    }
}

五、四元数之间的计算

1. 叉乘(组合旋转)

四元数乘法表示旋转的叠加,顺序为从右到左应用。
公式

                        q_{result} = q_{1} \times q_{2}

注意啊不满足交换律:即:

                ​​​​​​​        q_{1} \times q_{2} \neq q_{2} \times q_{1}

Quaternion qY = Quaternion.Euler(0, 90, 0); // 绕Y轴转90度
Quaternion qX = Quaternion.Euler(90, 0, 0); // 绕X轴转90度

// 顺序1:先绕Y轴转,再绕X轴转
transform.rotation = qX * qY;

// 顺序2:先绕X轴转,再绕Y轴转
transform.rotation = qY * qX;
/*效果:

顺序1:物体会先面向右侧(Y轴旋转),然后向上翻转(X轴旋转)。

顺序2:物体会先向上翻转(X轴旋转),然后面向右侧(Y轴旋转)。
最终朝向完全不同(可通过运行代码观察)。
*/
2. 点积(相似度)

四元数的点乘(Quaternion.Dot(q1, q2))返回值的范围是 [-1, 1],表示两个旋转的相似程度:

1:完全相同旋转。
-1:互为反向旋转。
0:旋转方向正交(无关)。

         Dot(q_{1},q_{2}) = q_{1}.x \cdot q_{2}.x +q_{1}.y \cdot q_{2}.y +q_{1}.z \cdot q_{2}.z +q_{1}.w \cdot q_{2}.w                         

 实际应用场景
(1) 判断旋转是否完成

Quaternion targetRotation = Quaternion.Euler(0, 90, 0);
float similarity = Quaternion.Dot(transform.rotation, targetRotation);

if (similarity > 0.999f) {
    Debug.Log("旋转完成!");
}

(2) 平滑过渡检测 在插值旋转时,若相似度接近1,可提前终止插值以优化性能:

Quaternion current = transform.rotation;
Quaternion target = Quaternion.Euler(0, 90, 0);
float t = Quaternion.Dot(current, target);

if (t < 0.99f) {
    transform.rotation = Quaternion.Slerp(current, target, Time.deltaTime * speed);
}

(3) 反向旋转检测

Quaternion inverse = Quaternion.Inverse(currentRotation);
float similarity = Quaternion.Dot(currentRotation, inverse);

if (similarity < -0.999f) {
    Debug.Log("当前旋转与反向旋转对齐");
}
操作 数学本质 Unity中的作用 典型场景
乘法(×) 旋转叠加(顺序敏感) 组合多个旋转,或转换坐标系 角色转身+抬头、动画叠加
点乘(Dot) 四维空间中的夹角余弦 检测旋转相似度、判断旋转完成或反向 插值优化、AI朝向检测、反向动作触发

综合对比:

using UnityEngine;

public class QuaternionOperationsDemo : MonoBehaviour
{
    void Start()
    {
        // 1. 验证乘法顺序
        Quaternion qY = Quaternion.Euler(0, 90, 0);
        Quaternion qX = Quaternion.Euler(90, 0, 0);
        
        Debug.Log("顺序1 (qX*qY): " + (qX * qY).eulerAngles); // 输出 (90, 90, 0)
        Debug.Log("顺序2 (qY*qX): " + (qY * qX).eulerAngles); // 输出 (90, 90, 270)

        // 2. 验证点乘相似度
        Quaternion a = Quaternion.identity;
        Quaternion b = Quaternion.Euler(0, 90, 0);
        Quaternion c = Quaternion.Inverse(b);
        
        Debug.Log("a vs b: " + Quaternion.Dot(a, b)); // 约0.7(不相似)
        Debug.Log("b vs b: " + Quaternion.Dot(b, b)); // 1(完全一致)
        Debug.Log("b vs c: " + Quaternion.Dot(b, c)); // -1(完全反向)
    }
}

3. 逆运算

四元数的逆(Inverse)表示反向旋转。

公式

        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        q^{-1} = (-\frac{x}{||q||},-\frac{y}{||q||},-\frac{z}{||q||},-\frac{w}{||q||},)

例如:

Quaternion inverse = Quaternion.Inverse(rotation);

        ​​​​​​​       这里同上,不再赘述

六、总结

四元数 Quaternion 属性与方法总结

属性/方法 参数 返回值 简单示例
identity Quaternion transform.rotation = Quaternion.identity;
eulerAngles Vector3(欧拉角) Vector3 angles = transform.rotation.eulerAngles;
AngleAxis float angleVector3 axis Quaternion Quaternion q = Quaternion.AngleAxis(90, Vector3.up);
Euler float xfloat yfloat z 或 Vector3 euler Quaternion Quaternion q = Quaternion.Euler(0, 90, 0);
Slerp Quaternion aQuaternion bfloat t Quaternion Quaternion.Slerp(current, target, Time.deltaTime * speed);
Lerp Quaternion aQuaternion bfloat t Quaternion Quaternion.Lerp(current, target, Time.deltaTime * speed);
Inverse Quaternion rotation Quaternion Quaternion inverse = Quaternion.Inverse(transform.rotation);
LookRotation Vector3 forwardVector3 upwards=Vector3.up(可选) Quaternion Quaternion q = Quaternion.LookRotation(target.position - transform.position);
operator * Quaternion aQuaternion b(或 Vector3 向量) Quaternion 或 Vector3 Quaternion combined = q1 * q2;
Vector3 rotated = q * Vector3.forward;
Dot Quaternion aQuaternion b float(相似度) float similarity = Quaternion.Dot(q1, q2);

详细说明

1. 属性
属性 说明
identity 表示无旋转的四元数,等同于 new Quaternion(0, 0, 0, 1)
eulerAngles 将四元数转换为欧拉角(单位为度),仅用于调试,不可直接修改。
2. 方法
方法 说明
AngleAxis 绕指定轴旋转指定角度(单位为度)。
Euler 将欧拉角转换为四元数(单位为度)。
Slerp 沿球面最短路径插值,适合平滑旋转(如摄像机跟随)。
Lerp 线性插值,速度更快但路径可能非最短。
Inverse 返回反向旋转的四元数(等效于逆矩阵)。
LookRotation 生成朝向指定方向的四元数,默认以 Vector3.up 为向上方向。
3. 运算符与静态方法
操作 说明
operator * 组合两个四元数的旋转,或对向量应用旋转(顺序为从右到左)。
Dot 计算两个四元数的四维点积,用于判断旋转相似度(1为相同,-1为反向)。

 


网站公告

今日签到

点亮在社区的每一天
去签到