首先,获得一个包围盒,three.js 的 geometry 对象都有生成包围盒的方法,有包围球和(矩形)包围盒两种,包围球的属性默认已经生成了可以直接访问,包围盒访问前则需要先调用mesh.geometry.computeBoundingBox()。这里有一种情况要考虑:物体是个group或有很多子物体,那么最简单的方法是使用辅助类:" var boxHelper = new THREE.BoxHelper(); boxHelper.setFromObject(mod);",后面举例都使用boxHelper来进行。
接着,访问包围盒属性,矩形:boxHelper.geometry.boundingBox,球形:boxHelper.geometry.boundingSphere。包围球通过半径能获知物体在空间中的大小和中心点;包围盒则是通过最大最小3轴确定物体大小通过geometry.center()获取中心点,任选一种即可。
最后,调整Object3D(所有3d物体的基类)对象位置和缩放比例来达到目标,这时可以这么做:
第一种方法,改变物体属性:
1.缩小物体比例,比例值根据包围球半径或包围盒最大x、z轴计算得到;
2.改变物体的位置,根据包围球或包围盒的大小缩放到合适比例后,position的xyz都设为0即可。
第二种方法,改变相机位置:
这里只根据包围球属性进行描述,包围盒类似。
z轴: 要想看到全景就得把相机往后退,根据半径改变z轴,这个地方大多数情况下camera.position.z = geometry.boundingSphere.radius * 2.2 + geometry.boundingSphere.center.z 就够了。
x轴:camera.position.x = center.x;
y轴:camera.position.y = center.y。
var boxHelper = new THREE.BoxHelper();
boxHelper.setFromObject(object);
boxHelper.geometry.computeBoundingSphere();//一定要先调用计算包围盒后再生成
var center = boxHelper.geometry.boundingSphere.center;//包围球中心
var radius = boxHelper.geometry.boundingSphere.radius;//包围球半径
var cameraPos = new THREE.Vector3(-object.position.x + radius * 1, object.position.y + radius, object.position.z + radius * 2);//相机自适应的位置
var lookPos = new THREE.Vector3(center.x + object.position.x, center.y + object.position.y, center.z + object.position.z);//相机及控制器自适应的目标
camera.position.copy(cameraPos);//初始化场景时,相机自适应的位置
orbitControls.target = lookPos;//初始化场景时,相机控制器的目标
camera.lookAt(lookPos);//初始化场景时,相机的目标,要在OrbitControls实例化之后
这里有个需要注意的地方:如果使用了THREE.OrbitControls进行鼠标控制,那么一定要加上controls.target = lookPos;并在OrbitControls创建了之后加上camera.lookAt(lookPos);
var controls = new THREE.OrbitControls( camera, domElement );
controls.target = lookPos;
camera.lookAt(lookPos);
如此,就能实现了。
附上效果图:
“小车”比“工人”大,通过包围球半径计算后不管大小都能最佳适配。
下面分别依次是:小车,有工人的小车,没有皮肤的工人,工人。
放入多个物体到场景中并且物体位置随机的情况下,想看到整体场景最佳适配到合适位置,如果是这样上面的方法依然有效,只需要把boxHelper的目标object改成场景scene即可:
boxHelper.setFromObject(scene);
只需要得到包围球(或包围盒),group跟scene类似,这里用group举例附包围盒效果图: