Three.js 中 Euler 和 Quaternion 转化的数值可能差异巨大

在 Three.js 中,可以通过 rotation 或者 quaternion 属性来修改 Object3D 的旋转角度。

rotation 属性

rotation 属性的类型为 THREE.Euler,即包内含三个角度的 Eualer 角(欧拉角)对象,分别表示物体位置 X、Y 和 Z 轴的旋转。

object.rotation.x; // 围绕X轴的旋转角度
object.rotation.y; // 围绕Y轴的旋转角度
object.rotation.z; // 围绕Z轴的旋转角度

可以通过修改这些属性的值来改变物体的旋转状态。例如,通过设置rotation.xMath.PI / 2,可以使物体绕X轴旋转90度。

object.rotation.x = Math.PI / 2; // 绕X轴旋转90度

quaternion 属性

quaternion 属性的类型为 THREE.Quaternion,一种四元数来表示旋转。在涉及一些复杂旋转操作的情况下,Quaternion 具有一些的优势,比如避免万向锁(gimbal lock)问题,所以它被广泛用于替代欧拉角。

以下是一个简单的例子,演示如何创建一个绕 Y 轴旋转 45 度的四元数:

// 创建一个四元数表示旋转 
var quaternion = new THREE.Quaternion();
// 绕Y轴旋转45度 
quaternion.setFromAxisAngle(new THREE.Vector3(0, 1, 0), Math.PI / 4);
// 将四元数应用到Group的quaternion属性 
object.quaternion.copy(quaternion);

rotation 和 quaternion 之间的转换

Three.js 中,rotation 和 quaternion 都可以修改当前 Object3D 的旋转,同时这两个值也可以相互转换。

rotation 转 quaternion:

// 绕 X 轴旋转 90 度 
const euler = new THREE.Euler(Math.PI / 2, 0, 0, 'XYZ'); 
// 创建一个空的 Quaternion 
const quaternion = new THREE.Quaternion(); 
// 将 Euler 转换为 
Quaternion quaternion.setFromEuler(euler);

quaternion 转 rotation:

const quaternion = new THREE.Quaternion(); 
// 示例:绕X轴旋转90度 
quaternion.setFromAxisAngle(new THREE.Vector3(1, 0, 0), Math.PI / 2); 
// 将 Quaternion 转换为 Euler 
const euler = new THREE.Euler().setFromQuaternion(quaternion);

Euler 和 Quaternion 转化的数值可能差异巨大

既然 Three.js 中可以使用 Euler 或者 Quaternion 来设置旋转,并且两者可以相互转换。那是否可以随意使用两个数值,并且相互转换得到另一个值呢?

这里可能会有一个坑:Euler 转 Quaternion,再转成 Euler 之后,转化前的 Euler 和转化后的 Euler 的数值可能差异巨大。

来看下面的例子:

// 绕 Y 轴旋转 -160°
const euler = new THREE.Euler(0, -160 * (Math.PI / 180), 0, 'XYZ');
const quaternion = new THREE.Quaternion().setFromEuler(euler);
const afterEuler = new THREE.Euler().setFromQuaternion(quaternion);
console.log("euler ", euler.order);
// 输出:
// euler:order: "XYZ", x: 0, y: -2.792526803190927, z: 0
console.log("afterEuler:", afterEuler);
// afterEuler:order: "XYZ", x: 3.141592653589793, y: -0.349065850398866, z: 3.141592653589793

Three.js 定义的 PI 为 #define PI 3.141592653589793

euler 转成 quaternion 之后,再转成 afterEuler 之后,euler 和 afterEuler 的数值相差巨大:

  • euler: 表示绕 Y 轴旋转 -160°。
  • afterEuler:表示绕 X 轴旋转 180°(PI),绕 y 轴旋转 -20°(-0.349065850398866 弧度),绕 z 轴旋转 180°(PI)。

euler 和 afterEuler 表示的旋转结果基本一致,但是 x,y, z 值相差巨大。

所以,当程序的一部分依靠 Euler 的单个绕轴旋转弧度,另一部分依靠 Quaternion 时,可能会出现差异。