包围盒是用于描述3D对象空间范围的简化几何形状,通常是一个与坐标轴对齐的长方体(Axis-Aligned Bounding Box, AABB)。
// 创建包围盒
const box = new THREE.Box3();
// 从对象创建
const mesh = new THREE.Mesh(geometry, material);
const box = new THREE.Box3().setFromObject(mesh);
// 手动设置
box.set(minPoint, maxPoint);
const sphere = new THREE.Sphere(center, radius);
sphere.setFromPoints(points); // 从点集计算
// 1. 从物体创建
const box = new THREE.Box3().setFromObject(object);
// 2. 从几何体创建
const geometry = new THREE.BoxGeometry(1, 1, 1);
const box = new THREE.Box3().setFromBufferAttribute(
geometry.attributes.position
);
// 3. 从点集创建
const points = [new THREE.Vector3(0,0,0), new THREE.Vector3(1,1,1)];
const box = new THREE.Box3().setFromPoints(points);
box.min; // Vector3 - 最小点坐标
box.max; // Vector3 - 最大点坐标
box.isEmpty(); // 布尔值 - 是否为空包围盒
// 应用矩阵变换
box.applyMatrix4(matrix);
// 平移
box.translate(offset);
// 扩展(合并包围盒)
box.union(otherBox);
// 相交
box.intersect(otherBox);
// 包含检测
box.containsPoint(point); // 是否包含点
box.containsBox(otherBox); // 是否包含另一个包围盒
// 相交检测
box.intersectsBox(otherBox); // 与包围盒相交
box.intersectsSphere(sphere); // 与球体相交
box.intersectsPlane(plane); // 与平面相交
// 获取尺寸和中心
box.getSize(targetVector); // 获取尺寸
box.getCenter(targetVector); // 获取中心点
function createBoundingBoxHelper(object) {
const box = new THREE.Box3().setFromObject(object);
// 创建可视化辅助线
const helper = new THREE.Box3Helper(box, 0xffff00);
scene.add(helper);
return helper;
}
// 或者使用 BoxHelper(已废弃,推荐Box3Helper)
const boxHelper = new THREE.BoxHelper(object, 0xffff00);
scene.add(boxHelper);
// 更新包围盒
function updateBoundingBox() {
box.setFromObject(object);
boxHelper.update();
}
function checkCollision(object1, object2) {
const box1 = new THREE.Box3().setFromObject(object1);
const box2 = new THREE.Box3().setFromObject(object2);
return box1.intersectsBox(box2);
}
// 带精度控制的碰撞检测
function preciseCollision(mesh1, mesh2) {
const box1 = mesh1.geometry.boundingBox.clone();
const box2 = mesh2.geometry.boundingBox.clone();
// 应用世界变换
box1.applyMatrix4(mesh1.matrixWorld);
box2.applyMatrix4(mesh2.matrixWorld);
return box1.intersectsBox(box2);
}
class ObjectManager {
constructor() {
this.objects = [];
this.frustum = new THREE.Frustum();
this.cameraMatrix = new THREE.Matrix4();
}
updateVisibility(camera) {
this.cameraMatrix.multiplyMatrices(
camera.projectionMatrix,
camera.matrixWorldInverse
);
this.frustum.setFromProjectionMatrix(this.cameraMatrix);
this.objects.forEach(obj => {
const box = new THREE.Box3().setFromObject(obj);
obj.visible = this.frustum.intersectsBox(box);
});
}
}
class OptimizedRaycaster {
constructor() {
this.raycaster = new THREE.Raycaster();
this.boundingBoxes = new Map();
}
// 预计算包围盒
precomputeBoxes(objects) {
objects.forEach(obj => {
this.boundingBoxes.set(
obj.uuid,
new THREE.Box3().setFromObject(obj)
);
});
}
// 优化后的相交检测
intersectObjects(mouse, camera, objects) {
this.raycaster.setFromCamera(mouse, camera);
const intersected = [];
// 先进行包围盒快速检测
objects.forEach(obj => {
const box = this.boundingBoxes.get(obj.uuid);
if (box && this.raycaster.ray.intersectsBox(box)) {
intersected.push(obj);
}
});
// 对通过包围盒检测的对象进行精确检测
return this.raycaster.intersectObjects(intersected, true);
}
}
class BoundingBoxCache {
constructor() {
this.cache = new WeakMap();
}
getBox(object) {
if (!this.cache.has(object)) {
const box = new THREE.Box3().setFromObject(object);
this.cache.set(object, box);
return box;
}
return this.cache.get(object);
}
invalidate(object) {
this.cache.delete(object);
}
}
// 创建层次结构
function createBVH(objects) {
const bvh = [];
// 每8个对象创建一个父包围盒
for (let i = 0; i < objects.length; i += 8) {
const group = objects.slice(i, i + 8);
const groupBox = new THREE.Box3();
group.forEach(obj => {
const box = new THREE.Box3().setFromObject(obj);
groupBox.union(box);
});
bvh.push({
box: groupBox,
objects: group
});
}
return bvh;
}
class DynamicBoundingBox {
constructor(object, updateThreshold = 0.1) {
this.object = object;
this.updateThreshold = updateThreshold;
this.lastPosition = object.position.clone();
this.lastRotation = object.rotation.clone();
this.lastScale = object.scale.clone();
this.box = new THREE.Box3().setFromObject(object);
}
needsUpdate() {
return (
this.lastPosition.distanceTo(this.object.position) > this.updateThreshold ||
this.lastRotation.angleTo(this.object.rotation) > this.updateThreshold ||
this.lastScale.distanceTo(this.object.scale) > this.updateThreshold
);
}
update() {
if (this.needsUpdate()) {
this.box.setFromObject(this.object);
this.lastPosition.copy(this.object.position);
this.lastRotation.copy(this.object.rotation);
this.lastScale.copy(this.object.scale);
return true;
}
return false;
}
}
// 问题:网格变形或蒙皮动画导致包围盒不准
// 解决方案:重新计算顶点位置
function updateSkinnedBoundingBox(mesh) {
const geometry = mesh.geometry;
const position = geometry.attributes.position;
const skinIndex = geometry.attributes.skinIndex;
const skinWeight = geometry.attributes.skinWeight;
// 更新蒙皮顶点
mesh.updateMatrixWorld(true);
// 重新计算包围盒
geometry.computeBoundingBox();
}
// 使用脏标记优化
class OptimizedObject {
constructor() {
this._boundingBoxDirty = true;
this._boundingBox = new THREE.Box3();
}
get boundingBox() {
if (this._boundingBoxDirty) {
this._boundingBox.setFromObject(this);
this._boundingBoxDirty = false;
}
return this._boundingBox;
}
markDirty() {
this._boundingBoxDirty = true;
}
}
// 避免内存泄漏
class BoundingBoxManager {
constructor() {
this.boxes = new Map();
this.disposed = new WeakSet();
}
// 清理未使用的包围盒
cleanup() {
for (const [obj, box] of this.boxes) {
if (this.disposed.has(obj) || !obj.parent) {
box.set(new THREE.Vector3(), new THREE.Vector3());
this.boxes.delete(obj);
}
}
}
}
class OctreeNode {
constructor(boundary, capacity = 4) {
this.boundary = boundary; // Box3
this.capacity = capacity;
this.objects = [];
this.divided = false;
this.children = [];
}
insert(object) {
const box = new THREE.Box3().setFromObject(object);
if (!this.boundary.containsBox(box)) {
return false;
}
if (this.objects.length < this.capacity) {
this.objects.push(object);
return true;
}
if (!this.divided) {
this.subdivide();
}
return this.children.some(child => child.insert(object));
}
subdivide() {
const size = this.boundary.getSize(new THREE.Vector3());
const halfSize = size.clone().multiplyScalar(0.5);
const center = this.boundary.getCenter(new THREE.Vector3());
// 创建8个子节点
for (let x = -1; x <= 1; x += 2) {
for (let y = -1; y <= 1; y += 2) {
for (let z = -1; z <= 1; z += 2) {
const childMin = new THREE.Vector3(
center.x + x * halfSize.x * 0.5,
center.y + y * halfSize.y * 0.5,
center.z + z * halfSize.z * 0.5
);
const childMax = childMin.clone().add(halfSize);
const childBox = new THREE.Box3(childMin, childMax);
this.children.push(new OctreeNode(childBox, this.capacity));
}
}
}
this.divided = true;
}
}
通过合理使用包围盒技术,可以显著提升Three.js应用的性能,特别是在处理大量物体或复杂场景时。