【Unity中的数学】—— 四元数

news2025/5/10 5:43:27

一、四元数的定义😎

四元数是一种高阶复数,是一个四维空间的概念,相对于复数的二维空间。它可以表示为 q = s + i x + j y + k z q = s + ix + jy + kz q=s+ix+jy+kz,其中 s s s x x x y y y z z z 都是实数,并且满足 i 2 = j 2 = k 2 = i j k = − 1 i^2 = j^2 = k^2 = ijk = -1 i2=j2=k2=ijk=1 i j = k ij = k ij=k j k = i jk = i jk=i k i = j ki = j ki=j j i = − k ji = -k ji=k k j = − i kj = -i kj=i i k = − j ik = -j ik=j 这些运算规则😜。

四元数的创造源于对复数以及矩阵的某些问题,在很多领域都有广泛的应用,比如计算机图形学、机器人学、航空航天等。它可以用来表示向量旋转或者坐标系转换,比欧拉角和旋转矩阵更具优势👏。例如,在计算机图形学中,四元数可以避免欧拉角表示旋转时出现的万向节死锁问题,并且计算更加紧凑高效,还能方便地进行球面插值。

二、万向节死锁😵

2.1 定义

万向节死锁(Gimbal Lock)是机械系统和三维空间旋转控制中的一种现象,主要发生在使用欧拉角描述三维旋转时😕。当一个旋转轴在一定条件下与另一个旋转轴重合时,系统失去了一个自由度,导致无法独立控制所有旋转方向,这种情况就称为万向节死锁。

2.2 原理

欧拉角是用来描述三维空间中刚体旋转的一种方法,它通过三个角度(通常为偏航角(yaw)、俯仰角(pitch)和滚转角(roll))来确定刚体的旋转状态😃。然而,欧拉角描述旋转时存在一个问题,就是当中间的旋转轴转动 90 度时,第一个旋转轴和第三个旋转轴会重合,系统就会损失一个自由度。

举个例子🤔,假如我们有一个飞机模型,按照 X − Y − Z X - Y - Z XYZ 的顺序进行旋转。当飞机绕 Y Y Y 轴旋转 90 度时, X X X 轴和 Z Z Z 轴的旋转效果就会相同,此时飞机就无法独立控制绕 X X X 轴的旋转了,这就是万向节死锁的表现。

2.3 避免方法

根据使用场景调整旋转顺序:用欧拉角描述旋转时无法完全避免死锁问题,但可以根据使用场景来减少死锁出现的概率。比如描述船在海上航行的姿态时,可以把中间的旋转轴定义为船的左右方向,因为船几乎很难在这个方向旋转 90 度(船头竖直朝上或朝下)🤗。
使用其他描述旋转的方式:使用四元数、旋转矩阵等其它方式描述旋转。四元数可以避免万向节死锁现象,并且只需要一个 4 维的四元数就可以执行绕任意过原点的向量的旋转,方便快捷,在某些实现下比旋转矩阵效率更高😎。

三、Unity中的四元数🎉

3.1 欧拉角与四元数互相转换

在 Unity 中,Transform 组件的 rotation 属性是一个四元数,但为了方便理解,我们通常会使用欧拉角来表示旋转。下面是欧拉角与四元数互相转换的方法👇:

3.1.1 欧拉角转四元数

// 获得挂在该脚本的对象的欧拉角
Vector3 euler = this.transform.eulerAngles;
Quaternion quater = Quaternion.Euler(euler);
Quaternion quater1 = Quaternion.Euler(0, 0, 0);

这里的 Quaternion.Euler 方法可以将欧拉角转换为四元数。它的实现原理是根据欧拉角的三个角度,通过一系列的三角函数计算得到四元数的四个分量😃。

3.1.2 四元数转欧拉角
print(quater.eulerAngles);

通过 eulerAngles 属性可以将四元数转换为欧拉角。需要注意的是,四元数到欧拉角的转换可能不是唯一的,因为一个旋转可以用多个不同的欧拉角表示😉。

3.2 对比物体间的旋转角度 Quaternion.Angle

Quaternion.Angle 方法用于计算两个四元数前方矢量之间的夹角度数,也就是对比物体之间的旋转角度😃。使用时需要声明一个公共 Transform 对象,示例代码如下:

public Transform target;

void Update()
{
    float angle = Quaternion.Angle(transform.rotation, target.rotation);
    Debug.Log("角度: " + angle);
}

在这个例子中,我们在 Update 函数中不断计算当前物体和目标物体之间的旋转角度,并将结果输出到控制台。这个方法在很多场景中都很有用,比如游戏中判断两个角色的朝向夹角😎。

