threejs 四元数(Quaternion)和欧拉角(Euler)学习

一.四元数(Quaternion)中四个分量的含义

四元数是一种用于表示3D旋转的数学工具,由四个分量组成,通常表示为 (x, y, z, w) 或 (i, j, k, real)。在Three.js中,THREE.Quaternion类使用(x, y, z, w)的表示形式。

四个分量的详细解释

  1. 虚部 (x, y, z)

    • 表示旋转轴的方向向量

    • 这个向量会被自动规范化(长度为1)

    • 分量的比例决定了旋转轴的方向

    • 例如:(1, 0, 0)表示X轴,(0, 1, 0)表示Y轴

  2. 实部 (w)

    • 表示旋转的角度(实际上是角度的一半的余弦值)

    • 与虚部共同决定旋转量

    • 当w=1时表示无旋转(单位四元数)

数学关系

四元数可以表示为:

javascript 复制代码
q = [x, y, z, w] = [sin(θ/2)*axis_x, sin(θ/2)*axis_y, sin(θ/2)*axis_z, cos(θ/2)]

其中:

  • θ 是旋转角度

  • axis_x, axis_y, axis_z\] 是旋转轴的单位向量

  1. 无旋转的单位四元数

    javascript 复制代码
    new THREE.Quaternion(0, 0, 0, 1)

2.绕Y轴旋转90度

javascript 复制代码
// 旋转轴:(0, 1, 0)
// 旋转角度:π/2 (90度)
// 计算:
// x = sin(π/4)*0 = 0
// y = sin(π/4)*1 ≈ 0.707
// z = sin(π/4)*0 = 0
// w = cos(π/4) ≈ 0.707
new THREE.Quaternion(0, 0.7071067811865475, 0, 0.7071067811865476)

可视化理解

可以把四元数想象为:

  • (x, y, z) 指向旋转轴的方向

  • w 的大小决定了旋转的角度

  • 四元数的长度(模)总是1(单位四元数)

在Three.js中的实际应用

javascript 复制代码
// 创建一个绕(1,1,0)轴旋转45度的四元数
const axis = new THREE.Vector3(1, 1, 0).normalize();
const angle = Math.PI / 4; // 45度
const quaternion = new THREE.Quaternion();

quaternion.setFromAxisAngle(axis, angle);

console.log(quaternion);
// 输出类似:Quaternion {x: 0.22, y: 0.22, z: 0, w: 0.92}
// 其中x,y,z是旋转轴分量(已规范化),w是角度分量

重要特性

  1. 单位长度

    所有表示旋转的四元数都应该是单位四元数:

    javascript 复制代码
    x² + y² + z² + w² = 1

2.规范化

如果手动修改了四元数值,应该调用:

javascript 复制代码
quaternion.normalize();

3.逆四元数

表示相反旋转的四元数可以通过取共轭获得:

javascript 复制代码
const inverse = quaternion.clone().conjugate();

理解四元数的四个分量含义有助于在3D编程中更有效地使用它们,特别是在需要精确控制旋转或进行复杂旋转运算时。

二.欧拉角(Euler Angle)三个分量的含义

在Three.js中,欧拉角使用THREE.Euler类表示,由三个分量(x, y, z)组成,分别表示绕三个轴的旋转角度。

三个分量的具体含义

  1. x分量

    • 表示绕X轴的旋转角度(俯仰角/Pitch)

    • 正值:物体向前倾斜(低头)

    • 负值:物体向后倾斜(抬头)

  2. y分量

    • 表示绕Y轴的旋转角度(偏航角/Yaw)

    • 正值:物体向右转

    • 负值:物体向左转

  3. z分量

    • 表示绕Z轴的旋转角度(滚转角/Roll)

    • 正值:物体顺时针旋转

    • 负值:物体逆时针旋转

旋转顺序的重要性

欧拉角的旋转顺序非常重要,Three.js默认使用"XYZ"顺序:

javascript 复制代码
const euler = new THREE.Euler(x, y, z, 'XYZ');

其他可能的顺序包括:'YXZ'、'ZXY'、'ZYX'、'YZX'、'XZY'等。不同顺序会导致完全不同的最终旋转结果。

实际示例

javascript 复制代码
// 创建一个绕X轴旋转45度,Y轴旋转30度的欧拉角
const euler = new THREE.Euler(
  Math.PI/4,    // X轴旋转45度 (π/4弧度)
  0.523598776,  // Y轴旋转30度 (约0.52弧度)
  0,            // Z轴不旋转
  'XYZ'         // 旋转顺序
);

// 应用到物体
mesh.rotation.copy(euler);

万向节锁问题

当绕第二个轴旋转±90度时,会出现万向节锁现象,导致失去一个旋转自由度。例如:

  • 在"XYZ"顺序下,当Y轴旋转90度时,X和Z轴的旋转会变得相同

与四元数的对比

