当前位置: 首页 > news >正文

Unity基础-欧拉角和四元数

Unity基础-欧拉角和四元数

三、欧拉角和四元数

1. 为什么要使用四元数

Unity使用左手坐标系,X轴向右为正,Z轴向前为正,Y轴向上为正。
在Unity中,物体的旋转通常有两种表示方法:

欧拉角
  • 通过三个角度值(X, Y, Z)表示旋转
  • 优点:简单易懂,便于理解
  • 缺点:
    • 多个旋转顺序不同可能导致不同结果
    • 同一结果可能有不同种旋转角度
    • 存在万向节死锁(Gimbal Lock)问题

【补充说明】

  • 欧拉角的旋转顺序(如XYZ、ZYX等)会影响最终的旋转结果。Unity默认采用"ZXY"顺序。
  • 常见陷阱:多次叠加欧拉角旋转时,容易出现意外的旋转效果,建议尽量用四元数做插值和叠加。
四元数
  • 使用四个分量(x, y, z, w)表示旋转
  • 优点:
    • 可以避免万向节死锁问题
    • 计算效率高,旋转组合更稳定
  • 缺点:不够直观,难以理解

【补充说明】

  • 四元数的数学性质:
    • 单位四元数长度为1,表示纯旋转。
    • 四元数的共轭(Conjugate)可用于求逆旋转。
    • 四元数的逆(Inverse)常用于"从B到A的旋转"。

2. 什么是万向节死锁

当使用欧拉角进行旋转,第二个旋转轴(通常是Y)旋转到90度时,第一个旋转轴和第三个旋转轴会重合,导致失去一个维度的旋转轴,从而无法实现某些旋转效果。

3. 什么是四元数

轴-角对:在3D空间内,任意旋转都可以表示为绕一个轴旋转一个角度,这里的轴可以是任意方向(不局限于X、Y、Z)。

四元数的定义

对于给定旋转,假设为绕着n轴,旋转β度,n轴为(x, y, z),那么可以构成四元数:

  • 四元数Q = [cos(β/2), sin(β/2) * n]
  • 展开为:Q = [cos(β/2), sin(β/2)x, sin(β/2)y, sin(β/2)z]

在Unity中,rotation属性就是四元数类型。

// 在Unity中定义一个四元数
Quaternion q = new Quaternion(Mathf.Sin(30 * Mathf.Deg2Rad), 0, 0, Mathf.Cos(30 * Mathf.Deg2Rad));
// 利用轴角对定义一个四元数
// 注意:应为 Quaternion.AngleAxis 而不是 AngleAixs
Quaternion q = Quaternion.AngleAxis(60, Vector3.right);

4. 欧拉角和四元数的相互转化

// 欧拉角转化为四元数
Quaternion quaternion = Quaternion.Euler(0, 60, 0);
// 使用四元数旋转,完美解决了万向节死锁问题
this.transform.rotation *= quaternion;
// 四元数转化为欧拉角
Vector3 rot = (this.transform.rotation).eulerAngles;
rot += Vector3.up;
// 使用欧拉角旋转,存在万向节死锁问题
this.transform.rotation = Quaternion.Euler(rot);

5. 单位四元数

单位四元数表示没有旋转量(角位移)。
当角度为0或者360度时,对于给定轴都会得到单位四元数。
[1, (0,0,0)] 和 [-1, (0,0,0)] 都是单位四元数,表示没有旋转量。

// 使用单位四元数进行对象实例化
Instantiate(target, Vector3.zero, Quaternion.identity);

6. 四元数差值运算

四元数中同样提供如同Vector3中的差值运算Lerp和Slerp。

  • Lerp:线性插值,速度快,但大角度旋转时效果不如Slerp
  • Slerp:球形插值,旋转更自然,常用于动画、摄像机等平滑过渡
// 使用差值先快后慢过渡
a.transform.rotation = Quaternion.Slerp(a.transform.rotation, target.transform.rotation, Time.deltaTime);
// 使用差值匀速过渡
float time = 0;
time += Time.deltaTime;
b.transform.rotation = Quaternion.Slerp(startQua, target.transform.rotation, time);

