three-mesh-bvh MeshBVH 层次结构基本使用
单个几何体:bvh
方式一:添加扩展函数(修改原型链)
javascript
import {
computeBoundsTree,
disposeBoundsTree,
acceleratedRaycast,
MeshBVHHelper
} from 'three-mesh-bvh';
// 添加扩展函数(THREE的原有方法)
THREE.BufferGeometry.prototype.computeBoundsTree = computeBoundsTree;
THREE.BufferGeometry.prototype.disposeBoundsTree = disposeBoundsTree;
THREE.Mesh.prototype.raycast = acceleratedRaycast;
// 创建几何体
const geom = new THREE.SphereGeometry(1, 32, 32);
const mesh = new THREE.Mesh(geom, new THREE.MeshBasicMaterial({}));
// 计算几何体的 BVH
geom.computeBoundsTree({
strategy: CENTER,// AVERAGE、CENTER、SAH // 使用中心策略
maxDepth: 40, // 最大深度
maxLeafTris: 10, // 每个叶子节点的最大三角形数
setBoundingBox: true, // 设置边界框
useSharedArrayBuffer: false, // 是否使用共享数组缓冲区
verbose: true, // 是否输出详细信息
onProgress: (progress) => {
console.log(`Progress: ${progress * 100}%`); // 进度回调
},
range: {
start: 0,
count: geom.index ? geom.index.count : geom.attributes.position.count // 范围
}
});
const helper = new MeshBVHHelper(mesh, 40) // 辅助线
scene.add(mesh,helper)
import {
computeBoundsTree,
disposeBoundsTree,
acceleratedRaycast,
MeshBVHHelper
} from 'three-mesh-bvh';
// 添加扩展函数(THREE的原有方法)
THREE.BufferGeometry.prototype.computeBoundsTree = computeBoundsTree;
THREE.BufferGeometry.prototype.disposeBoundsTree = disposeBoundsTree;
THREE.Mesh.prototype.raycast = acceleratedRaycast;
// 创建几何体
const geom = new THREE.SphereGeometry(1, 32, 32);
const mesh = new THREE.Mesh(geom, new THREE.MeshBasicMaterial({}));
// 计算几何体的 BVH
geom.computeBoundsTree({
strategy: CENTER,// AVERAGE、CENTER、SAH // 使用中心策略
maxDepth: 40, // 最大深度
maxLeafTris: 10, // 每个叶子节点的最大三角形数
setBoundingBox: true, // 设置边界框
useSharedArrayBuffer: false, // 是否使用共享数组缓冲区
verbose: true, // 是否输出详细信息
onProgress: (progress) => {
console.log(`Progress: ${progress * 100}%`); // 进度回调
},
range: {
start: 0,
count: geom.index ? geom.index.count : geom.attributes.position.count // 范围
}
});
const helper = new MeshBVHHelper(mesh, 40) // 辅助线
scene.add(mesh,helper)
方式二:手动构建 BVH
javascript
import { MeshBVH, MeshBVHHelper} from 'three-mesh-bvh';
const bvh = new MeshBVH(geom, {
strategy: 1, // 使用中心策略
maxDepth: 40, // 最大深度
maxLeafTris: 10, // 每个叶子节点的最大三角形数
setBoundingBox: true, // 设置边界框
useSharedArrayBuffer: false, // 是否使用共享数组缓冲区
verbose: true, // 是否输出详细信息
onProgress: (progress) => {
console.log(`Progress: ${progress * 100}%`); // 进度回调
},
range: {
start: 0,
count: geom.index ? geom.index.count : geom.attributes.position.count // 范围
}
})
geom.boundsTree = bvh;
const helper = new MeshBVHHelper(mesh, 40) // 辅助线
scene.add(mesh,helper)
import { MeshBVH, MeshBVHHelper} from 'three-mesh-bvh';
const bvh = new MeshBVH(geom, {
strategy: 1, // 使用中心策略
maxDepth: 40, // 最大深度
maxLeafTris: 10, // 每个叶子节点的最大三角形数
setBoundingBox: true, // 设置边界框
useSharedArrayBuffer: false, // 是否使用共享数组缓冲区
verbose: true, // 是否输出详细信息
onProgress: (progress) => {
console.log(`Progress: ${progress * 100}%`); // 进度回调
},
range: {
start: 0,
count: geom.index ? geom.index.count : geom.attributes.position.count // 范围
}
})
geom.boundsTree = bvh;
const helper = new MeshBVHHelper(mesh, 40) // 辅助线
scene.add(mesh,helper)
批量几何体:bvh
多种几何体、不同坐标位置、相同材质 做 bvh 计算
javascript
const material = new THREE.MeshBasicMaterial({});
const boxGeo = new THREE.BoxGeometry(2.0, 2.0, 2.0);
const sphereGeo = new THREE.SphereGeometry(1.2, 32, 32);
const torusGeo = new THREE.TorusGeometry(2, 0.4, 16, 32);
const maxVertexCount = boxGeo.attributes.position.count + sphereGeo.attributes.position.count + torusGeo.attributes.position.count;
const maxIndexCount = (boxGeo.index ? boxGeo.index.count : 0) + (sphereGeo.index ? sphereGeo.index.count : 0) + (torusGeo.index ? torusGeo.index.count : 0);
const batchedMesh = new THREE.BatchedMesh(100, maxVertexCount, maxIndexCount, material);
const geometries = [boxGeo, sphereGeo, torusGeo];
const geometryIds = geometries.map(geometry => batchedMesh.addGeometry(geometry));
const num = 20
for (let i = 0; i < num; i++) {
batchedMesh.addInstance(geometryIds[i % geometryIds.length])
batchedMesh.setMatrixAt(i, randomizeMatrix(new THREE.Matrix4())); // 设置位置
}
batchedMesh.computeBoundsTree(geometryIds[num]);
scene.add(batchedMesh)
const material = new THREE.MeshBasicMaterial({});
const boxGeo = new THREE.BoxGeometry(2.0, 2.0, 2.0);
const sphereGeo = new THREE.SphereGeometry(1.2, 32, 32);
const torusGeo = new THREE.TorusGeometry(2, 0.4, 16, 32);
const maxVertexCount = boxGeo.attributes.position.count + sphereGeo.attributes.position.count + torusGeo.attributes.position.count;
const maxIndexCount = (boxGeo.index ? boxGeo.index.count : 0) + (sphereGeo.index ? sphereGeo.index.count : 0) + (torusGeo.index ? torusGeo.index.count : 0);
const batchedMesh = new THREE.BatchedMesh(100, maxVertexCount, maxIndexCount, material);
const geometries = [boxGeo, sphereGeo, torusGeo];
const geometryIds = geometries.map(geometry => batchedMesh.addGeometry(geometry));
const num = 20
for (let i = 0; i < num; i++) {
batchedMesh.addInstance(geometryIds[i % geometryIds.length])
batchedMesh.setMatrixAt(i, randomizeMatrix(new THREE.Matrix4())); // 设置位置
}
batchedMesh.computeBoundsTree(geometryIds[num]);
scene.add(batchedMesh)
多个几何体合并成一个、再做 bvh 计算
javascript
// gltf-格式-模型压缩
const dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath('./draco/gltf/');
// gltf-格式-模型加载
const loader = new GLTFLoader();
loader.setDRACOLoader(dracoLoader);
loader.setMeshoptDecoder(MeshoptDecoder);
const [A] = await Promise.all([
loader.loadAsync('./models/gears.glb'),
]);
// 将模型合并处理
const geometries: any = [];
A.scene.traverse((child: any) => {
if (child.isMesh) {
child.updateMatrixWorld = true;
const geometry = child.geometry.clone();
geometry.applyMatrix4(child.matrixWorld)
geometries.push(geometry);
}
});
const mergedGeometry = BufferGeometryUtils.mergeGeometries(geometries, false);
const material = new THREE.MeshBasicMaterial({ color: 0xff0000 });
const mesh = new THREE.Mesh(mergedGeometry, material);
mergedGeometry.computeBoundsTree( {
strategy: CENTER,
maxDepth: 40,
maxLeafTris: 10,
verbose: true,
setBoundingBox: true,
useSharedArrayBuffer: false,
onProgress: (progress) => {
console.log(`Progress: ${progress * 100}%`);
},
range: {
start: 0,
count: mergedGeometry.index ? mergedGeometry.index.count : mergedGeometry.attributes.position.count
}
}
);
const helper = new MeshBVHHelper(mesh, 40) // 辅助线
scene.add(helper)
// gltf-格式-模型压缩
const dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath('./draco/gltf/');
// gltf-格式-模型加载
const loader = new GLTFLoader();
loader.setDRACOLoader(dracoLoader);
loader.setMeshoptDecoder(MeshoptDecoder);
const [A] = await Promise.all([
loader.loadAsync('./models/gears.glb'),
]);
// 将模型合并处理
const geometries: any = [];
A.scene.traverse((child: any) => {
if (child.isMesh) {
child.updateMatrixWorld = true;
const geometry = child.geometry.clone();
geometry.applyMatrix4(child.matrixWorld)
geometries.push(geometry);
}
});
const mergedGeometry = BufferGeometryUtils.mergeGeometries(geometries, false);
const material = new THREE.MeshBasicMaterial({ color: 0xff0000 });
const mesh = new THREE.Mesh(mergedGeometry, material);
mergedGeometry.computeBoundsTree( {
strategy: CENTER,
maxDepth: 40,
maxLeafTris: 10,
verbose: true,
setBoundingBox: true,
useSharedArrayBuffer: false,
onProgress: (progress) => {
console.log(`Progress: ${progress * 100}%`);
},
range: {
start: 0,
count: mergedGeometry.index ? mergedGeometry.index.count : mergedGeometry.attributes.position.count
}
}
);
const helper = new MeshBVHHelper(mesh, 40) // 辅助线
scene.add(helper)