3.3 直接绕轴旋转角度 Quaternion.AngleAxis

Quaternion.AngleAxis 方法用于创建一个绕指定轴旋转指定角度的四元数😜。它的函数原型如下:

public static Quaternion AngleAxis(float angle, Vector3 axis);

参数说明:

angle:旋转的角度,以度为单位。
axis:旋转的轴向,一个 Vector3 类型的对象。

返回值是一个 Quaternion 类型的对象,表示旋转的结果。下面是一些使用示例👇:

3.3.1 绕 Y 轴旋转游戏对象

public class RotateObject : MonoBehaviour
{
    public float rotationSpeed = 10f;

    private void Update()
    {
        // 根据旋转速度和 Y 轴创建旋转四元数
        Quaternion rotation = Quaternion.AngleAxis(rotationSpeed * Time.deltaTime, Vector3.up);

        // 将旋转应用到游戏对象的旋转属性上
        transform.rotation *= rotation;
    }
}

在这个示例中,我们创建了一个名为 RotateObject 的脚本,并将其绑定到一个游戏对象上。脚本中定义了一个 rotationSpeed 变量来控制旋转速度。在 Update 方法中,我们使用 Quaternion.AngleAxis 方法创建了一个绕 Y 轴旋转的旋转四元数 rotation,角度为 rotationSpeed 乘以 Time.deltaTime(用于平滑旋转)。然后,将该旋转应用到游戏对象的旋转属性上,使对象随时间不断绕 Y 轴旋转😎。

3.3.2 绕任意轴旋转游戏对象

public class RotateObject : MonoBehaviour
{
    public float rotationSpeed = 10f;
    public Vector3 rotationAxis = Vector3.up;

    private void Update()
    {
        // 根据旋转速度和轴向创建旋转四元数
        Quaternion rotation = Quaternion.AngleAxis(rotationSpeed * Time.deltaTime, rotationAxis);

        // 将旋转应用到游戏对象的旋转属性上
        transform.rotation *= rotation;
    }
}

这个示例与上面的类似,只是我们可以指定任意的旋转轴。通过修改 rotationAxis 变量,我们可以让游戏对象绕不同的轴进行旋转😃。

3.3.3 连续旋转游戏对象

public class RotateObject : MonoBehaviour
{
    public float rotationSpeed1 = 10f;
    public float rotationSpeed2 = 5f;

    private void Update()
    {
        // 根据旋转速度和 Y 轴创建旋转四元数
        Quaternion rotation1 = Quaternion.AngleAxis(rotationSpeed1 * Time.deltaTime, Vector3.up);

        // 根据旋转速度和 X 轴创建旋转四元数
        Quaternion rotation2 = Quaternion.AngleAxis(rotationSpeed2 * Time.deltaTime, Vector3.right);

        // 将两个旋转应用到游戏对象的旋转属性上
        transform.rotation *= rotation1 * rotation2;
    }
}

在这个示例中,我们创建了两个旋转四元数 rotation1 和 rotation2,分别绕 Y 轴和 X 轴进行旋转。然后,将这两个旋转应用到游戏对象的旋转属性上,使对象同时绕 Y 轴和 X 轴连续旋转😜。

3.4 其他静态方法

除了上面介绍的方法,Quaternion 类还有很多其他的静态方法,如 Dot、Inverse、Lerp、LookRotation、RotateToWards 和 Slerp 等。这些方法的具体使用可以参考官方手册😃。

四、四元数的计算🧮

4.1 加法

两个四元数的加法就是将“实部虚部”对应位置做元素求和😃。设两个四元数 q 1 = s 1 + i x 1 + j y 1 + k z 1 q_1 = s_1 + ix_1 + jy_1 + kz_1 q1=s1+ix1+jy1+kz1 q 2 = s 2 + i x 2 + j y 2 + k z 2 q_2 = s_2 + ix_2 + jy_2 + kz_2 q2=s2+ix2+jy2+kz2,则它们的和为: q 1 + q 2 = ( s 1 + s 2 ) + i ( x 1 + x 2 ) + j ( y 1 + y 2 ) + k ( z 1 + z 2 ) q_1 + q_2 = (s_1 + s_2) + i(x_1 + x_2) + j(y_1 + y_2) + k(z_1 + z_2) q1+q2=(s1+s2)+i(x1+x2)+j(y1+y2)+k(z1+z2)

四元数的加法满足交换律、结合律和分配律👏。

4.2 缩放

