围绕世界轴顺序旋转threejs对象(外在欧拉角)

时间:2021-03-29 00:23:24

标签: three.js rotation euler-angles dat.gui

我正在创建外部欧拉角旋转的可视化,我想要一个动画,其中立方体根据用户输入围绕世界轴旋转。我有一个带有 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 旋转控件时,已旋转立方体将围绕其局部 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)?

谢谢。

1 个答案:

答案 0 :(得分:0)

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

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