直接看效果
| 调整前 | 调整后 | 
|---|---|
|  |  | 
调整后模型可以全部展示,不会超出显示区域,有一些比较小的模型也是可以放大显示的
直接贴代码
            
            
              js
              
              
            
          
          function fitOnScreen() {
  const box = new THREE.Box3().setFromObject(bldg);
  const boxSize = box.getSize(new THREE.Vector3()).length();
  const boxCenter = box.getCenter(new THREE.Vector3());
  frameArea(boxSize * 1.5, boxSize, boxCenter);
  controls.maxDistance = boxSize * 10;
  controls.target.copy(boxCenter);
  controls.update();
}
function frameArea(sizeToFitOnScreen, boxSize, boxCenter) {
  const halfSizeToFitOnScreen = sizeToFitOnScreen * 0.5;
  const halfFovY = THREE.MathUtils.degToRad(camera.fov * 0.5);
  const distance = halfSizeToFitOnScreen / Math.tan(halfFovY);
  const direction = new THREE.Vector3()
    .subVectors(camera.position, boxCenter)
    .multiply(new THREE.Vector3(1, 0, 1))
    .normalize();
  camera.position.copy(direction.multiplyScalar(distance).add(boxCenter));
  
  camera.near = boxSize / 100;
  camera.far = boxSize * 100;
  camera.updateProjectionMatrix();
  camera.lookAt(boxCenter.x, boxCenter.y, boxCenter.z);
}首页声明,上面代码是我在three.js官网demo里面复制,这里只是做代码解读
上面的代码是一个用于调整相机位置以适应场景中对象的函数。
- 函数fitOnScreen用于计算场景中对象的包围盒大小,并根据大小和中心点调整相机和控制器的位置。
- 函数frameArea用于根据给定的尺寸,计算相机的位置和截锥体的近平面和远平面。
fitOnScreen
1. 使用Box3对象获取场景中所有对象的包围盒。
            
            
              js
              
              
            
          
            // 计算包围盒大小及中心点
  const box = new THREE.Box3().setFromObject(scene);
  // 添加包围盒的辅助对象
  const boxHelper = new THREE.BoxHelper(bldg, 0xffff00);
  scene.add(boxHelper);
2. 计算包围盒的尺寸和中心点
            
            
              js
              
              
            
          
            const boxSize = box.getSize(new THREE.Vector3()).length();
  const boxCenter = box.getCenter(new THREE.Vector3());getSize 函数用于获取物体的尺寸(即包围盒的宽度、高度和深度),并返回一个新的 Vector3 向量,向量的三个分量分别表示包围盒在X、Y和Z轴上的尺寸。
然后,.length() 函数用于计算向量的长度(模)。对于 Vector3 向量,长度可以通过计算其三个分量的平方和的平方根来获取。即 length = √(x^2 + y^2 + z^2)。
在给定的代码中,getSize(new THREE.Vector3()) 返回的是一个 Vector3 向量,表示包围盒的尺寸。然后,.length() 函数应用于该向量,计算并返回包围盒尺寸的长度,即包围盒的对角线的长度。这个长度可以用于表示包围盒的大小或用于其他计算任务。
对于一些gemoetry可以使用其它方法处理
            
            
              js
              
              
            
          
          geometry.computeBoundingBox();
let { min, max } = geometry.boundingBox;
// 获取物体的高度差
let uHeight = max.y - min.y;
let uWidth = max.y - min.x;3. 调用frameArea函数,传入包围盒的尺寸以及中心点。
这里先不展开解释
4. 设置控制器的maxDistance属性,限制相机与场景中心的最大距离。
controls.maxDistance = boxSize * 10;
通俗点,就是不能让用户把场景模型缩得太小
5. 将控制器的target属性设置为包围盒的中心点,并且更新控制器。
        
            
            
              js
              
              
            
          
            // 控制器将以 boxCenter 为中心进行旋转和缩放操作。
  controls.target.copy(boxCenter);
  // 摄像机的变换发生任何手动改变后调用
  controls.update();frameArea
传入三个参数
- sizeToFitOnScreen 需要适应的屏幕大小
- boxSize 模型大小
- boxCenter 模型中心坐标
1. 根据计算出的尺寸,将其一半设置为适应屏幕的一半尺寸
2. 使用相机的垂直视角一半以及尺寸计算相机与目标之间的距离
            
            
              js
              
              
            
          
            // 一半,看下面
  const halfSizeToFitOnScreen = sizeToFitOnScreen * 0.5;
  // 角度转弧度
  const halfFovY = THREE.MathUtils.degToRad(camera.fov * 0.5);
  // 求得相机到模型的距离
  const distance = halfSizeToFitOnScreen / Math.tan(halfFovY);

3. 计算一个单位向量,指向相机在xz平面上的方向。
            
            
              js
              
              
            
          
            const direction = new THREE.Vector3()
    .subVectors(camera.position, boxCenter)
    .multiply(new THREE.Vector3(1, 0, 1))
    .normalize();- new THREE.Vector3()创建一个新的三维向量对象
- .subVectors(camera.position, boxCenter)计算两个向量的差值,即从包围盒中心指向相机位置的向量

- .multiply(new THREE.Vector3(1, 0, 1))其实就是把y轴置零,x z轴不变
- .normalize();得到一个表示方向的单位向量
向量归一化,就是等比例缩放向量的xyz三个分量,缩放到向量长度.length()为1。
            
            
              js
              
              
            
          
          const dir = new THREE.Vector3(1, 1, 0);
dir.normalize(); //向量归一化
console.log('dir',dir);
//Vector3(√2/2, √2/2, 0)   Vector3(0.707, 0.707, 0)
4. 根据距离和中心点,设置相机的位置
camera.position.copy(direction.multiplyScalar(distance).add(boxCenter));
- direction.multiplyScalar(distance)单位向量乘以距离
- add(boxCenter)起点平移到boxCenter的位置
- camera.position.copy()最后,我们将相机的位置设置为新计算得到的向量。使用- copy函数可以将新向量的值复制到- camera.position中,从而将相机移动到新的位置。
5. 计算适当的近平面和远平面的值
            
            
              js
              
              
            
          
            camera.near = boxSize / 100;
  camera.far = boxSize * 100;6. 更新相机的投影矩阵
camera.updateProjectionMatrix(); 更新摄像机投影矩阵。在任何参数被改变以后必须被调用。
7. 将相机的视角对准包围盒的中心。
camera.lookAt(boxCenter.x, boxCenter.y, boxCenter.z); 外层控制器调整target也会调整相机焦点的
总结
其实也没什么好总结的,个人理解,这代码只要针对加载的模型有大有小,要动态调整相机及控制器,达到比较好的显示效果。