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

Three.js正交相机下模型跨设备自适应位置(非match media方案)

问题描述

我正试图找到最佳方案,让模型在所有设备上的位置(必要时包含缩放)适配,且无需仅依赖match media。显然我无法使用百分比,因此想了解Three.js是否有内置功能可助我实现理想效果,也欢迎提供其他可行方案。目前我的场景中使用的是正交相机(orthographic camera)。

实际情况

期望效果:
期望效果

窗口调整大小时模型被裁切:
裁切效果

当前Resize代码

rendererSize.width = window.innerWidth;
rendererSize.height = window.innerHeight;

aspect = rendererSize.width / rendererSize.height;

//* [ORTHOGRAPHIC CAMERA]
camera.left = -f * aspect;
camera.right = f * aspect;

camera.updateProjectionMatrix();
renderer.setSize(rendererSize.width, rendererSize.height);

解决方案

针对正交相机的适配问题,不用依赖matchMedia,可以用以下几种实用方案:

1. 基于模型边界盒动态调整相机参数

这是最精准的方案,先计算模型的包围盒,再根据窗口宽高比调整相机可视范围,确保模型始终完整显示:

// 先计算目标模型的包围盒
const box = new THREE.Box3().setFromObject(yourModel);
const size = new THREE.Vector3();
box.getSize(size);
const modelWidth = size.x;
const modelHeight = size.y;

function onWindowResize() {
  const width = window.innerWidth;
  const height = window.innerHeight;
  const aspect = width / height;

  // 可自定义边距比例,比如1.2就是保留20%的留白
  const paddingRatio = 1.2;
  const targetWidth = modelWidth * paddingRatio;
  const targetHeight = modelHeight * paddingRatio;

  // 根据窗口宽高比适配,避免裁切
  if (aspect > targetWidth / targetHeight) {
    // 窗口偏宽,以模型高度为基准计算相机范围
    camera.top = targetHeight / 2;
    camera.bottom = -camera.top;
    camera.left = -camera.top * aspect;
    camera.right = camera.top * aspect;
  } else {
    // 窗口偏高,以模型宽度为基准计算相机范围
    camera.left = -targetWidth / 2;
    camera.right = targetWidth / 2;
    camera.top = camera.right / aspect;
    camera.bottom = -camera.top;
  }

  camera.updateProjectionMatrix();
  renderer.setSize(width, height);
}

2. 固定相机可视比例,动态调整位置

如果不需要精准匹配模型尺寸,也可以固定相机的基础可视范围,再根据窗口比例调整相机位置,保证模型始终在目标区域:

function onWindowResize() {
  const width = window.innerWidth;
  const height = window.innerHeight;
  const aspect = width / height;

  // 设定基础可视范围大小
  const baseRange = 10;
  if (aspect > 1) {
    // 宽屏模式:以高度为基准
    camera.top = baseRange / 2;
    camera.bottom = -camera.top;
    camera.left = -camera.top * aspect;
    camera.right = camera.top * aspect;
  } else {
    // 竖屏模式:以宽度为基准
    camera.left = -baseRange / 2;
    camera.right = baseRange / 2;
    camera.top = camera.right / aspect;
    camera.bottom = -camera.top;
  }

  // 示例:让模型固定在屏幕右下区域,调整相机位置
  camera.position.set(camera.right * 0.8, camera.bottom * 0.8, 10);
  camera.lookAt(yourModel.position);

  camera.updateProjectionMatrix();
  renderer.setSize(width, height);
}

3. 动态调整模型缩放(应急方案)

如果相机参数调整太繁琐,也可以直接根据窗口比例缩放模型,注意保持模型原始比例:

function onWindowResize() {
  const width = window.innerWidth;
  const height = window.innerHeight;
  const aspect = width / height;

  // 设定模型原始适配的目标宽高比,比如16:9
  const targetAspect = 16 / 9;
  if (aspect > targetAspect) {
    yourModel.scale.set(1, 1 / aspect * targetAspect, 1);
  } else {
    yourModel.scale.set(aspect / targetAspect, 1, 1);
  }

  renderer.setSize(width, height);
}

关键注意事项

  • 你当前代码裁切的核心原因是固定f值计算相机左右范围,宽高比变化时可视范围无法覆盖模型,必须动态计算参数。
  • 调整相机参数后必须调用camera.updateProjectionMatrix(),否则修改不会生效。
  • 若场景有多个模型,计算包围盒时要把所有模型都包含进去(用box.expandByObject(otherModel))。

内容的提问来源于stack exchange,提问作者aka_lux

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 21:35:03