You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 10:16:11