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

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

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

3,494 stars335 forksJavaScriptMIT

At a glance

What is it?
three-mesh-bvh is an MIT-licensed JavaScript library that builds a bounding volume hierarchy over three.js geometry so raycasting and spatial queries stop scanning every triangle. It is a good fit when picking, sculpting or physics against dense meshes becomes the bottleneck, and the wrong tool when you need a general-purpose physics engine or a scene graph BVH that is still settling.
Who is it for?
Adopt three-mesh-bvh if you are picking, sculpting, voxelizing or path tracing against three.js geometry dense enough that plain Raycaster.intersectObjects is the bottleneck, and you can accept that the BVH is a derived structure you must rebuild or refit when the geometry changes.
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 5 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 25, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What three-mesh-bvh solves, and for whom

A three.js Mesh.raycast walks the geometry index and tests the ray against every triangle. On a small model that is invisible. On an 80,000 polygon model, casting 500 rays per frame is not, which is the situation the project's own headline example describes. three-mesh-bvh builds a bounding volume hierarchy over the triangles and answers the same query by descending a tree, so most triangles are never tested. The README points to the Wikipedia article on bounding volume hierarchies for the general idea, and the repository is explicit that the two goals are speeding up raycasting and enabling spatial queries against three.js meshes.

The audience is narrower than "anyone using three.js". It is people writing interactive tools where the cursor drives a query: triangle painting, lasso selection, sculpting, distance comparison, clipped edge extraction, geometry voxelization. It is also people writing renderers, since the example list includes CPU and GPU path tracing, a Lambert variant and a gem refraction demo. If your app only renders and never asks "what is under this point", the library has nothing to offer you.

How the BVH is built and queried

The mechanism is a tree of bounding volumes stored on the geometry, not on the mesh. The README's manual path is the clearest statement of the data flow: `geom.boundsTree = new MeshBVH( geom )` generates the hierarchy and assigns the newly generated index, and the tree lives on the BufferGeometry. The accelerated raycast function then assumes that variable exists. That placement matters when you clone geometry or share it between meshes: the acceleration structure travels with the geometry, not with the object.

Queries come in two flavours. The convenience path patches three.js prototypes so existing code keeps working, and the direct path skips three.js raycasting entirely. In the direct path the README inverts the mesh world matrix, transforms the ray into the geometry's local space, and calls `bvh.raycastFirst( raycaster.ray )`. The comment in the README is blunt about why: ensure the ray is in the local space of the geometry being cast against. Getting that transform wrong is the most common way to get plausible but wrong hits.

The library is not limited to triangles. It ships PointsBVH, LineBVH, LineLoopBVH and LineSegmentsBVH, selectable through a `type` option on computeBoundsTree or by constructing the class directly. Each implements a core API including shapecast and raycastObject3D for its primitive type. Two further classes, SkinnedMeshBVH and ObjectBVH, extend the idea to skinned meshes and to a scene-wide hierarchy of objects.

Installing three-mesh-bvh and getting a first accelerated raycast

The package is published to npm under the name three-mesh-bvh, and package.json declares `"module": "src/index.js"` with a CommonJS build at `build/index.umd.cjs`, so both import styles resolve. Install it alongside three, which is a peer dependency in practice rather than something the package pulls in for you.

bash
npm install three three-mesh-bvh

Next, attach the extension functions. This is the README's pre-made-function path, and it is the least invasive way to try the library because your existing raycasting code does not change. The same block also shows the BatchedMesh variants, which are separate functions rather than the same ones reused.

js
import * as THREE from 'three';
import {
  computeBoundsTree, disposeBoundsTree, acceleratedRaycast,
} from 'three-mesh-bvh';

THREE.BufferGeometry.prototype.computeBoundsTree = computeBoundsTree;
THREE.BufferGeometry.prototype.disposeBoundsTree = disposeBoundsTree;
THREE.Mesh.prototype.raycast = acceleratedRaycast;

With the prototypes patched, build the tree on the geometry you care about and turn on the first-hit shortcut. Setting `firstHitOnly` to true makes Mesh.raycast use the BVH's raycastFirst function, which the README says returns a result more quickly. If you only need to know whether a ray hit and where it hit first, this is the cheap path.

js
geometry.computeBoundsTree();

const raycaster = new THREE.Raycaster();
raycaster.firstHitOnly = true;
raycaster.intersectObjects( [ mesh ] );

If you would rather not touch prototypes, the manual route is one line: `geom.boundsTree = new MeshBVH( geom )`, plus assigning `acceleratedRaycast` to `THREE.Mesh.prototype.raycast` once. Building the tree is not free, so for large geometry the repository includes a WebWorker generation example and an async generation example under example/; the README notes that webworker generation is not supported for the non-triangle BVH types.

Where three-mesh-bvh breaks down

The BVH is a snapshot. It is derived from vertex positions at the moment you build it, so a mesh whose vertices move every frame has a stale tree unless you refit or rebuild. The README does not document a rollback or a versioning scheme for the structure; it documents the structure itself. That means the update strategy is your design decision, and it is the part most likely to be underestimated. A rebuild on every frame for a dense mesh will cost more than the raycasting you were trying to save.

