three-mesh-bvh包围体层次结构(提升射线检测和空间查询性能(碰撞测试、可见性测试))

📘 three-mesh-bvh 简介

three-mesh-bvh 是一个基于 包围体层次结构(BVH,Bounding Volume Hierarchy) 的加速库,用于提升 three.js 中网格(Mesh)几何体在执行 射线检测(Raycasting)空间查询(碰撞检测、可见性测试等) 时的性能。

在 three.js 默认实现中,Raycaster 会逐个三角面检查射线是否命中,当几何体包含数十万甚至上百万个三角面时,性能会严重下降。
通过为几何体构建 BVH,检测复杂度由 O(n) 降低到 O(log n),显著提升运行效率。

image

这张图展示的是 Bounding Volume Hierarchy (BVH) 的概念:

  • 原始的复杂模型有很多细小三角形,直接做射线检测会非常慢。

  • BVH 把模型外层先用一个大的包围体(bounding volume,比如长方体)包起来。

  • 然后逐层把包围体再细分(像树结构一样),每一层都只包住其中一部分三角形。

这样射线检测时,就不用和所有三角面逐一相交,而是:

  1. 先看射线是否和大的包围体相交。

  2. 如果相交,再进入子包围体继续检测。

  3. 最后只检测到可能相交的少量三角形。

👉 效果就是把原本 O(n) 的检测优化成 O(log n),大幅提升效率。

📌 核心特性

  1. 加速射线检测:替代默认的三角面遍历,实现高效拾取与碰撞。

  2. 空间查询:支持包围盒(Box)、球体(Sphere)、胶囊体(Capsule)与网格的快速碰撞检测。

  3. 动态更新:支持 refit() 方法在几何体少量修改时快速更新 BVH,而无需重建。

  4. 高兼容性:可直接替换 three.js 的 Mesh.raycast,无需改写业务逻辑。

 

📌 安装

npm install three-mesh-bvh
 
 

📌 基础用法

1. 替换 Mesh 的 Raycast

import * as THREE from 'three';
import { MeshBVH, acceleratedRaycast } from 'three-mesh-bvh';

// 替换 three.js 默认的 raycast
THREE.Mesh.prototype.raycast = acceleratedRaycast;

 

2. 为几何体构建 BVH

// 创建一个地形或复杂模型
const geometry = new THREE.PlaneGeometry(1000, 1000, 500, 500);
geometry.rotateX(-Math.PI / 2);

// 构建 BVH
geometry.boundsTree = new MeshBVH(geometry);

const material = new THREE.MeshStandardMaterial({ color: 0x88cc88, wireframe: false });
const groundMesh = new THREE.Mesh(geometry, material);
scene.add(groundMesh);
 
3. 射线检测(Raycaster) 
const raycaster = new THREE.Raycaster();
raycaster.firstHitOnly = true; // 只取最近的交点,加速

// 从 (x,1000,z) 向下发射射线
raycaster.set(new THREE.Vector3(0, 1000, 0), new THREE.Vector3(0, -1, 0));

const intersects = raycaster.intersectObject(groundMesh);
if (intersects.length > 0) {
  console.log('命中点:', intersects[0].point);
}

 

📌 碰撞检测示例(球体 vs 地形)

import { MeshBVH, MeshBVHVisualizer } from 'three-mesh-bvh';

const bvh = new MeshBVH(groundMesh.geometry);

// 定义一个球体
const sphere = new THREE.Sphere(new THREE.Vector3(0, 10, 0), 2);

// 检测是否碰撞
const hit = bvh.intersectsSphere(sphere);
console.log('是否碰撞:', hit);

 

📌 小车贴地应用示例(四轮射线)

const raycaster = new THREE.Raycaster();
raycaster.firstHitOnly = true; // 优化性能
const down = new THREE.Vector3(0, -1, 0);

// 车轮相对位置
const wheelOffsets = [
  new THREE.Vector3( 1, 0,  1),
  new THREE.Vector3(-1, 0,  1),
  new THREE.Vector3( 1, 0, -1),
  new THREE.Vector3(-1, 0, -1),
];

function updateCarOnGround(car, groundMesh) {
  const wheelHits = [];

  for (let offset of wheelOffsets) {
    const worldPos = car.localToWorld(offset.clone());
    raycaster.set(new THREE.Vector3(worldPos.x, 9999, worldPos.z), down);

    const hit = raycaster.intersectObject(groundMesh)[0];
    if (hit) wheelHits.push(hit.point);
  }

  if (wheelHits.length >= 3) {
    // 计算车身法线
    const v1 = wheelHits[1].clone().sub(wheelHits[0]);
    const v2 = wheelHits[2].clone().sub(wheelHits[0]);
    const normal = new THREE.Vector3().crossVectors(v1, v2).normalize();

    // 对齐车身朝向
    const q = new THREE.Quaternion().setFromUnitVectors(new THREE.Vector3(0, 1, 0), normal);
    car.quaternion.slerp(q, 0.2);

    // 设置高度
    const avgY = wheelHits.reduce((sum, p) => sum + p.y, 0) / wheelHits.length;
    car.position.y = THREE.MathUtils.lerp(car.position.y, avgY + 0.3, 0.2);
  }
}

 

📌 总结

  • three-mesh-bvh 通过构建 BVH,加速射线检测和空间查询,适合处理高模地形、大规模场景。

  • 主要用途:高效拾取、角色/车辆贴地、碰撞检测、视锥裁剪。

  • 性能提升:从 O(n) → O(log n),对于百万级三角面的场景能带来几十倍速度提升。

 

posted @ 2025-08-25 11:30  SimoonJia  阅读(97)  评论(0)    收藏  举报