- Published: 2025-03-13
- Updated: 2025-06-24
- MeshLib Team
What is Collision Detection in 3D?
3D collision detection is a computational process. Its goal is to find out if objects touch or intersect in 3D space: whether it is about cubes, spheres, cones, or any other more complex models you upload. This task is important in versatile scientific and business fields: countless digital objects are triangle meshes. That is why reliable mesh collision logic is key for correct and realistic physics.
In real-time environments, even one missed collision can ruin the experience or damage your data. This makes collision detection very important. You might be programming a physics routine, working on contact analysis, or dealing with graphics. In all these cases, detecting collisions between triangular meshes is essential. It helps ensure accuracy, realism, and proper system behavior.
- Correct physical responses.
- Precise interference checks.
- Stable behavior for physics engines.
3D Collision Detection Algorithm
When a collision between two triangular meshes needs to be detected, two phases ensue:

Broad Phase: Coarse Filtering—AABB Hierarchy Traversal
The broad phase is the first conceptual stage of collision detection. Its objective is to swiftly rule out mesh regions that definitely do not intersect. The resolution of this problem is simple.
Instead of using a single bounding box per mesh, one can build an AABB-tree for collision detection between triangular meshes. It is a hierarchy of bounding boxes that encloses smaller and smaller mesh regions, down to the triangle level.
At runtime, for simple and fast collision detection operations, one recursively traverses two such trees together.
Per each pair of AABBs:
– If the boxes do not overlap, we immediately prune that entire branch. There is no need to descend or check the triangles inside.
– If they do overlap, one continues down to the next level of both trees.
This eliminates large portions of both meshes from further consideration.
This dramatically reduces computational load before one ever touches triangle data for elevated efficiency.

Narrow Phase: Precise Testing—Triangle–Triangle Checks
The narrow phase begins as soon as the AABB traversal reaches two leaf nodes whose boxes still overlap.
In MeshLib, each leaf node holds exactly one triangle (other libraries may group a handful of triangles per leaf), so the goal shifts from ‘eliminate swiftly’ to ‘measure with precision.’ A typical pipeline looks like this:
– For every pair of overlapping leaf nodes, each triangle contained in node A is tested against each triangle in node B via a high-precision intersection algorithm. By applying these routines, the system determines whether two triangles intersect, and if so, record it by returning their IDs (or a triangle-plus-edge ID).
– This phase is computationally heavier, but thanks to the pruning done earlier, it runs only on a subset of triangles. While individual triangle–triangle checks involve more complex math and conditional logic, the broad phase eliminates the majority of irrelevant regions. Thus, the narrow phase operates on a reduced dataset
The result is an answer: do they collide or not?
Collision detection example with MeshLib

