依次围绕世界轴旋转 threejs 对象(外部欧拉角)

Sequentially rotate threejs object around world axes (extrinsic Euler angles)

我正在创建外部欧拉角旋转的可视化,我想要一个立方体根据用户输入围绕世界轴旋转的动画。我有一个带有 x、y 和 z 旋转角度控件的 dat.GUI 控件。 See this screenshot.

到目前为止,我已经能够实现 内部 旋转,只需使用 cube_axes.rotation.x(和 .y.z)并设置立方体旋转。我的 GUI 代码如下所示:

gui.add(params, 'x_rot').name('X rotation').min(-180).max(180).step(5).onChange(() => {
        cube_axes.rotation.x = toRadians(params.x_rot)
})
gui.add(params, 'y_rot').name('Y rotation').min(-180).max(180).step(5).onChange(() => {
        cube_axes.rotation.y = toRadians(params.y_rot)
})
gui.add(params, 'z_rot').name('Z rotation').min(-180).max(180).step(5).onChange(() => {
        cube_axes.rotation.z = toRadians(params.z_rot)
})

当用户移动 x 旋转控件时,立方体将围绕其局部 x 轴旋转指定的度数。然后,当用户移动 y 旋转控件时,already-rotated 立方体围绕其局部 y 轴旋转。

然而,我在 外部 旋转时遇到的问题是,立方体会擦除以前的旋转(本质上是自我重置)并简单地旋转正在更改的控件。因此,立方体永远不会在之前的旋转之上旋转。这是我的代码:

gui.add(params, 'x_rot').name('X rotation').min(-180).max(180).step(5).onChange(() => {
        //cube_axes.setRotationFromAxisAngle(x_vector, toRadians(params.x_rot))
        let quaternion = new THREE.Quaternion().setFromAxisAngle(x_vector, toRadians(params.x_rot));
        cube_axes.rotation.setFromQuaternion(quaternion);
})
gui.add(params, 'y_rot').name('Y rotation').min(-180).max(180).step(5).onChange(() => {
        //cube_axes.setRotationFromAxisAngle(y_vector, toRadians(params.y_rot))
        let quaternion = new THREE.Quaternion().setFromAxisAngle(y_vector, toRadians(params.y_rot));
        cube_axes.rotation.setFromQuaternion(quaternion);
})
gui.add(params, 'z_rot').name('Z rotation').min(-180).max(180).step(5).onChange(() => {
        //cube_axes.setRotationFromAxisAngle(z_vector, toRadians(params.z_rot))
        let quaternion = new THREE.Quaternion().setFromAxisAngle(z_vector, toRadians(params.z_rot));
        cube_axes.rotation.setFromQuaternion(quaternion);
})

我试过使用 .setFromQuaternion(来自 this question)和 .setRotationFromAxisAngle(注释掉的行),但两种方法都有同样的问题。我不确定这里发生了什么。是因为我使用 .rotation 而不是特定的旋转轴(.rotation.x.rotation.y.rotation.z)吗?

谢谢。

我明白了!使用 .applyQuaternion 而不是 .setFromQuaternion。根据我的理解,这在已经存在的内容之上应用了旋转,而不是完全重置它。这是我的代码:

gui.add(params, 'x_rot').name('X rotation').min(-180).max(180).step(5).onChange(() => {
    let quaternion = new THREE.Quaternion().setFromAxisAngle(x_vector, toRadians(params.x_rot));
    cube_axes.applyQuaternion(quaternion);
})
gui.add(params, 'y_rot').name('Y rotation').min(-180).max(180).step(5).onChange(() => {
    let quaternion = new THREE.Quaternion().setFromAxisAngle(y_vector, toRadians(params.y_rot));
    cube_axes.applyQuaternion(quaternion);
})
gui.add(params, 'z_rot').name('Z rotation').min(-180).max(180).step(5).onChange(() => {
    let quaternion = new THREE.Quaternion().setFromAxisAngle(z_vector, toRadians(params.z_rot));
    cube_axes.applyQuaternion(quaternion);
})

请注意,此实现不使用三个对象的 rotation 属性。

编辑:对于那些试图做同样事情的人,您还需要一个额外的变量来跟踪先前的参数,以便您可以应用正确的角度。否则,您最终会得到不正确的旋转(只要控件发生变化,旋转就会继续添加另一个角度)。 请看下面的代码:

let prev_params = {
    x_rot: 0,
    y_rot: 0,
    z_rot: 0,
}

然后 GUI onChange 函数中的这段代码(我只包含了 x 的代码):

let angle = toRadians(params.x_rot)
if (prev_params.x_rot) {
    angle = angle - toRadians(prev_params.x_rot)
}
let quaternion = new THREE.Quaternion().setFromAxisAngle(x_vector, angle)
cube_axes.applyQuaternion(quaternion)

prev_params.x_rot = params.x_rot