CollisionManager
BVH-based overlap detection between Snappable blocks. Used internally by ComponentMgr to gate socket snapping (blocks colliding → socket marked as blocked). Can also be used directly for custom collision queries.
Warning
Meant to be used with ComponentMgr only.
Getting started
const collisionManager = new CollisionManager()
No parameters. Creates a fresh instance with debug disabled and default BVH options.
ComponentMgr creates its own internal CollisionManager automatically — you rarely need to instantiate one directly.
Penetration Tolerance
Two meshes that are placed face-to-face will share a boundary plane.
Due to floating-point precision and the slight z-fight offset applied to socket meshes, their bounding boxes may overlap by a fraction of a millimetre even when they are not truly intersecting.
A zero tolerance would flag this contact as a collision and permanently block snapping.
The 5 mm default gives enough slack for precision-modelled furniture (where parts are intended to touch) while still catching meaningful overlaps.
If your models are very small (e.g. jewellery at centimetre scale) you may need to reduce this to 0.001. If your models are large (e.g. architectural elements at metre scale) the default is appropriate.
Think of it like a neighbour who only files a noise complaint when the music is genuinely, measurably loud — not every time you cough. Below the threshold, the collision manager politely pretends nothing happened.
OverlapResult Object
{
hasOverlap: boolean, // true if a blocking collision was found
contactPointWorld: THREE.Vector3|null, // world-space centre of the overlap region
meshA: THREE.Mesh|null, // first colliding mesh (from snappableA)
meshB: THREE.Mesh|null, // second colliding mesh (from snappableB)
overlapBoxWorld: THREE.Box3|null, // world-space bounding box of the overlap region
meshAMatrixWorld: THREE.Matrix4|null, // matrixWorld of meshA at the time of detection
meshBMatrixWorld: THREE.Matrix4|null, // matrixWorld of meshB at the time of detection
penetrationDepthWorld: number|null, // smallest axis penetration depth in world units
penetrationAxesWorld: {x,y,z}|null, // per-axis overlap distances
isBlockedByPenetration: boolean, // true if penetrationDepth > penetrationTolerance
}
Algorithm Detail
Think of it like sorting your inbox. First you delete everything that is obviously irrelevant without opening it — that's the AABB broad-phase, and it takes milliseconds. Then you carefully read what's left — that's the BVH narrow-phase, which is expensive and precise. You do not carefully read the Nigerian prince emails.
Socket meshes are excluded from collision checks — only geometry meshes participate.
BVH trees are computed lazily on first use (computeBoundsTree()) and cached on the geometry.
API
Constructor()
Constructor initialises the new CollisionManager instance
Methods
checkOverlap(snappableA, snappableB) → OverlapResult
Checks whether two Snappable blocks physically overlap using a two-phase algorithm:
- AABB broad phase — fast axis-aligned bounding box intersection test; returns early if boxes do not intersect
- BVH narrow phase — precise mesh-vs-mesh intersection using
three-mesh-bvh; penetration depth is compared againstpenetrationTolerance
Returns the first detected overlap (stops after one hit).
Parameters
snappableA: First snappable to check for overlapssnappableB: Second snappable to check for overlaps
Returns
OverlapResult: The first detected overlap
checkAllOverlaps(snappableA, snappableB, maxResults?) → OverlapResult[]
Same as checkOverlap but continues searching across all mesh pairs and returns every blocking overlap up to maxResults.
When maxResults is reached the method stops immediately and returns the results collected so far — it does not scan remaining mesh pairs. This makes it safe to call with a small cap (e.g. 20) on complex blocks with many meshes, at the cost of potentially missing overlaps beyond the limit.
Used internally by ComponentMgr's visual debug overlay to power the showAllCollisionAreas option.
Parameters
snappableA: First snappable to check for overlapssnappableB: Second snappable to check for overlapsmaxResults: Maximum number of overlaps to return
Returns
OverlapResult[]: Array of detected overlaps
visualizeCollisions(snappable, scene)
Adds BVH gradient visualisation helpers to the scene for a given Snappable. Only runs when isDebugEnabled is true.
Parameters
snappable: Snappable instance to visualise its BVHscene: Scene to add the visualisers to
removeDebugVisualizers(snappable)
Removes BVH helpers for a specific Snappable from the scene and disposes them.
Parameters
snappable: Snappable instance to remove BVH helpers for
clearDebugVisualizers()
Removes and disposes all BVH helpers for all Snappable instances.
setDebugOptions(options)
Merges options into the current BVH debug configuration and updates any existing helpers in-place.
Parameters
options: Object containing BVH debug optionsdepth: BVH tree depth to visualise. The BVH itself may have more levels than this — the helper only renders boxes down to this depth. Lower values show coarser, larger bounding volumes; higher values show the finer leaf-level triangles. The actual BVH depth is determined bythree-mesh-bvhbased on mesh complexity and is not configurable here.gradientStart: Colour at the shallowest BVH levelgradientEnd: Colour at the deepest BVH levelopacity: Helper mesh opacitypenetrationTolerance: Minimum penetration depth in metres before an overlap is counted as a blocking collision. Default: 5 mm — see note below.
Properties
isDebugEnabled
set/set — when set to false, all existing visualisers are cleared