如何在Three.js正交相机场景中使点击对象居中屏幕
嘿,这个需求其实挺常见的,我来给你拆解下具体怎么实现——毕竟正交相机的逻辑和透视相机有点不一样,得抓住它的核心特点来搞:
实现步骤详解
第一步:搞定点击拾取,精准定位目标对象
首先你得能准确拿到用户点击的那个带白色圆圈标注的对象,Three.js里用Raycaster就能轻松实现:
const raycaster = new THREE.Raycaster(); const mouse = new THREE.Vector2(); // 监听点击事件 window.addEventListener('click', (event) => { // 把浏览器的鼠标坐标转换成Three.js的标准化设备坐标 mouse.x = (event.clientX / window.innerWidth) * 2 - 1; mouse.y = -(event.clientY / window.innerHeight) * 2 + 1; // 从相机位置发射射线 raycaster.setFromCamera(mouse, camera); // 检测场景中被射线击中的对象,第二个参数true表示递归检测子对象 const intersects = raycaster.intersectObjects(scene.children, true); if (intersects.length > 0) { // 取第一个击中的对象(最上层的) const targetObj = intersects[0].object; // 执行居中逻辑 centerObjectToScreen(targetObj); } });
第二步:正交相机下的对象居中核心逻辑
正交相机的视口是轴对齐的矩形,它的位置、缩放参数决定了可见区域。要让目标对象移到屏幕中央,本质是让相机的视口中心和对象的世界中心对齐:
1. 先获取对象的真实世界中心
如果对象本身有几何偏移,或者是嵌套在父对象里,最好用包围盒来计算它的真实中心:
function getObjectWorldCenter(obj) { const boundingBox = new THREE.Box3().setFromObject(obj); const center = new THREE.Vector3(); boundingBox.getCenter(center); return center; }
2. 调整相机位置实现居中
正交相机默认是看向-z轴方向,所以我们只需要让相机的x、y轴位置和对象的世界中心一致就行(z轴位置不用动,因为正交相机不考虑远近)。如果你的相机有旋转,那就需要把对象中心转换到相机局部坐标系后再计算偏移:
function centerObjectToScreen(targetObj) { const objWorldCenter = getObjectWorldCenter(targetObj); // 普通轴对齐场景(比如顶视图、前视图)直接平移相机 camera.position.x = objWorldCenter.x; camera.position.y = objWorldCenter.y; // 如果你相机有旋转(比如非轴对齐视角),用下面这段替代上面的赋值: // const cameraLocalCenter = camera.worldToLocal(objWorldCenter.clone()); // camera.position.add(cameraLocalCenter); // 必须更新相机投影矩阵,否则修改不会生效 camera.updateProjectionMatrix(); }
可选:给居中加上平滑过渡动画
如果不想让相机瞬间跳过去,用Tween.js做个缓动动画会更友好:
// 先引入Tween.js,然后修改centerObjectToScreen函数 function centerObjectToScreen(targetObj) { const objWorldCenter = getObjectWorldCenter(targetObj); new TWEEN.Tween(camera.position) .to({ x: objWorldCenter.x, y: objWorldCenter.y }, 600) // 600ms完成动画 .easing(TWEEN.Easing.Quadratic.InOut) // 选个平滑的缓动曲线 .onUpdate(() => { camera.updateProjectionMatrix(); }) .start(); } // 别忘了在你的渲染循环里加上这句 function animate() { requestAnimationFrame(animate); TWEEN.update(); renderer.render(scene, camera); }
几个注意事项
- 如果目标对象是父对象的子元素,
setFromObject会自动考虑父对象的变换,不用额外处理。 - 相机的
zoom缩放属性不影响居中逻辑,哪怕你调整了缩放,只要相机位置对齐对象中心,它依然会在屏幕中央。 - 要是你想让对象居中后占满一定屏幕比例,可以在居中后根据对象包围盒大小和视口尺寸,计算调整相机的
zoom值。
内容的提问来源于stack exchange,提问作者Patel Hardik
相关产品推荐
相关产品推荐

