如何在Three.js中以最大比例展示大尺寸模型?

threeJs 模型尺寸很大,如何在canvas内最大比例展示呢?

得到的盒模型最大 减 去最小 尺寸为 7900, 但是canvas尺寸只有 700px。通过网上的代码得到的 scale 都无法达到效果,值还有为负数的,小于1的。该怎么让模型最大比例展示呢

const x = (box.max.x - box.min.x);
      const y = (box.max.y - box.min.y);
      const z = (box.max.z - box.min.z);
      // const maxDim = Math.max(x, y, z);
      const maxDim = Math.sqrt(x * x + y * y + z * z) / 2;
      console.log('maxDim', maxDim, camera.current);
      const scale = camera.current?.position.z  / maxDim;
      const scale = 50 / maxDim;
      const scale =  maxDim / (2 * Math.tan((boxSize * 100) * Math.PI / 360));;
      console.log('scale', scale);
      root.scale.set(scale, scale, scale);
阅读 204
avatarAI BotBETA

要在Three.js中以最大比例展示大尺寸模型,并且确保模型适应canvas尺寸,你需要计算适当的缩放比例(scale)并应用到模型上。以下是一个详细的步骤和代码示例,展示如何计算这个缩放比例并应用到你的模型中:

  1. 计算模型的尺寸
    你已经正确地计算了模型的尺寸(maxDim),这里我们采用模型的对角线长度作为参考尺寸。
  2. 计算缩放比例
    缩放比例应该基于canvas的尺寸和模型的尺寸来计算。确保模型在canvas中可见且尽可能大。
  3. 应用缩放比例
    将计算出的缩放比例应用到模型的根节点上。

以下是一个简化的代码示例:

// 假设 box 是模型的边界框(Box3),camera 是你的相机实例
const box = new THREE.Box3().setFromObject(yourModel); // 替换 yourModel 为你的模型实例
const x = box.max.x - box.min.x;
const y = box.max.y - box.min.y;
const z = box.max.z - box.min.z;

// 计算模型的对角线长度
const maxDim = Math.sqrt(x x + y y + z * z);

// 获取canvas的宽度和高度(假设是700x700)
const canvasWidth = 700;
const canvasHeight = 700;
const aspectRatio = canvasWidth / canvasHeight;

// 假设相机使用透视投影,并且你希望模型尽可能填充canvas
const fieldOfView = 75; // 视角(Field of View),通常是45度或75度
const near = 0.1; // 近裁剪面
const far = 10000; // 远裁剪面

// 计算相机的最佳距离(z轴位置)
const cameraDistance = maxDim / (2 * Math.tan(THREE.MathUtils.degToRad(fieldOfView) / 2));

// 计算缩放比例,使得模型的对角线长度等于canvas的对角线长度
// 注意:这里我们假设canvas是正方形,如果不是,你需要根据aspectRatio调整
const canvasDiagonal = Math.sqrt(canvasWidth canvasWidth + canvasHeight canvasHeight);
const scale = canvasDiagonal / maxDim;

// 应用缩放比例到模型
yourModel.scale.set(scale, scale, scale);

// 设置相机位置
camera.position.set(0, 0, cameraDistance);
camera.lookAt(0, 0, 0); // 确保相机看向模型的中心

// 更新渲染器和控制器(如果有的话)
renderer.setSize(canvasWidth, canvasHeight);
// 控制器设置(如OrbitControls)需要根据新的相机位置和缩放比例进行更新

注意:

  • 在这个示例中,我们假设canvas是正方形的(700x700),如果你的canvas不是正方形,你可能需要根据aspectRatio来调整相机的aspect属性或模型的缩放比例。
  • yourModel应该替换为你的实际模型实例。
  • camera是你的Three.js相机实例。
  • renderer是你的Three.js渲染器实例。

通过这种方式,你应该能够在大尺寸模型上应用适当的缩放比例,并在canvas中以最大比例展示它。

3 个回答

https://blog.csdn.net/shebao3333/article/details/129506771

参考这位博主的答案实现了模型最大化

