three.js结合Tween+lookAt实现相机动画时意外旋转问题求解
问题原因
你遇到的意外旋转是万向锁奇点导致的:当动画结束时,相机位置为(0,20,0),lookAt目标为(0,0,0),此时相机视线方向为(0,-1,0),和Three.js相机默认的up向量(0,1,0)完全反向共线,lookAt方法无法正常计算相机的水平朝向,就会出现突然跳转的异常。
解决方案
- 方案1:微调相机终点坐标(改动最小)
只要让相机终点不要完全落在Y轴上,避免视线和up向量共线即可,视觉上和完全俯瞰没有差异,修改后的代码如下:
function TWEEN_begin_CAMERA_1() { const tweenCamera1 = new TWEEN.Tween( {x: camera.position.x, y: camera.position.y, z: camera.position.z, lookAtX: 0, lookAtY: 0, lookAtZ: 0} ) // 仅修改x、z的终点值为极小的非0值 .to( {x: 0.001, y: 20, z: 0.001, lookAtX: 0, lookAtY: 0, lookAtZ: 0}, 1000 ) const updateCamera = function (object, elapsed) { camera.position.set(object.x, object.y, object.z); camera.lookAt(new THREE.Vector3(object.lookAtX, object.lookAtY, object.lookAtZ)) } tweenCamera1.onUpdate(updateCamera) tweenCamera1.start() }
- 方案2:修改相机up向量(不需要调整坐标)
如果你需要相机严格在Y轴正上方,可以手动调整up向量避免和视线共线,如果后续需要恢复默认视角,重新执行camera.up.set(0,1,0)即可:
const updateCamera = function (object, elapsed) { camera.position.set(object.x, object.y, object.z); camera.up.set(0, 0, 1); camera.lookAt(new THREE.Vector3(object.lookAtX, object.lookAtY, object.lookAtZ)) }
- 方案3:补间相机四元数(最稳定,适合复杂相机动画)
直接预先计算起始和结束状态的相机朝向四元数进行补间,彻底避免lookAt的计算异常:
function TWEEN_begin_CAMERA_1() { // 保存当前相机四元数作为起点 const startQuat = camera.quaternion.clone(); // 计算终点朝向四元数 const endPos = new THREE.Vector3(0,20,0); const lookAtTarget = new THREE.Vector3(0,0,0); const tempCamera = camera.clone(); tempCamera.position.copy(endPos); tempCamera.up.set(0,0,1); tempCamera.lookAt(lookAtTarget); const endQuat = tempCamera.quaternion.clone(); // 补间位置和四元数 const tweenCamera1 = new TWEEN.Tween({ x: camera.position.x, y: camera.position.y, z: camera.position.z, qx: startQuat.x, qy: startQuat.y, qz: startQuat.z, qw: startQuat.w }) .to({ x: 0, y: 20, z: 0, qx: endQuat.x, qy: endQuat.y, qz: endQuat.z, qw: endQuat.w }, 1000) .onUpdate(function(obj) { camera.position.set(obj.x, obj.y, obj.z); camera.quaternion.set(obj.qx, obj.qy, obj.qz, obj.qw); }) .start() }
内容的提问来源于stack exchange,提问作者Ruslan Karimov
相关产品推荐
相关产品推荐

