三和 Tween.js - 不必要的旋转,这是万向节锁吗?

Three and Tween.js - unwanted spinning, is this gimbal lock?

我正在从这里补间对象

Position (X:82.22, Y:-8.31, Z:57.75)
Rotation (X:-3.00, Y:-0.95, Z:-3.02)

到这里

Position (X:57.36, Y:-8.31, Z:93.78)
Rotation (X:-3.05, Y:-0.55, Z:-3.10)

与这个补间

            behaviour.tween = new TWEEN.Tween(behaviour.origin).to(behaviour.target,behaviour.offsetTime * 1000)
            .onUpdate(function(){

                hotspot.position.x = behaviour.origin.pX;
                hotspot.position.y = behaviour.origin.pY;
                hotspot.position.z = behaviour.origin.pZ;
                hotspot.rotation.x = behaviour.origin.rX;
                hotspot.rotation.y = behaviour.origin.rY;
                hotspot.rotation.z = behaviour.origin.rZ;
                hotspot.scale.set(behaviour.origin.scale,behaviour.origin.scale,behaviour.origin.scale);
                hotspot.opacity = behaviour.origin.opacity;

            }).

对象在场景中移动时沿 z 轴旋转。

这应该是云台锁吧?如果是这样,解决这个问题的方法是什么?

使用四元数进行转换总是更安全。对我来说,它在不使用 slerp 的情况下工作得很好,但只使用 Tween.js.

// excerpt from my code
var q = obj.quaternion.clone().multiply(new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(1,0,0), theta));

new TWEEN.Tween(obj.quaternion)
  .to(q, time)
  .onUpdate(function () { object.quaternion.copy(this); }) // onUpdate isn't really needed in this case
  .start();

所以,对你来说,它应该与这样的东西一起工作:

behaviour.origin.position = new THREE.Vector3(82.22, -8.31, 57.75);
behaviour.origin.quaternion = ew THREE.Quaternion().setFromEuler(new THREE.Euler(-3.00, -0.95, 3.02));

behaviour.target.position = new THREE.Vector(57.36, -8.31, 93.78);
behaviour.target.quaternion = ew THREE.Quaternion().setFromEuler(new THREE.Euler(3.05, -0.55, 3.10));

new TWEEN.Tween(behaviour.origin)
  .to(behaviour.target, behaviour.offsetTime * 1000)
  .onUpdate(function () {
    hotspot.position.copy(behaviour.origin.position);
    hotspot.quaternion.copy(behaviour.origin.quaternion);
  })
  .start();

更新: 好的,建议使用四元数 slerp(),否则它也会导致奇怪的行为。因此,我想代码应该是这样的:

behaviour.origin.position = new THREE.Vector3(82.22, -8.31, 57.75);
behaviour.origin.quaternion = new THREE.Quaternion().setFromEuler(new THREE.Euler(-3.00, -0.95, 3.02));

behaviour.target.position = new THREE.Vector(57.36, -8.31, 93.78);
behaviour.target.quaternion = new THREE.Quaternion().setFromEuler(new THREE.Euler(3.05, -0.55, 3.10));

behaviour.origin.t = 0;
behaviour.target.t = 1;

new TWEEN.Tween(behaviour.origin)
  .to(behaviour.target, behaviour.offsetTime * 1000)
  .onUpdate(function () {
    hotspot.position.copy(behaviour.origin.position);
    THREE.Quaternion.slerp(behaviour.origin.quaternion, behaviour.target.quaternion, hotspot.quaternion, behaviour.origin.t);
  })
  .start();