const fov = camera.fov * ( Math.PI / 180 );
    const fovh = 2*Math.atan(Math.tan(fov/2) * camera.aspect);
    let dx = size.z / 2 + Math.abs( size.x / 2 / Math.tan( fovh / 2 ) );
    let dy = size.z / 2 + Math.abs( size.y / 2 / Math.tan( fov / 2 ) );
    let cameraZ = Math.max(dx, dy);

    // offset the camera, if desired (to avoid filling the whole canvas)
    if( offset !== undefined && offset !== 0 ) cameraZ *= offset;

    camera.position.set( 0, 0, cameraZ );

    // set the far plane of the camera so that it easily encompasses the whole object
    const minZ = boundingBox.min.z;
    const cameraToFarEdge = ( minZ < 0 ) ? -minZ + cameraZ : cameraZ - minZ;

    camera.far = cameraToFarEdge * 3;
    camera.updateProjectionMatrix();
————————————————
// 假设你有了 scene, camera, renderer,  model
const model = yourModel; // 换成你自己模型

// 1. 计算包围盒
const box = new THREE.Box3().setFromObject(model);
const x = (box.max.x - box.min.x);
const y = (box.max.y - box.min.y);
const z = (box.max.z - box.min.z);

// 2. 确定最大尺寸
const maxDim = Math.max(x, y, z);

// 3. 计算相机到模型中心的距离
const fov = camera.fov * (Math.PI / 180); // 把角度转换为弧度
let cameraZ = Math.abs(maxDim / 2 * Math.tan(fov / 2)); // 保持模型在视野范围内
cameraZ *= 1.2; //稍微放大一点点,免得边缘被裁切

// 4. 设置相机位置和朝向
camera.position.z = cameraZ;
//设置相机x,y位置,让模型居中
const centerX = (box.min.x + box.max.x) / 2;
const centerY = (box.min.y + box.max.y) / 2;
camera.position.x = centerX;
camera.position.y = centerY;

camera.lookAt(new THREE.Vector3(centerX, centerY, 0)); // 让相机看向模型中心

// 5. 根据画布大小调整相机参数
const canvas = renderer.domElement; 
const aspectRatio = canvas.clientWidth / canvas.clientHeight;
camera.aspect = aspectRatio;
camera.updateProjectionMatrix(); // 更新投影矩阵

// 6. 设置模型的中心点
const center = box.getCenter(new THREE.Vector3());
model.position.sub(center); // 把模型的中心点移动到原点
const objDataUrl = 'model.glb';
const loader = new GLTFLoader();
loader.load(objDataUrl, (gltf) => {
  const scene = gltf.scene;
  const box = new THREE.Box3().setFromObject(scene);
  const center = new THREE.Vector3();
  box.getCenter(center);
  const size = new THREE.Vector3();
  box.getSize(size);
  
  // 计算模型对角线长度
  const maxDim = Math.sqrt(
    size.x * size.x + 
    size.y * size.y + 
    size.z * size.z
  );
  
  // 计算缩放比例,使用canvas的较小边作为参考
  const canvasWidth = this.renderer.domElement.width;  // 700
  const canvasHeight = this.renderer.domElement.height; // 600
  const canvasMaxDim = Math.min(canvasWidth, canvasHeight); // 600
  
  // 添加一个安全系数0.8,确保模型完全在画布内
  const scale = (canvasMaxDim / maxDim) * 0.8;
  
  // 应用缩放
  scene.scale.set(scale, scale, scale);
  
  // 将模型中心移动到原点(注意要考虑缩放)
  center.multiplyScalar(scale);
  scene.position.sub(center);
  
  this.scene.add(scene);
  this.calcMeshCenter(scene);

  // 设置相机
  const camera = this.camera;
  // 假设使用透视相机,FOV为45度
  camera.fov = 45;
  // 将相机放置在适当距离,确保能看到整个模型
  const scaledMaxDim = maxDim * scale;
  const distance = (scaledMaxDim / 2) / Math.tan((camera.fov / 2) * Math.PI / 180);
  camera.position.set(0, 0, distance);
  camera.near = distance / 100;
  camera.far = distance * 3;
  camera.updateProjectionMatrix();
  camera.lookAt(0, 0, 0);

}, (xhr) => {
  const process = Math.floor((xhr.loaded / xhr.total) * 100);
  if (process === 100) {
    this.showProcess = false;
  }
}, (error) => {
  console.error('error', error);
});
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
宣传栏