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

游戏引擎中为什么要用四元数表示旋转而不用欧拉角旋转?

个人观点,仅供参考,如有错误可太刺激了

四元数的简单概念和使用

欧拉角通常用于表示一个物体的旋转状态,而不是表示旋转过程

欧拉角描述的是物体相对于某个参考坐标系的朝向或旋转状态,通常以不同的轴(例如,绕X轴、Y轴和Z轴)的旋转角度来表示。这可以让你知道物体是如何朝向的,但它不提供旋转的完整信息。 当你用三个欧拉角表示一个旋转状态时,绕三个轴旋转的顺序不同,会得到不同的旋转结果。这些性质,就导致了以下这些问题:

欧拉角存在的问题

  1. 万向锁(Gimbal Lock): Gimbal Lock 是一个常见的问题,会导致旋转自由度的丢失
  2. 非唯一性: 欧拉角表示不是唯一的,相同的旋转可以用多种不同的欧拉角组合来表示,这很扯淡
  3. 不连续性: 欧拉角旋转可能会导致不连续性,特别是在插值时,会导致角度的突然跳跃,使得动画过渡不平滑
  4. 旋转顺序依赖: 欧拉角旋转的结果依赖于旋转轴的顺序,因此必须明确定义旋转顺序
  5. 数学计算复杂性: 进行欧拉角旋转计算需要需要复杂的矩阵运算

四元数的优点:

  1. 一个四元数通常需要存储4个分量(w、x、y、z),而旋转矩阵通常需要存储9个分量(3x3矩阵)。由于存储空间较小,四元数在内存中占用更少的空间。
  2. 计算效率: 四元数的乘法运算相对于矩阵乘法来说计算更快,因为四元数只涉及4个分量的乘法和加法,而矩阵涉及9个分量的乘法和加法。这在计算机图形和游戏中非常重要,因为需要频繁执行旋转操作。
  3. 插值: 四元数在插值(如球形线性插值)方面表现更好。插值旋转矩阵涉及到矩阵分解和插值,而四元数的插值通常更简单和高效。
  4. 避免万向锁: 四元数在避免万向锁问题上更稳定。欧拉角旋转和旋转矩阵都可能在特定情况下遇到万向锁问题,而四元数通常不会。
  5. 四元数既可以表示朝向,也能表示变换到当前朝向的旋转变换

怎么理解优点5:也能表示变换到当前朝向的旋转变换?

案例: 一个游戏对象,在世界空间中以某个姿态摆放着,已知该物体的面朝方向的欧拉角表示为 forward = (roll, pitch, yaw),求其 Up 向量和 Right 向量

  • 一般计算方法:非常简单且好理解,用叉乘
    glm::vec3 forward = getObjectTransform().Rotation; // 物体的朝向
    glm::vec3 worldUp = glm::vec3(0.0f, 1.0f, 0.0f); glm::vec3 RightInWorld = glm::normalize(glm::cross(worldUp, forward)); 
    glm::vec3 UpInWorld = glm::normalize(glm::cross(forward, Right)); 
    
  • 用四元数计算: 因为当前朝向的四元数同时也代表了物体的局部坐标空间中物体朝向变换到世界空间中的当前朝向的旋转变换,因此把该四元数变换应用给局部UpRight就能得到物体当前在世界空间中的的UpRight
    glm::quat forwardQuad = glm::quat(getObjectTransform().Rotation);glm::vec3 UpInWorld = glm::rotate(forwardQuad, glm::vec3(0.0f, 1.0f, 0.0f);
    glm::vec3 RightInWorld = glm::rotate(forwardQuad, glm::vec3(1.0f, 0.0f, 0.0f));
    

二者计算量其实差不多,根据需要选择方法即可。

http://www.lryc.cn/news/218479.html

相关文章:

  • E-Office(泛微OA)前台任意文件读取漏洞复现
  • 前端小案例 | 喵喵大王立大功 | 一个带便利贴功能的todolist面板
  • 算法训练营第十一天 | 20. 有效的括号、 1047. 删除字符串中的所有相邻重复项、150. 逆波兰表达式求值
  • Python unittest单元测试框架 TestSuite测试套件
  • FSB逮捕为乌克兰网络部队工作的俄罗斯黑客
  • 【PC电脑windows-学习样例tusb_serial_device-ESP32的USB模拟串口程序+VScode建立工程+usb组件添加+-基础样例学习】
  • LeetCode75——Day26
  • 面试算法53:二叉搜索树的下一个节点
  • 2023SHCTF web方向wp
  • 从物理磁盘到数据库 —— 存储IO链路访问图
  • 基于java+springboot+vue在线选课系统
  • GO学习之 同步操作sync包
  • NUUO网络摄像头(NVR)RCE漏洞复现
  • 一款快速获取目标网站关键信息的工具
  • 将GC编程语言引入WebAssembly的新方法
  • 微信小程序UI自动化测试实践:Minium+PageObject
  • Java零基础入门-输入与输出
  • iOS报错命名空间“std”中的“unary_function”
  • Flink SQL 窗口聚合详解
  • 中间件redis的使用
  • Why delete[] array when deepcopying with “=“?
  • curl(六)DNS解析、认证、代理
  • (免费领源码)PHP#MySQL高校学生信息管理系统28099-计算机毕业设计项目选题推荐
  • [动态规划] (四) LeetCode 91.解码方法
  • Vue Vuex的使用和原理 专门解决共享数据的问题
  • 第九周实验记录
  • STM32WB55开发(6)----FUS更新
  • centos关闭Java进程的脚本
  • 深度学习网络模型 MobileNet系列MobileNet V1、MobileNet V2、MobileNet V3网络详解以及pytorch代码复现
  • Spring 中 BeanFactory 和 FactoryBean 有何区别?