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时表示无旋转(单位四元数)

数学关系

四元数可以表示为:

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. 无旋转的单位四元数

    new THREE.Quaternion(0, 0, 0, 1)

    2.绕Y轴旋转90度: 

// 旋转轴:(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中的实际应用

// 创建一个绕(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. 单位长度
    所有表示旋转的四元数都应该是单位四元数:

    x² + y² + z² + w² = 1

    2.规范化
       如果手动修改了四元数值,应该调用: 

quaternion.normalize();

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

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"顺序:

const euler = new THREE.Euler(x, y, z, 'XYZ');

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

实际示例

// 创建一个绕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.使用欧拉角当:

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

  • 进行简单的单轴旋转

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

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

 2.使用四元数当:

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

  • 需要避免万向节锁

  • 进行复杂的旋转组合

  • 需要平滑的旋转动画

  • 绕任意轴旋转

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

    转换关系

    两者可以相互转换:

  • // 欧拉角转四元数
    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(欧拉角)时,内部会自动转换为四元数

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值