How to Detect Collisions in MeshLib?
Our 3D collision detection library takes pride in how we solve various collision detection tasks. Whatever the situation you are dealing with, we will detect it, one way or another: we handle all collision types when it comes to 3D meshes. From say, capsules, ellipsoids, cylinders, etc., to much more complex structures.
Colliding Triangle Detection
Colliding Triangle Detection allows you to identify every pair of overlapping triangles in two meshes (or mesh regions). This is accomplished by executing exact triangle–triangle intersection tests. As a library for 3D collision detection, among other tasks, we offer two complementary methods for this:
- findCollidingTriangles returns an explicit list of intersecting face-to-face pairs.
- findCollidingTriangleBitsets returns one bitset per object. Hence, it marks only the faces involved in collisions for ultra-compact storage.
This can be useful in:
- Physics engine. Deriving precise contact manifolds for rigid- and soft-body solvers*.*
- 3D printing and additive manufacturing. Catching self-intersections which would confuse slicers or halt fabrication.
- Repair and cleanup tools. Highlighting overlapping faces so automated fixes can remove or remesh them.
- Structural and FEA pre-processing to flag interpenetrating parts before running expensive stress analyses.
- Clash detection. Locating interference between components in large mechanical or architectural assemblies.
- Medical or scientific simulation. Ensuring watertight, non-colliding anatomical models for reliable results.
Colliding triangle detection: code examples in Python & C++
from meshlib import mrmeshpy as mm
meshA = mm.makeUVSphere() # make mesh A
meshB = mm.makeUVSphere() # make mesh B
meshB.transform(mm.AffineXf3f.translation(mm.Vector3f(0.1,0.1,0.1))) # shift mesh B for better demonstration
collidingFacePairs = mm.findCollidingTriangles(meshA,meshB) # find each pair of colliding faces
for fp in collidingFacePairs:
print(fp.aFace,fp.bFace) # print each pair of colliding faces
collidingFaceBitSetA,collidingFaceBitSetB = mm.findCollidingTriangleBitsets(meshA,meshB) # find bitsets of colliding faces
print(collidingFaceBitSetA.count()) # print number of colliding faces from mesh A
print(collidingFaceBitSetB.count()) # print number of colliding faces from mesh B
isColliding = not mm.findCollidingTriangles(meshA,meshB,firstIntersectionOnly=True).empty() # fast check if mesh A and mesh B collide
print(isColliding)
#include "MRMesh/MRMakeSphereMesh.h"
#include "MRMesh/MRMesh.h"
#include "MRMesh/MRMatrix3.h"
#include "MRMesh/MRAffineXf.h"
#include "MRMesh/MRMeshCollide.h"
#include
int main()
{
auto meshA = MR::makeUVSphere(); // make mesh A
auto meshB = MR::makeUVSphere(); // make mesh B
meshB.transform( MR::AffineXf3f::translation( MR::Vector3f( 0.1f, 0.1f, 0.1f ) ) ); // shift mesh B for better demonstration
auto collidingFacePairs = MR::findCollidingTriangles( meshA, meshB ); // find each pair of colliding faces
for ( const auto [fa, fb] : collidingFacePairs )
std::cout << int( fa ) << " " << int( fb ) << "\n"; // print each pair of colliding faces
auto [collidingFaceBitSetA, collidingFaceBitSetB] = MR::findCollidingTriangleBitsets( meshA, meshB ); // find bitsets of colliding faces
std::cout << collidingFaceBitSetA.count() << "\n"; // print number of colliding faces from mesh A
std::cout << collidingFaceBitSetB.count() << "\n"; // print number of colliding faces from mesh B
auto isColliding = !MR::findCollidingTriangles( meshA, meshB, nullptr, true ).empty(); // fast check if mesh A and mesh B collide
std::cout << isColliding << "\n";
return 0;
}
Step-by-step collision detection flow
- Ensure AABB trees exist for meshes A and B. MeshLib automatically builds (and then caches) an AABB tree the first time any of our algorithms needs it. If a cached tree already exists, the library simply reuses it. Thus, in practice you do not trigger this step manually
- Recursively traverse both trees:
- Test node A-box vs. node B-box.
- If no overlap, prune this branch.
- If overlap, descend into children.
- When two leaf boxes overlap, perform the exact triangle–triangle intersection test.
- Collect results: either face-pair lists or bitsets.
Self-Collision Detection
Self-Collision Detection allows one to discover each pair of triangles inside a single mesh that intersect one another by running exact triangle–triangle intersection methods. The routine gives an immediate response on self-overlaps, so that downstream tools can react with the proper fix. Our 3D collision detection library here, as one of the most efficient ones, provides two functions:
- findSelfCollidingTriangles returns an explicit list (std::vector<FaceFace>) of every intersecting face pair. Alternatively, it exits early after the first hit if you pass nullptr for the output.
- findSelfCollidingTrianglesBS returns a single FaceBitSet, which flags only the faces involved in self-intersections. The latter offers an ultra-compact resolution of the problem in the area.
In practical terms, these functions are of interest for:
- 3D printing and additive manufacturing. One needs to catch internal folds or self-cuts which would confuse a slicer.
- Mesh repair pipelines. Highlighting self-overlapping faces, so automatic remeshing can clean them.
- Scan data post-processing to detect folds created by noisy photogrammetry or LiDAR captures.
- Medical or scientific models. Guaranteeing anatomical surfaces are free of internal collisions before computational analysis.
Self-collision detection: code examples in Python & C++
from meshlib import mrmeshpy as mm
mesh = mm.makeTorusWithSelfIntersections() # make torus with self-intersections
selfCollidingParis = mm.findSelfCollidingTriangles(mesh) # find self-intersecting faces pairs
for fp in selfCollidingParis:
print(fp.aFace,fp.bFace) # print each pair
selfCollidingBitSet = mm.findSelfCollidingTrianglesBS(mesh) # find bitset of self-intersecting faces
print(selfCollidingBitSet.count()) # print number of self-intersecting faces
isSelfColliding = mm.findSelfCollidingTriangles(mesh,None) # fast check if mesh has self-intersections
print(isSelfColliding)
#include "MRMesh/MRTorus.h"
#include "MRMesh/MRMesh.h"
#include "MRMesh/MRMatrix3.h"
#include "MRMesh/MRAffineXf.h"
#include "MRMesh/MRMeshCollide.h"
#include
int main()
{
auto mesh = MR::makeTorusWithSelfIntersections(); // make torus with self-intersections
auto selfCollidingParis = MR::findSelfCollidingTriangles( mesh ); // find self-intersecting faces pairs
if ( !selfCollidingParis.has_value() )
{
// check error
std::cerr << selfCollidingParis.error();
return 1;
}
for ( auto [fl, fr] : *selfCollidingParis )
std::cout << int( fl ) << " " << int( fr ) << "\n"; // print each pair
auto selfCollidingBitSet = MR::findSelfCollidingTrianglesBS( mesh ); // find bitset of self-intersecting faces
if ( !selfCollidingBitSet.has_value() )
{
// check error
std::cerr << selfCollidingBitSet.error();
return 1;
}
std::cout << selfCollidingBitSet->count() << "\n"; // print number of self-intersecting faces
auto isSelfColliding = MR::findSelfCollidingTriangles( mesh, nullptr ); // fast check if mesh has self-intersections
if ( !isSelfColliding.has_value() )
{
// check error
std::cerr << isSelfColliding.error();
return 1;
}
std::cout << *isSelfColliding << "\n";
return 0;
}
Step-by-step collision detection flow
- Prepare your mesh handle. Make sure you have one MeshPart, that covers the area you want to test.
- Component filtering. Pass a Face2RegionMap to check self-intersections per component. That is, if two separate components of a single mesh intersect, they will not be treated as self-intersections.
- Define touch semantics. Set touchIsIntersection to true if merely touching faces should count as self-intersections. Otherwise, leave it false.
- Pick the function, fitting your workflow:
- Call findSelfCollidingTriangles. Get an explicit std::vector<FaceFace> listing every self-intersecting face pair;
- Call findSelfCollidingTrianglesBS. Receive a single FaceBitSet that flags only the triangles involved in self-collisions.
- Process the result. Iterate over the face pairs or the bitset to highlight overlaps, invoke repair, or feed your physics/simulation pipeline.
Edge-Triangle Intersection Detection
Edge-Triangle Intersection Detection lets you uncover every point where a mesh edge pierces a triangle on another mesh. The routine delivers a response about cross-element clashes. As a result, downstream systems could react with a precise resolution. Our 3D collision detection library exposes the potential of our findCollidingEdgeTrisPrecise, which can:
- Detect all intersections between each particular edge from mesh A and given triangles from mesh B.
- Detect all intersections between each particular triangle from mesh A and a given edge from mesh B.
- Detect all pairs of colliding edges from one mesh and triangle from another mesh.
As for applications of this collision detection function, they might encompass:
- Boolean operations, where this function is capable of detecting exact edge–triangle intersections that form the basis of contour extraction between meshes.
- Visualization tasks. Here, identifying intersecting contours helps highlight mesh clashes or render intersection boundaries.
Edge-triangle detection: code examples in Python & C++
from meshlib import mrmeshpy as mm
meshA = mm.makeUVSphere() # make mesh A
meshB = mm.makeUVSphere() # make mesh B
meshB.transform(mm.AffineXf3f.translation(mm.Vector3f(0.1,0.1,0.1))) # shift mesh B for better demonstration
converters = mm.getVectorConverters(meshA,meshB) # create converters to integer field (needed for absolute precision predicates)
collidingFaceEdges = mm.findCollidingEdgeTrisPrecise(meshA,meshB,converters.toInt) # find each intersecting edge/triangle pair
for eAtB in collidingFaceEdges.edgesAtrisB:
print(eAtB.edge,eAtB.tri) # print pairs of edges from mesh A and triangles from mesh B
for eBtA in collidingFaceEdges.edgesBtrisA:
print(eBtA.edge,eBtA.tri) # print pairs of edges from mesh B and triangles from mesh A
#include "MRMesh/MRMakeSphereMesh.h"
#include "MRMesh/MRMesh.h"
#include "MRMesh/MRMatrix3.h"
#include "MRMesh/MRAffineXf.h"
#include "MRMesh/MRMeshCollidePrecise.h"
#include
int main()
{
auto meshA = MR::makeUVSphere(); // make mesh A
auto meshB = MR::makeUVSphere(); // make mesh B
meshB.transform( MR::AffineXf3f::translation( MR::Vector3f( 0.1f, 0.1f, 0.1f ) ) ); // shift mesh B for better demonstration
auto converters = MR::getVectorConverters( meshA, meshB ); // create converters to integer field (needed for absolute precision predicates)
auto collidingFaceEdges = MR::findCollidingEdgeTrisPrecise( meshA, meshB, converters.toInt ); // find each intersecting edge/triangle pair
for ( auto [e, t] : collidingFaceEdges.edgesAtrisB )
std::cout << int( e ) << " " << int( t ) << "\n"; // print pairs of edges from mesh A and triangles from mesh B
for ( auto [e, t] : collidingFaceEdges.edgesBtrisA )
std::cout << int( e ) << " " << int( t ) << "\n"; // print pairs of edges from mesh B and triangles from mesh A
return 0;
}
Step-by-step collision detection flow
- Select geometry, choosing edges and faces of mesh A. Build the complementary list (faces or edges) for mesh B.
- Coordinate alignment (optional). If mesh B is in a different frame, transform B into A’s space.
- Choose the overload that matches your collision detection test.
- Edges-vs-faces
- Faces-vs-edges
- Full-part audit
- Call the function. Capture the returned results, containing all edge–triangle hits.
- Process the result. Iterate to mark contact points and then trigger clearance fixes.
MeshLib: Open-Source Mesh Processing Library for Collision Detection
MeshLib is engineered to solve the very problems that trip up most collision-detection projects. By combining spatial hierarchies with rigorously tested narrow-phase routines, it turns daunting datasets into predictable, fast workflows. The three main mesh collision detection problems are not issues with us:
Overlaps in complex geometries. When a mesh contains millions of faces, intricate fillets, or tightly packed parts, locating the real contacts becomes a needle-in-a-haystack problem. MeshLib attacks it in two stages: a BVH broad phase (in the form of AABB) cuts the haystack down to a fist-sized bundle. Then, its triangle–triangle narrow phase pinpoints the exact colliding facets.
Self-collision inside a single mesh. Highly detailed or folded surfaces can intersect themselves, derailing 3D printing, physics, you name it. MeshLib exposes dedicated calls that either return every internal clash or bail out after the first hit, depending on your performance budget.
Large-scale performance bottlenecks. Pairwise checks on huge assemblies can stall interactive tools or overnight batch jobs. Like most modern libraries, MeshLib leverages BVH acceleration to narrow down candidate pairs.
Under the Hood: Bounding-Volume Hierarchies (BVH) for Mesh Collision Detection
MeshLib’s broad-phase engine is built on Bounding Volume Hierarchies:
- Hierarchy of Axis-Aligned Bounding Boxes (AABB, as AABB is essentially one node-type inside the BVH). Each internal node stores an AABB that encloses its children, so whole subtrees are rejected with a single overlap test.
- Precise but conservative pruning. Only pairs guaranteed not to collide are discarded. Everything with even a slim possibility proceeds to the narrow phase.
- Focused compute budget. By shrinking the candidate list to a handful of suspects, we push work cycles toward the triangles that matter. This keeps frame-times low and batch jobs short.
Mesh Сollision Detection in Action: a Video Guide
MeshLib’s collision-detection engine is written in high-performance C++. First-class bindings for you to call the same routines from C, C#, and Python are available.
- C++ (native): Setup guide. Works everywhere
- Python: Setup guide. 3.8 – 3.13 on all major OS alternatives. Exceptions: macOS: 3.8 excluded on x64, 3.8–3.13 on any distro that ships manylinux_2_31.
Source code: github.com/MeshInspector/MeshLib
What our customers say
Thomas Tong
Founder, Polyga

Gal Cohen
CTO, customed.ai

Mariusz Hermansdorfer
Head of Computational Design at Henning Larsen Architechts

HeonJae Cho, DDS, MSD, PhD
Chief Executive Officer, 3DONS INC

Ruedger Rubbert
Chief Technology Officer, Brius Technologies Inc








Start Your Journey with MeshLib
MeshLib SDK offers multiple ways to dive in — from live technical demos to full application trials and hands-on SDK access. No complicated setups or hidden steps. Just the tools you need to start building smarter, faster, and better.
