如何避免相机跳跃during/after Tween/animation?
How to avoid camera jumps during/after Tween/animation?
我在 THREE.js 中创建相机 Tween 时遇到了一些问题,特别是在动画的结尾和开头,似乎总是有一个相机 'jump',这意味着相机一旦动画开始和动画结束就会闪烁。作为参考,我正在做的是:
摄像头俯视场景
当用户点击场景中的元素时,相机会放大它(通过 TWEEN),当它足够近时,OrbitControls 目标会更改为所选元素的质心,并自动旋转开始,所以用户看到元素在屏幕中央旋转。
当用户再次单击时,相机会缩小到其初始位置(通过 TWEEN)并返回到原始控件。
我在每个 TWEEN 的开头和结尾都遇到了 'jumps/flickers'。
这是我的补间函数:
var origpos = new THREE.Vector3().copy(camera.position); // original position
var origrot = new THREE.Euler().copy(camera.rotation); // original rotation
camera.position.set(x, y+500, z+variation);
camera.lookAt(new THREE.Vector3(x,y,z));
var dstrot = new THREE.Euler().copy(camera.rotation)
// reset original position and rotation
camera.position.set(origpos.x, origpos.y, origpos.z);
camera.rotation.set(origrot.x, origrot.y, origrot.z);
options = {duration: 3000};
//
// Tweening
//
// position
new TWEEN.Tween(camera.position).to({
x: x,
y: y+500,
z: z
}, options.duration).easing(TWEEN.Easing.Cubic.Out).onUpdate(function () {
camera.lookAt(new THREE.Vector3(x,y,z));
}).onComplete(function () {
controls.autoRotate = true;
controls.autoRotateSpeed = 5.0;
controls.target = new THREE.Vector3(x, y, z);
}).start();
// rotation (using slerp)
(function () {
var qa = camera.quaternion; // src quaternion
var qb = new THREE.Quaternion().setFromEuler(dstrot); // dst quaternion
var qm = new THREE.Quaternion();
var o = {t: 0};
new TWEEN.Tween(o).to({t: 1}, options.duration).onUpdate(function () {
THREE.Quaternion.slerp(qa, qb, qm, o.t);
camera.quaternion.set(qm.x, qm.y, qm.z, qm.w);
}).start();
}).call(this);
好的,看来问题出在我使用四元数和 SLERP 旋转相机的方法本身。
我发现最好的方法(更简单且没有 flicker/jump)是插入 camera.rotation 的参数而不是插入四元数。
所以,camera.rotation.the_axis_where_you_want_to_rotate 的 Tween 完美地工作,并且与位置上的 Tween 同时完成,达到了我想要的效果。
我在 THREE.js 中创建相机 Tween 时遇到了一些问题,特别是在动画的结尾和开头,似乎总是有一个相机 'jump',这意味着相机一旦动画开始和动画结束就会闪烁。作为参考,我正在做的是:
摄像头俯视场景
当用户点击场景中的元素时,相机会放大它(通过 TWEEN),当它足够近时,OrbitControls 目标会更改为所选元素的质心,并自动旋转开始,所以用户看到元素在屏幕中央旋转。
当用户再次单击时,相机会缩小到其初始位置(通过 TWEEN)并返回到原始控件。
我在每个 TWEEN 的开头和结尾都遇到了 'jumps/flickers'。
这是我的补间函数:
var origpos = new THREE.Vector3().copy(camera.position); // original position
var origrot = new THREE.Euler().copy(camera.rotation); // original rotation
camera.position.set(x, y+500, z+variation);
camera.lookAt(new THREE.Vector3(x,y,z));
var dstrot = new THREE.Euler().copy(camera.rotation)
// reset original position and rotation
camera.position.set(origpos.x, origpos.y, origpos.z);
camera.rotation.set(origrot.x, origrot.y, origrot.z);
options = {duration: 3000};
//
// Tweening
//
// position
new TWEEN.Tween(camera.position).to({
x: x,
y: y+500,
z: z
}, options.duration).easing(TWEEN.Easing.Cubic.Out).onUpdate(function () {
camera.lookAt(new THREE.Vector3(x,y,z));
}).onComplete(function () {
controls.autoRotate = true;
controls.autoRotateSpeed = 5.0;
controls.target = new THREE.Vector3(x, y, z);
}).start();
// rotation (using slerp)
(function () {
var qa = camera.quaternion; // src quaternion
var qb = new THREE.Quaternion().setFromEuler(dstrot); // dst quaternion
var qm = new THREE.Quaternion();
var o = {t: 0};
new TWEEN.Tween(o).to({t: 1}, options.duration).onUpdate(function () {
THREE.Quaternion.slerp(qa, qb, qm, o.t);
camera.quaternion.set(qm.x, qm.y, qm.z, qm.w);
}).start();
}).call(this);
好的,看来问题出在我使用四元数和 SLERP 旋转相机的方法本身。
我发现最好的方法(更简单且没有 flicker/jump)是插入 camera.rotation 的参数而不是插入四元数。
所以,camera.rotation.the_axis_where_you_want_to_rotate 的 Tween 完美地工作,并且与位置上的 Tween 同时完成,达到了我想要的效果。