在Three.js中,包围盒(Bounding Box)和包围球(Bounding Sphere)是两种常见的用于简化碰撞检测和空间查询的几何体
包围盒
- 碰撞检测:包围盒是一个简单的几何空间,里面包含着复杂形状的物体。通过为物体添加包围盒,可以在进行精确的碰撞检测之前进行过滤,即当包围盒碰撞时,才进行精确的碰撞检测和处理。这样可以显著提高碰撞检测的效率。
- 场景边界判定:包围盒可以作为场景边界的判定值,用于确定物体是否在某个特定区域内。
- 体积和中心点计算:对于不规则物体,可以通过包围盒来近似计算其体积和中心点。
计算几何体的矩形包围
js
gltfLoader.load(
"./model/Duck.glb",
(gltf)=>{
console.log(gltf);
// 把模型加入到场景中
scene.add(gltf.scene)
// 获取到几何体
let duckMesh = gltf.scene.getObjectByName("LOD3spShape")
let duckGeometry = duckMesh.geometry
// 计算包围盒
duckGeometry.computeBoundingBox()
// 获取包围盒
let duckBox = duckGeometry.boundingBox
// 创建包围盒辅助器
let boxHelper = new THREE.Box3Helper(duckBox, 0xffff00)
// 更新世界矩阵
duckMesh.updateWorldMatrix(true, true)
// 更新包围盒
duckBox.applyMatrix4(duckMesh.matrixWorld)
// 添加到场景中
scene.add(boxHelper)
}
)
几何体居中
几何体.center()
js
const gltfLoader = new GLTFLoader()
gltfLoader.load(
"./model/Duck.glb",
(gltf)=>{
console.log(gltf);
// 把模型加入到场景中
scene.add(gltf.scene)
// 获取到几何体
let duckMesh = gltf.scene.getObjectByName("LOD3spShape")
let duckGeometry = duckMesh.geometry
// 设置居中
duckGeometry.center()
// 计算包围盒
duckGeometry.computeBoundingBox()
// 获取包围盒
let duckBox = duckGeometry.boundingBox
// 创建包围盒辅助器
let boxHelper = new THREE.Box3Helper(duckBox, 0xffff00)
// 更新世界矩阵
duckMesh.updateWorldMatrix(true, true)
// 更新包围盒
duckBox.applyMatrix4(duckMesh.matrixWorld)
// 添加到场景中
scene.add(boxHelper)
}
)
获取包围盒中心点
js
// 获取包围盒中心点
let center = duckBox.getCenter(new THREE.Vector3())
包围球
- 碰撞检测:与包围盒类似,包围球也可以用于碰撞检测。通过将物体封装到一个包围球中,可以简化碰撞检测的计算过程。
- 相机飞行参考值:在Three.js中,包围球还可以作为相机飞行的参考值,帮助确定相机的移动范围和视角。
js
// 获取包围球
let duckSphere = duckGeometry.boundingSphere
duckSphere.applyMatrix4(duckMesh.matrixWorld)
// 创建包围球辅助器
let sphereGeometry = new THREE.SphereGeometry(duckSphere.radius, 16, 16)
let sphereMaterial = new THREE.MeshBasicMaterial({
color: 0xff0000,
wireframe: true
})
let sphereMesh = new THREE.Mesh(sphereGeometry, sphereMaterial)
sphereMesh.position.copy(duckSphere.center)
scene.add(sphereMesh)
多个物体的包围盒
第一种方式
循环需要包围的盒子,用一个空盒子合并需要包围的盒子,然后创建父盒子的包围盒
js
let box = new THREE.Box3()
let arrSphere = [sphere1, sphere2, sphere3]
for (let i = 0; i < arrSphere.length; i++) {
// 计算当前物体的包围盒
arrSphere[i].geometry.computeBoundingBox()
// 获取包围盒
let box3 = arrSphere[i].geometry.boundingBox
// 更新世界矩阵
arrSphere[i].updateWorldMatrix(true, true)
// 将包围盒转换到世界坐标系
box3.applyMatrix4(arrSphere[i].matrixWorld)
// 合并包围盒
box.union(box3)
}
// 创建包围盒辅助器
let boxHelper = new THREE.Box3Helper(box, 0xffff00)
scene.add(boxHelper)
第二种方式
使用setFromObject,计算包围盒的3D对象
js
let box = new THREE.Box3()
let arrSphere = [sphere1, sphere2, sphere3]
for (let i = 0; i < arrSphere.length; i++) {
let box3 = new THREE.Box3().setFromObject(arrSphere[i])
// 合并包围盒
box.union(box3)
}
// 创建包围盒辅助器
let boxHelper = new THREE.Box3Helper(box, 0xffff00)
scene.add(boxHelper)