Coverage is uneven by design. The README states plainly that some features, including webworker generation and serialization, are not supported for the Points, Line, LineLoop and LineSegments BVH types at the moment. If your pipeline depends on serializing the acceleration structure to ship it to a client, that path exists for triangle meshes and not for those.

The scene-level classes carry a stability warning in the README itself. SkinnedMeshBVH and ObjectBVH are described as recently added, with APIs that may change over time. Building a long-lived product on them means accepting churn. Finally, this is not a physics engine. The repository includes sphere physics collision and player movement examples, but those are demonstrations of spatial queries, not a solver with constraints, restitution models or a broadphase you can hand to a rigid body simulation.

three-bvh-csg and the rest of the ecosystem

The most direct alternative is not a competitor to three-mesh-bvh but a consumer of it: three-bvh-csg, listed in the README under external projects and by the same author. It performs constructive solid geometry operations on meshes, which is a different job from answering ray and shape queries. If you are choosing between them, the question is whether you need to combine solids or to interrogate them. A boolean union of two meshes is CSG; finding the triangle under the cursor is BVH. The two are often used together, with the BVH accelerating the intersection tests that CSG performs internally.

The other listed external projects are three-gpu-pathtracer, for rendering, and three-edge-projection. For the underlying spatial structure, the alternative people weigh against a BVH is an octree, which subdivides space rather than partitioning primitives. The practical difference is what you are querying: a BVH is built over the geometry and answers primitive-level questions like which triangle did this ray hit, while an octree partitions a volume and answers region-level questions like what is inside this box. For ray-triangle intersection against a static mesh, the BVH is the structure the library is built around. For repeated box or region queries over sparse, moving content, an octree is often the simpler fit, and three-mesh-bvh does not offer one.

Maintenance, licence and the cost of upgrading

The repository is not archived, and the last push was on 2026-08-01, the same day as the v0.9.14 release. The preceding releases, v0.9.13 and v0.9.12, both landed on 2026-07-18, so the release cadence in that window was a matter of hours rather than months. The version in package.json is 0.9.15, one patch ahead of the most recent listed release, which is normal for a repository whose publish step runs the build first.

Staying on 0.x has a concrete cost. The README warns that SkinnedMeshBVH and ObjectBVH APIs may change, and a minor version bump in a 0.x line is where that change would land. The package declares `"sideEffects": false` and ships `src/*` and `build/*`, so a bundler can tree-shake the parts you do not import, which keeps the upgrade surface smaller than the file count suggests. The repository also carries an API.md and a CHANGELOG.md at the top level, so the diff between versions is documented rather than something you have to reconstruct from commits.

The licence is MIT, declared in package.json and present as a LICENSE file. MIT permits commercial use and modification provided the copyright notice and permission notice are retained. That is a permissive licence with few obligations, but it is not legal advice: if you redistribute the library inside a product, read the LICENSE file and your own counsel's guidance rather than this paragraph.

Editorial conclusion

Adopt three-mesh-bvh if you are picking, sculpting, voxelizing or path tracing against three.js geometry dense enough that plain Raycaster.intersectObjects is the bottleneck, and you can accept that the BVH is a derived structure you must rebuild or refit when the geometry changes. Do not adopt it as a general physics engine or as a drop-in for a scene-wide acceleration structure you can rely on for years: the README describes SkinnedMeshBVH and ObjectBVH as recently added with APIs that may change. Before committing, verify three things on your own meshes: that the memory cost of a full-precision BVH is acceptable, that your update path (refit or rebuild) keeps up with your animation, and that the geometry types you actually cast against are covered, since the README states that webworker generation and serialization are not supported for the Points, Line, LineLoop and LineSegments BVH types at the moment.

Frequently asked questions

What does BVH stand for in three-mesh-bvh?

BVH stands for Bounding Volume Hierarchy. The README links to the Wikipedia article on bounding volume hierarchies for the general concept, and describes the library as a BVH implementation for speeding up raycasting and enabling spatial queries against three.js meshes.

What is three-mesh-bvh?

It is a JavaScript library that builds a bounding volume hierarchy over three.js geometry so that raycasting and spatial queries do not test every triangle. It is published on npm as three-mesh-bvh under the MIT licence, and the README lists examples covering raycasting, point cloud and line intersection, shape intersection, SDF generation and path tracing.

How do I install three-mesh-bvh from npm?

Install it with npm install three three-mesh-bvh, then import the extension functions and assign computeBoundsTree, disposeBoundsTree and acceleratedRaycast to the relevant three.js prototypes, or construct a MeshBVH directly and assign it to geometry.boundsTree.

Does three-mesh-bvh support TypeScript?

The package declares "types": "src/index.d.ts" in package.json and exposes the source through the "./src/*" export, so type definitions ship with the package. The repository also runs tsc --noEmit as part of its lint script.

Is there a WebGPU version of three-mesh-bvh?

The package exposes a "./webgpu" entry point mapping to src/webgpu/index.js, and the repository contains a WEBGPU_API.md file. The README's WebGPU compute shader examples are commented out, so treat that path as separate from the main raycasting API.

Official sources

  1. Official documentation
  2. Official README
  3. Project repository
  4. Release notes
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/gkjohnson-three-mesh-bvh.svg)](https://hysenlabs.com/projects/gkjohnson-three-mesh-bvh)