特性 欧拉角 四元数
表示方式 三个角度值 四个数值(x,y,z,w)
直观性
万向节锁 存在 不存在
插值 线性插值不自然 球面插值(Slerp)平滑
组合旋转 顺序敏感,计算复杂 简单四元数乘法

使用建议

  1. 适合使用欧拉角的场景

    • 简单的单轴旋转

    • 需要直观角度控制的编辑器工具

    • 不需要复杂旋转组合的情况

  2. 应避免使用欧拉角的情况

    • 需要绕任意轴旋转

    • 需要平滑的旋转动画

    • 需要避免万向节锁的复杂旋转

理解欧拉角三个分量的含义对于正确控制3D物体的旋转至关重要,特别是在需要精确控制物体朝向的应用中。

三.四元数(Quaternion)与欧拉角(Euler)的区别

四元数和欧拉角都是表示3D旋转的方式,但它们在实现和特性上有显著差异。以下是两者的主要区别:

1. 数学表示

欧拉角

  • 使用三个角度值表示旋转(通常为x, y, z)

  • 例如:new THREE.Euler(0.5, 0.2, 0.1) 表示绕x轴旋转0.5弧度,y轴0.2弧度,z轴0.1弧度

四元数

  • 使用四个数值(x, y, z, w)表示旋转

  • 例如:new THREE.Quaternion(x, y, z, w)

2. 万向节锁(Gimbal Lock)问题

欧拉角

  • 存在万向节锁问题,当某个轴的旋转达到90度时,会失去一个自由度

  • 导致旋转行为不符合预期

四元数

  • 不存在万向节锁问题

  • 可以表示任意旋转而不丢失自由度

3. 插值效果

欧拉角

  • 线性插值可能导致旋转路径不自然

  • 旋转动画可能出现抖动或突变

四元数

  • 可以使用球面线性插值(Slerp)

  • 旋转动画平滑自然

4. 计算复杂度

欧拉角

  • 计算简单,直观易懂

  • 适合简单的旋转操作

四元数

  • 计算相对复杂

  • 但组合旋转(四元数乘法)效率更高

5. 使用场景对比

特性 欧拉角 四元数
直观性 高(直接对应轴旋转角度) 低(数学抽象)
万向节锁
插值效果
组合旋转 顺序依赖,计算复杂 简单乘法运算
存储空间 3个值 4个值
规范化 不需要 需要保持单位长度

实际应用建议

1.使用欧拉角当:

  • 需要直观的角度控制(如编辑器中的旋转工具)

  • 进行简单的单轴旋转

  • 不需要复杂旋转组合或插值

    javascript 复制代码
    // 欧拉角简单旋转示例
    mesh.rotation.x = Math.PI/4; // 绕X轴旋转45度

2.使用四元数当:

理解这两种旋转表示方式的差异,可以帮助你在Three.js开发中选择最适合特定场景的旋转方法

  • 需要避免万向节锁

  • 进行复杂的旋转组合

  • 需要平滑的旋转动画

  • 绕任意轴旋转

    javascript 复制代码
    // 四元数旋转示例
    const axis = new THREE.Vector3(1, 1, 0).normalize();
    const angle = Math.PI/3; // 60度
    mesh.quaternion.setFromAxisAngle(axis, angle);

    转换关系

    两者可以相互转换:

javascript 复制代码
// 欧拉角转四元数
const euler = new THREE.Euler(0.5, 0.2, 0.1);
const quat = new THREE.Quaternion().setFromEuler(euler);

// 四元数转欧拉角
const newEuler = new THREE.Euler().setFromQuaternion(quat);

性能考虑

  • 频繁的欧拉角与四元数转换会影响性能

  • Three.js内部实际上使用四元数存储旋转,当修改object.rotation(欧拉角)时,内部会自动转换为四元数

  • 对于频繁更新的旋转操作,直接操作四元数更高效

相关推荐
虾球xz3 分钟前
游戏引擎学习第309天:用于重叠检测的网格划分
c++·学习·算法·游戏引擎
sslings26 分钟前
SpringMVC实战:动态时钟
java·学习
大写-凌祁30 分钟前
BLIP论文笔记
论文阅读·人工智能·python·深度学习·学习·机器学习
Nejosi_念旧39 分钟前
TypeScript 泛型讲解
前端·javascript·typescript
layman05281 小时前
vue——v-pre的使用
前端·javascript·vue.js
广州华锐视点1 小时前
打破次元壁,VR 气象站开启气象学习新姿势
学习·vr
zizisuo1 小时前
Java集合框架深度剖析:结构、并发与设计模式全解析
java·javascript·数据结构·设计模式
要加油哦~1 小时前
刷题 | 牛客 - js中等题-下(更ing)30/54知识点&解答
java·开发语言·javascript
Python涛哥1 小时前
前端流行框架Vue3教程:25. 组件保持存活
前端·javascript·vue.js
xixingzhe21 小时前
监督学习与无监督学习区别
人工智能·学习·机器学习