CLI tool
gkjohnson/three-mesh-bvh avatar
gkjohnson/three-mesh-bvh

three-mesh-bvh: Faster Raycasting and Spatial Queries for three.js

A BVH implementation to speed up raycasting and enable spatial queries against three.js meshes.

3,486 stars333 forksJavaScriptMIT

At a glance

What is it?
three-mesh-bvh builds a bounding volume hierarchy for three.js geometries to accelerate raycasting and add shapecast, point, line, and object-level queries. It is a mature library with a clear API, but it has constraints around geometry updates and serialization that you should weigh before adopting it.
Who is it for?
Adopt three-mesh-bvh if your three.js project does heavy raycasting or spatial queries on static or rarely updated geometry and you can afford the build time. Do not use it for frequently deformed meshes unless you can rebuild the BVH each frame, and avoid it if you need full WebGPU compute support or broad serialization for line and point types.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 6 days ago.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 14, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

The problem: three.js raycasting slows down with polygon count

Default three.js raycasting checks every triangle in a mesh. On an 80,000-polygon model, a single raycast can take tens of milliseconds, which kills frame rate when you cast multiple rays per frame. three-mesh-bvh solves this by building a bounding volume hierarchy (BVH), a tree structure that lets a ray skip large groups of triangles that it cannot hit. The README claims casting 500 rays against an 80,000-polygon model at 60fps, which implies roughly 3.3 milliseconds for all 500 rays, a clear improvement over brute force. The library is aimed at three.js developers writing games, physics, path tracers, or tools that need fast picking, collision, or spatial queries.

How the BVH works under the hood

A BVH recursively partitions a geometry's triangles into a tree. Each node stores a bounding box that encloses its child nodes or triangles. When a ray is cast, the traversal checks the root box, then descends into children whose boxes the ray intersects, skipping entire subtrees that miss. The library implements this as a typed array structure, which the README refers to as a "newly generated index" that replaces the geometry's default index. The BVH is stored on the geometry as a `boundsTree` property. For raycasting, the library provides `raycastFirst`, which returns the first hit without traversing the whole tree, and a full `raycast` that collects all hits. The README shows that setting `raycaster.firstHitOnly = true` makes three.js use the faster `raycastFirst` path.

Getting it running: extension functions and direct construction

You install the package from npm, then import the extension functions. The README shows two usage patterns. The first patches three.js prototypes: `THREE.BufferGeometry.prototype.computeBoundsTree = computeBoundsTree`, `THREE.BufferGeometry.prototype.disposeBoundsTree = disposeBoundsTree`, and `THREE.Mesh.prototype.raycast = acceleratedRaycast`. Then you call `geometry.computeBoundsTree()` once. The second pattern constructs a `MeshBVH` manually: `new MeshBVH( geometry )` and assigns it to `geometry.boundsTree`. For raycasting, you still need to set `THREE.Mesh.prototype.raycast = acceleratedRaycast`. The library also provides `computeBatchedBoundsTree` and `disposeBatchedBoundsTree` for `THREE.BatchedMesh`. For points and lines, you pass a `type` option: `geometry.computeBoundsTree( { type: PointsBVH } )` or construct `new PointsBVH( geometry )` directly. The README notes that these specialized BVHs do not support webworker generation or serialization yet.

Beyond raycasting: shapecast and object-level BVHs

The library is not just for rays. It exposes `shapecast`, which lets you cast arbitrary shapes against the BVH, useful for collision volumes or swept shapes. The examples list includes sphere physics and character movement, which likely use this. There is also `ObjectBVH`, a scene-wide BVH that accelerates raycasting against a hierarchy of objects, with examples for frustum culling and skinned meshes. The README warns that `SkinnedMeshBVH` and `ObjectBVH` are "recently added so the APIs may change over time." That is a real consideration: if you build on these, you may need to adapt to breaking changes in minor releases. The core `MeshBVH` API appears stable, but the newer types are less settled.

Limitations: geometry updates, serialization, and WebGPU

A BVH is a static structure. If you move vertices, deform a mesh, or change its topology, the BVH becomes stale and raycasts return wrong results. The README does not mention a refit method, so you must rebuild the BVH when geometry changes. That is a build cost, and for dynamic meshes it can negate the speedup. The specialized `PointsBVH` and `LineBVH` types lack webworker generation and serialization, so you cannot offload their construction to a worker or save them to disk. The README also has commented-out WebGPU compute shader examples, indicating that WebGPU support is not yet available. If your project targets WebGPU, you may need to wait or find another solution. The library also requires the geometry to have a certain structure; the README does not specify, but you should ensure your geometry is non-indexed or has a compatible index.

A real alternative: three-bvh-csg and manual spatial partitioning

For constructive solid geometry, the author maintains `three-bvh-csg`, which uses the same BVH but for boolean operations. That is not a direct alternative for raycasting, but it shows the ecosystem. For raycasting specifically, a simpler alternative is to manually partition your geometry into multiple meshes and use three.js's built-in bounding sphere or box checks. That approach avoids a dependency but requires you to manage the partitioning yourself. The difference is that three-mesh-bvh automates the tree construction and traversal, giving you a general solution. Another alternative is to use a WebGL-based picking approach, like reading the depth buffer, but that only works for screen-space picking, not arbitrary rays. For spatial queries beyond raycasting, three-mesh-bvh's shapecast is unique; a manual partition would not give you that without significant work.

Maintenance and license: MIT, active, but check version compatibility

The project is MIT-licensed, so you can use it in commercial projects without paying fees. The repository is active, with the last push on 2026-08-01 and releases at v0.9.14, v0.9.13, and v0.9.12 within a few weeks. That suggests ongoing maintenance, but it also means the API can shift, especially for the newer BVH types. The README does not state a peer dependency for three.js, so you must verify that the library works with your three.js version. The examples use a specific import style, and the library is written in JavaScript, so no build step is needed beyond your normal bundler. Upgrade cost: when a new version comes out, you should read the changelog for breaking changes, particularly around the `SkinnedMeshBVH` and `ObjectBVH` APIs. The core `MeshBVH` API has been stable enough for the author to build external projects like `three-gpu-pathtracer` on it, which is a good sign.

Editorial conclusion

Adopt three-mesh-bvh if your three.js project does heavy raycasting or spatial queries on static or rarely updated geometry and you can afford the build time. Do not use it for frequently deformed meshes unless you can rebuild the BVH each frame, and avoid it if you need full WebGPU compute support or broad serialization for line and point types. Before committing, verify that your three.js version matches the library's peer dependency and test the build time on your largest models, since the README shows a 500-ray cast against an 80,000-polygon model at 60fps but does not state build cost.

Official sources

  1. Official documentation
  2. Official README
  3. Project repository
  4. Release notes
Community notes

Community notes