经纬志
首页 / three.js / 使用示例

多相机

同一份场景渲染四次:鸟瞰、正交俯视、平视与长焦特写,共用一块画布。

three.js 0.160.0 · 更新 2026-10-28
源码与运行效果
运行效果

说明

四台相机共用同一条场景数据,只改变观察方式。 每台相机渲染前都要按自己的视口比例更新投影: 透视相机改 aspect,正交相机重设四个边界。 这一步漏掉时,画面会横向压扁。

左下角是平视视角,机位高度与人眼接近,能看到楼体的立面与遮挡关系; 右上角换成正交俯视,楼间距与路网位置最清楚,且没有近大远小。 两者的差别正是选择投影方式时最需要判断的地方。

视口相机设置
左上透视视野 45 度,机位 (58, 44, 62),可拖拽旋转
右上正交俯视,up 设为 (0, 0, −1),纵向可见 84 单位
左下透视视野 55 度,机位高度 7,平视
右下透视视野 22 度,长焦压缩空间
楼群—140 个立方体,高度按序号取模
参考物—160 单位网格与一根北向细柱

视口与裁剪矩形

renderer.setScissorTest(true);

function renderView(cam, x, y, w, h) {
  renderer.setViewport(x, y, w, h);
  renderer.setScissor(x, y, w, h);

  if (cam.isOrthographicCamera) {
    const halfH = 42;
    const halfW = halfH * (w / h);
    cam.left = -halfW;
    cam.right = halfW;
    cam.top = halfH;
    cam.bottom = -halfH;
    cam.updateProjectionMatrix();
  } else {
    cam.aspect = w / h;
    cam.updateProjectionMatrix();
  }

  renderer.render(scene, cam);
}

setViewport 决定画在哪里,setScissor 决定哪块区域允许被写入,两者通常取相同的矩形。 坐标原点在画布左下角,Y 轴向上,这跟 CSS 相反, 所以「左上」的实际参数是 y = H / 2。

开启裁剪测试后,每次渲染的自动清屏也被限制在裁剪矩形内, 因此四个视口不会互相擦除背景。这也是必须两边都设置的原因。

交互挂在哪台相机上

OrbitControls 只绑定了一个相机与一个 DOM 元素, 拖拽会作用在整个画布上,但只有左上角的透视视图随之变化。 多视口若都要交互,需要按指针位置判断落在哪个象限, 再切换 controls.object,或为每个视口各建一套控制器。

单视口按钮把整块画布交给透视相机,并隐藏其余三个标签。 切换只改渲染调用,场景数据没有重建,所以没有额外开销。

正交相机的宽高比

正交相机没有 aspect 属性,比例完全由四个边界决定。 固定纵向范围、按宽高比推算横向范围的写法, 能保证不同视口尺寸下地物不被拉伸,方格仍是方格。

多相机不是多图层。四台相机看到的是同一份场景, 只是投影不同。要按图层分别控制可见性,应使用 Object3D.layers 或手动切换 visible, three.js 不会因为相机不同而自动分区。