在系数缩放这一点上,四元数与复数是一致的😃。设四元数 q = s + i x + j y + k z q = s + ix + jy + kz q=s+ix+jy+kz,标量为 λ \lambda λ,则它们的乘积为: λ q = λ s + i λ x + j λ y + k λ z \lambda q = \lambda s + i\lambda x + j\lambda y + k\lambda z λq=λs+x+y+z

4.3 乘法

四元数的乘法是所有元素之前都要运算一遍😕。设两个四元数 q 1 = s 1 + i x 1 + j y 1 + k z 1 q_1 = s_1 + ix_1 + jy_1 + kz_1 q1=s1+ix1+jy1+kz1 q 2 = s 2 + i x 2 + j y 2 + k z 2 q_2 = s_2 + ix_2 + jy_2 + kz_2 q2=s2+ix2+jy2+kz2,则它们的乘积为: q 1 q 2 = ( s 1 s 2 − x 1 x 2 − y 1 y 2 − z 1 z 2 ) + i ( s 1 x 2 + s 2 x 1 + y 1 z 2 − y 2 z 1 ) + j ( s 1 y 2 + s 2 y 1 + x 2 z 1 − x 1 z 2 ) + k ( s 1 z 2 + s 2 z 1 + x 1 y 2 − x 2 y 1 ) q_1q_2 = (s_1s_2 - x_1x_2 - y_1y_2 - z_1z_2) + i(s_1x_2 + s_2x_1 + y_1z_2 - y_2z_1) + j(s_1y_2 + s_2y_1 + x_2z_1 - x_1z_2) + k(s_1z_2 + s_2z_1 + x_1y_2 - x_2y_1) q1q2=(s1s2x1x2y1y2z1z2)+i(s1x2+s2x1+y1z2y2z1)+j(s1y2+s2y1+x2z1x1z2)+k(s1z2+s2z1+x1y2x2y1)

需要注意的是,四元数与复数的最大的一点不同,复数乘法是有交换律的,而四元数没有😉。也就是说,一般情况下 q 1 q 2 ≠ q 2 q 1 q_1q_2 \neq q_2q_1 q1q2=q2q1

4.3.1 旋转 = 四元数 * 四元数

四元数相乘可以将旋转效果组合😎。例如, q u a t e r n i o n . e u l e r ( 0 , 0 , 10 ) ∗ q u a t e r n i o n . e u l e r ( 0 , 0 , 15 ) = = q u a t e r n i o n . e u l e r ( 0 , 0 , 25 ) quaternion.euler(0, 0, 10) * quaternion.euler(0, 0, 15) == quaternion.euler(0, 0, 25) quaternion.euler(0,0,10)quaternion.euler(0,0,15)==quaternion.euler(0,0,25),这就是四元数相乘的效果。在 Unity 中,我们可以通过四元数相乘来实现物体的复合旋转。

4.3.2 旋转向量 = 四元数 * 向量

四元数乘以向量表示将向量按照四元数表示的角度旋转😃。例如, v e c t o r 3 a = q u a t e r n i o n . e u l e r ( 0 , 0 , 10 ) ∗ n e w v e c t o r 3 ( 0 , 0 , 30 ) vector3 a = quaternion.euler(0, 0, 10) * new vector3(0, 0, 30) vector3a=quaternion.euler(0,0,10)newvector3(0,0,30) 表示将(0,0,30)这个向量绕 z 轴为定轴,顺时针旋转 10°。需要注意的是,四元数只能进行 * 运算,不能进行 + - 运算,这是由四元数复杂的内部原理决定的😜。

4.4 其他运算

四元数还有一些其他的运算,如求模、单位化、求共轭、求逆等😃。这些运算在四元数的应用中也非常重要,下面是它们的定义和公式:

4.4.1 求模

四元数 q = s + i x + j y + k z q = s + ix + jy + kz q=s+ix+jy+kz 的模定义为: ∣ q ∣ = s 2 + x 2 + y 2 + z 2 |q| = \sqrt{s^2 + x^2 + y^2 + z^2} q=s2+x2+y2+z2

4.4.2 单位化

单位化是将四元数的模变为 1,公式为: N o r m a l i z e ( q ) = q ∣ q ∣ Normalize(q) = \frac{q}{|q|} Normalize(q)=qq

4.4.3 求共轭

四元数 q = s + i x + j y + k z q = s + ix + jy + kz q=s+ix+jy+kz 的共轭定义为: q ∗ = s − i x − j y − k z q^* = s - ix - jy - kz q=sixjykz

4.4.4 求逆