【补充说明】

  • Slerp(球形插值)适合大角度、需要平滑过渡的旋转,动画和摄像机常用。
  • Lerp(线性插值)速度快,适合小角度、对精度要求不高的场景。
  • 实际开发中,推荐优先使用Slerp进行旋转插值。

7. LookRotation(朝向旋转)

Quaternion.LookRotation 可以将传入的面朝向量转换为对应的四元数角度信息。

应用示例:
当需要改变人物的面朝方向时,只需将目标面朝向向量传入该函数,即可得到目标四元数角度信息。随后,将人物的四元数角度信息更新为获得的结果,即可实现转向效果。

// 向量指向转四元数LookRotation
lookA.rotation = Quaternion.LookRotation(lookB.position - lookA.position);

关键点:

  • 输入:面朝向量(表示目标方向)
  • 输出:对应的四元数角度信息
  • 用途:快速实现物体或角色的方向调整

【补充说明】

  • LookRotation的输入向量不能为零向量,否则会报错。
  • 可以指定第二个参数(up方向),如Quaternion.LookRotation(forward, up),以控制物体的"头顶"朝向。

【补充:四元数在Unity常见应用场景】

  • 角色和摄像机的平滑旋转
  • 物体朝向目标(如导弹追踪、角色面向)
  • 动画骨骼插值
  • 3D物理模拟中的旋转

8. 四元数的计算

8.1 四元数相乘
q3 = q1 * q2
  • 两个四元数相乘得到一个新的四元数
  • 代表两个旋转量的叠加,相当于旋转
  • 注意:旋转相对的坐标系是物体的局部坐标系,不是世界的全局坐标系
8.2 四元数乘向量
v2 = q1 * v1
  • 四元数乘向量返回一个新向量
  • 可以将指定向量旋转对应四元数的旋转量,相当于旋转向量
  • 注意:q1和v1不可以调换顺序!
8.3 实际应用示例
// 创建一个绕Z轴旋转45度的四元数
Quaternion q = Quaternion.AngleAxis(45, Vector3.forward);
// 应用到物体的旋转上
this.transform.rotation *= q; // 旋转向量
Vector3 v = Vector3.up;
print(v);  // 输出原始向量
v = q * v; // 将向量v旋转45度
print(v);  // 输出旋转后的向量

【补充说明】

  • 四元数乘法不满足交换律,即 q1 * q2 ≠ q2 * q1
  • 四元数乘向量时,顺序必须是四元数在前,向量在后
  • 在Unity中,transform.rotation *= q 等价于 transform.rotation = transform.rotation * q

相关文章:

  • 当数据包从上层移动到下层时,OSI 模型中会发生什么?
  • Qt/C++学习系列之Excel使用记录
  • xctf-weak_auth(弱口令)
  • 初探Succinct Jagged稀疏多项式承诺方案
  • Go语言堆内存管理
  • Scade 语言概念 - 方程(equation)
  • BeckHoff--MES数据交互 MQ TRANCE API (MQ 追溯 API - 系统概述和命令参考)
  • STM32开发中,线程启动异常问题排查简述
  • Linux下的fuser用法简析
  • Qt(part 2)1、Qwindow(菜单栏,工具栏,状态栏),铆接部件,核心部件 ,2、添加资源文件 3、对话框
  • 2025年AI编程工具推荐
  • linux设备重启后时间与网络时间不同步怎么解决?
  • Bootstrap Blazor中实现富文本框Editor组件的内容导出为docx格式的Word文档
  • Spring Security深度解析:构建企业级安全框架
  • CCPC chongqing 2025 H
  • c++ 静态成员变量
  • xss漏洞学习
  • 什么是可恢复保险丝
  • ELF文件,静态链接(Linux)
  • 关于 ​​Thread 与 Runnable​​ 以及 ​​线程生命周期​​ 的详细说明与示例
  • 自己有网站想制作个程序/今天头条新闻100条
  • 云主机怎么安装网站/seo教程最新
  • 哪个网站做国际生意/关键词优化平台有哪些
  • 一个域名两个网站/株洲百度seo
  • 哪个cms做企业网站好/新闻最新消息10条
  • 找装修公司去哪个网站/购买域名后如何建立网站