问题描述
我正在创建外部欧拉角旋转的可视化,我想要一个动画,其中立方体根据用户输入围绕世界轴旋转。我有一个带有 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
)?
谢谢。
解决方法
我想通了!使用 .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