ThreeJS中基于几何索引的模型选区射线检测性能优化问题
解决高亮网格射线投射卡顿问题:复用原几何BVH树
核心问题分析
你遇到的卡顿是因为高亮网格每次射线检测时都在重新构建BVH树,而没有复用原网格已生成的boundsTree。由于高亮网格的顶点数据完全来自原几何,仅索引子集不同,完全可以直接复用原几何的BVH来大幅降低射线检测的耗时。
解决方案步骤
1. 初始化时复用原网格的BVH树
在创建高亮网格后,直接将原网格几何的boundsTree赋值给高亮网格的几何:
// 假设mesh是原模型网格,highlightMesh是你的高亮网格 highlightMesh.geometry.boundsTree = mesh.geometry.boundsTree;
2. 优化索引更新后的逻辑
你现有的索引更新逻辑不需要修改,但要确保不重新构建高亮网格的BVH。更新索引后仅标记索引需要更新即可:
const originalIndex = mesh.geometry.index; const highlightIndex = highlightMesh.geometry.index; // 更新高亮网格索引 for ( let i = 0, l = indices.length; i < l; i ++ ) { const i2 = originalIndex.getX( indices[ i ] ); highlightIndex.setX( i, i2 ); } highlightMesh.geometry.drawRange.count = indices.length; highlightIndex.needsUpdate = true; // 不要调用 highlightMesh.geometry.boundsTree = null 或重新构建
3. 使用BVH原生射线检测方法(可选但推荐)
替换Three.js原生Raycaster.intersectObject为Three-Mesh-BVH的bvh.raycast方法,进一步提升检测效率,同时过滤超出高亮范围的面索引:
const raycaster = new THREE.Raycaster(); const mouse = new THREE.Vector2(); function onMouseMove(event) { // 计算鼠标归一化坐标 mouse.x = (event.clientX / window.innerWidth) * 2 - 1; mouse.y = -(event.clientY / window.innerHeight) * 2 + 1; raycaster.setFromCamera(mouse, camera); const intersects = []; const bvh = highlightMesh.geometry.boundsTree; if (!bvh) return; // 使用BVH射线检测,仅保留在高亮范围内的结果 bvh.raycast(raycaster.ray, (hit) => { if (hit.faceIndex < highlightMesh.geometry.drawRange.count) { intersects.push({ object: highlightMesh, face: hit.face, faceIndex: hit.faceIndex, point: hit.point.clone(), distance: hit.distance }); } }); // 处理相交结果... }
原理说明
原网格的boundsTree已经预计算了所有顶点的空间分区信息,高亮网格只是选取了原几何的部分索引,复用这个BVH可以避免重复的空间分区计算。射线检测时只需要简单过滤掉超出当前高亮范围的面索引,就能得到准确的相交结果,同时将射线检测的时间复杂度从O(n)降到O(log n)。
内容的提问来源于stack exchange,提问作者Blaine
相关产品推荐
相关产品推荐