四元数 q q q 的逆定义为: q − 1 = q ∗ ∣ q ∣ 2 q^{-1} = \frac{q^*}{|q|^2} q1=q2q

对于单位四元数,分母为 1, q − 1 = q ∗ q^{-1} = q^* q1=q

五、总结🥳

四元数在 Unity 中是一个非常重要的概念,它可以用来表示物体的旋转,避免欧拉角表示旋转时出现的万向节死锁问题😎。通过本文的介绍,我们了解了四元数的定义、万向节死锁的原理、Unity 中四元数的操作以及四元数的计算方法。希望这些内容对你有所帮助,让你在使用 Unity 进行开发时能够更加得心应手👏!

如果你想进一步了解四元数的相关知识,可以参考一些专业的数学书籍或者在线教程。同时,也可以通过实践来加深对四元数的理解,比如在 Unity 中创建一些简单的旋转效果,使用四元数来实现物体的旋转控制😃。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2372055.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

vscode docker 调试

目录 启动docker: vscode docker 调试 如果已经安装docker并且启动了。 启动docker: docker exec -it nlf /bin/bash vscode docker 调试 按照图中1 2 3 的顺序,进入,可以加载docker进行调试了。

HTML01:HTML基本结构

HTML基本结构 <html> <head><meta charset"UTF-8"><title>我的第一个网页</title> </head> <body>我的第一个网页 </body> </html><body、</body等成对的标签&#xff0c;分别叫开发标签和闭合标签单独…

URP - 屏幕图像(_CameraOpaqueTexture)

首先需要在unity中开启屏幕图像开关才可以使用该纹理 同样只有不透明对象才能被渲染到屏幕图像中 若想要该对象不被渲染到屏幕图像中&#xff0c;可以将其Shader的渲染队列改为 "Queue" "Transparent" 如何在Shader中使用_CameraOpaqueTexture&#xf…

如何在Ubuntu上安装NVIDIA显卡驱动?

作者&#xff1a;算力魔方创始人/英特尔创新大使刘力 一&#xff0c;前言 对于使用NVIDIA显卡的Ubuntu用户来说&#xff0c;正确安装显卡驱动是获得最佳图形性能的关键。与Windows系统不同&#xff0c;Linux系统通常不会自动安装专有显卡驱动。本文将详细介绍在Ubuntu系统上安…

机器视觉的手机FPC油墨丝印应用

在现代智能手机制造过程中&#xff0c;精密的组件装配和质量控制是确保产品性能和用户体验的关键。其中&#xff0c;柔性印刷电路板&#xff08;FPC&#xff09;的油墨丝印工艺尤为关键&#xff0c;它不仅影响到电路板的美观&#xff0c;更直接关系到电路的导电性能和可靠性。而…

Android智能体开发框架-架构文档

编写目的 1 提高智能体的开发效率&#xff0c; 2 降低系统开销&#xff0c; 3 支持跨平台扩展&#xff0c; 4 提供统一的开发范式 整体架构 接口层&#xff08;api层&#xff09;&#xff1a;提供API供开发者调用&#xff0c;支持Java/Kotlin和Native&#xff08;C&#x…

MySQL----数据库的操作

1. 查看数据库 语法&#xff1a;show databases; 示例展示&#xff1a; 2. 创建库 语法&#xff1a; CREATE DATABASE [IF NOT EXISTS] database_name[CHARACTER SET charset_name][COLLATE collation_name]; 注意&#xff1a;[] 为可选项 {} 为必选项 database_name 为数据…

两种方法求解最长公共子序列问题并输出所有解

最长公共子序列&#xff08;Longest Common Subsequence, LCS&#xff09;是动态规划领域的经典问题&#xff0c;广泛应用于生物信息学&#xff08;如DNA序列比对&#xff09;、文本差异比对&#xff08;如Git版本控制&#xff09;等领域。本文将通过​​自顶向下递归记忆化​​…

【Linux网络】网络协议基础

网络基础 计算机网络背景 独立模式:计算机之间相互独立 网络互联:多台计算机连接在一起,完成数据共享 局域网LAN:计算机数量更多了,通过交换机和路由器连接在一起 广域网WAN:将远隔千里的计算机都连在一起 所谓"局域网"和"广域网"只是一个相对的概念.比…

LeapVAD:通过认知感知和 Dual-Process 思维实现自动驾驶飞跃——论文阅读

《LeapVAD: A Leap in Autonomous Driving via Cognitive Perception and Dual-Process Thinking》2025年1月发表&#xff0c;来自浙江大学、上海AI实验室、慕尼黑工大、同济大学和中科大的论文。 尽管自动驾驶技术取得了显著进步&#xff0c;但由于推理能力有限&#xff0c;数…

windows 部署 Kafka3.x KRaft 模式 不依赖 ZooKeeper

1.下载 https://archive.apache.org/dist/kafka/3.9.0/kafka_2.12-3.9.0.tgz2.配置使用 KRaft 模式 2.1 修改 Kafka 的配置文件 cd D:\data\bigdata\kafka_2.12-3.9.0\config\kraft 修改 server.properties # 设置 Kafka 数据日志存储目录 log.dirsD:\\data\\bigdata\\kaf…

Xilinx FPGA | 管脚约束 / 时序约束 / 问题解析

注&#xff1a;本文为 “Xilinx FPGA | 管脚约束 / 时序约束 / 问题解析” 相关文章合辑。 略作重排&#xff0c;未整理去重。 如有内容异常&#xff0c;请看原文。 Xilinx FPGA 管脚 XDC 约束之&#xff1a;物理约束 FPGA技术实战 于 2020-02-04 17:14:53 发布 说明&#x…

Python-JsonRPC

Python-JsonRPC 使用Python学习JsonRPC数据交互 1-核心知识点 1&#xff09;什么是JsonRPC&#xff0c;这种协议是如何工作的&#xff1f;->使用请求进行验证2&#xff09;JsonRPC可以使用Postman进行验证吗&#xff1f;->可以使用POSTMAN进行调用&#xff08;使用HTTP请…

Redis从入门到实战——实战篇(下)

四、达人探店 1. 发布探店笔记 探店笔记类似于点评网站的评价&#xff0c;往往是图文结合。对应的表有两个&#xff1a; tb_blog&#xff1a;探店笔记表&#xff0c;包含笔记中的标题、文字、图片等tb_blog_comments&#xff1a;其他用户对探店笔记的评价 步骤①&#xff1…

面试问题(连载。。。。)

flexbox 和 crid 的区别 1. 布局维度与核心特性 Flexbox&#xff08;弹性盒子&#xff09; 一维布局&#xff1a;专注于行或列的线性排列&#xff0c;适合单方向&#xff08;水平或垂直&#xff09;的布局需求。动态分配空间&#xff1a;通过 flex-grow、flex-shrink 和 flex…

OpenCv实战笔记(1)在win11搭建opencv4.11.1 + qt5.15.2 + vs2019_x64开发环境

一. 准备工作 Visual Studio 2019&#xff08;安装时勾选 C 桌面开发 和 Windows 10 SDK&#xff09; CMake 3.20&#xff08;官网下载&#xff09; Qt 5.15.2&#xff08;下载 Qt Online Installer&#xff09;安装时勾选 MSVC 2019 64-bit 组件。 opencv 4.11.1 源码下载 git…

全局网络:重构数字时代的连接范式

从局部到全局 —— 网络架构的范式革命 在全球化与数字化深度融合的今天&#xff0c;传统网络架构的 “碎片化” 问题日益凸显&#xff1a;跨地域数据流通低效、设备互联孤岛化、安全策略难以统一。 全局网络作为一种突破地域与技术边界的新型网络架构&#xff0c;正成为企业…

C++ Primer (第五版)-第十四章重载运算与类型转换

文章目录 一、基本概念可以被重载某些运算符不应被重载尽量明智使用运算符重载赋值和复合赋值运算符选择作为成员或者非成员 输入和输出运算符输入运算符尽量减少格式化操作输入输出运算符必须是非成员函数 重载输入运算符>>输入时的错误标示错误 算数和关系运算符相等运…

鸿蒙开发——5.ArkUI @Builder装饰器:打造高效可复用的UI组件

鸿蒙开发——5.ArkUI Builder装饰器&#xff1a;打造高效可复用的UI组件 ArkUI Builder装饰器&#xff1a;打造高效可复用的UI组件一、Builder装饰器是什么&#xff1f;二、两种构建函数类型1. 私有自定义构建函数2. 全局自定义构建函数 三、参数传递核心规则1. 按值传递&#…

PyTorchVideo实战:从零开始构建高效视频分类模型

视频理解作为机器学习的核心领域&#xff0c;为动作识别、视频摘要和监控等应用提供了技术基础。本教程将详细介绍如何利用PyTorchVideo和PyTorch Lightning两个强大框架&#xff0c;构建基于Kinetics数据集训练的3D ResNet模型&#xff0c;实现高效的视频分类流程。 PyTorch…