CoACD: approximate convex decomposition for 3D meshes
[SIGGRAPH2022] Approximate Convex Decomposition for 3D Meshes with Collision-Aware Concavity and Tree Search
At a glance
- What is it?
- CoACD takes a mesh and splits it into a set of convex parts, which is what collision detection actually wants, using a tree search over concavity that is designed to preserve the collision behaviour of the original shape with fewer components. It ships as a C++ tool, a Python package and a Unity integration, and the README documents the parameters and the threading trade-offs in real detail.
- Who is it for?
- Adopt CoACD if you are building physics or collision for concave geometry and need convex proxies that preserve the shape's collision behaviour, and start with the Python package and a threshold sweep before you tune anything else. Do not adopt it if your meshes are already convex, or if you need a watertight, manifold result, since the output is a set of convex hulls rather than a repaired solid.
- 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 30 days ago.
- What is it written in?
- Mainly C++, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Why collision detection wants convex pieces
Approximate convex decomposition enables efficient geometry processing algorithms specifically designed for convex shapes, for example collision detection. The problem it solves is that most real objects are concave, and collision code that assumes convexity either gives wrong answers or is slow enough to be unusable in a game loop.
The approach is to cut a concave mesh into a set of convex parts. The question is where to cut, and the paper this repository accompanies, published at SIGGRAPH 2022, proposes a method that is better at preserving the collision conditions of the input shape with fewer components. Fewer parts means fewer collider pairs, and preserving the collision conditions means the pieces still approximate the original rather than just being a loose fit.
The method is described in the title as collision-aware concavity and tree search, and the tree search is the interesting part. The search splits a part when it finds concavity above a threshold, and the collision-awareness is what keeps the split from producing pieces that stick out of the original shape.
The artefacts in the repository match the paper. There is a project page at colin97.github.io/CoACD, the paper itself on arXiv, and a video, and the implementation is in C++ with a Python binding and a Unity package, so the same algorithm is reachable from a research script, a pipeline or a game engine.
The Python path, and the real metric mode
The PyPI package is the shortest route in, and the README's example is short enough to be the whole mental model:
import coacd
mesh = trimesh.load(input_file, force="mesh")
mesh = coacd.Mesh(mesh.vertices, mesh.faces)
parts = coacd.run_coacd(mesh) # a list of convex hulls.
# Or use real metric mode (threshold in meters)
parts = coacd.run_coacd(mesh, threshold=0.01, real_metric=True)The input is loaded with trimesh, the vertices and faces are handed to a coacd.Mesh, and run_coacd returns a list of convex hulls. There is also a complete example script in the repository at python/package/bin/coacd, run with the input and output paths:
cd python
python package/bin/coacd -i $InputFile -o $OutputFileOne constraint is stated early: the input mesh must be a triangle mesh, and in Blender you can triangulate the mesh to convert non-triangular faces such as quads or n-gons to triangles.
The real metric mode is the notable addition, dated April 2026. It suits meshes in real-world scale, for example from 3D scans or CAD models in meters, and lets you specify the concavity threshold directly in meters instead of in normalized units. That matters more than it sounds, because a threshold tuned on a normalised model silently means something different on a model that happens to be scaled larger.
Building the C++ tool and choosing a threading backend
Building from source is three steps. Clone with submodules, install git and cmake 3.24 or newer, and pick a compiler: g++ 9 or newer but below 12 on Linux, clang 10.14 or higher on macOS, and MSVC 2019 or 2022 on Windows.
The build itself is a directory and a cmake invocation:
cmake .. -DCMAKE_BUILD_TYPE=Release \
&& make main -jThe threading options are the part worth reading carefully, because the defaults differ by platform and the two backends are mutually exclusive by design. WITH_OPENMP defaults to on for Linux and Windows and off for macOS, and prefers OpenMP when it is found. WITH_STD_THREADS defaults to on and is a C++17 std::thread fallback used only when OpenMP is disabled or missing, never alongside OpenMP.
So the three configurations are:
# Default Linux/Windows: OpenMP
cmake .. -DCMAKE_BUILD_TYPE=Release
# No OpenMP (macOS default, or dual-libgomp environments such as ROCm/HIP torch):
cmake .. -DCMAKE_BUILD_TYPE=Release -DWITH_OPENMP=OFF
# Fully sequential:
cmake .. -DCMAKE_BUILD_TYPE=Release -DWITH_OPENMP=OFF -DWITH_STD_THREADS=OFFThe macOS default exists because OpenMP is not reliably available there, and the note about dual-libgomp environments such as ROCm or HIP torch is a specific warning for people who already have a conflicting OpenMP runtime loaded into the same process.
For Python wheels built from source, the equivalent switch is an environment variable, COACD_WITH_OPENMP=0 to force the std::thread backend, and Windows has its own set of flags for the static MSVC runtime and the OpenVDB and TBB options.
Running the tool needs only an input and an output path, ./main -i PATH_OF_YOUR_MESH -o PATH_OF_OUTPUT, and the convex components are written in both .obj and .wrl formats.
The threshold is the knob, and everything else follows from it
The parameters section is sorted by importance, and that ordering is the design summary. The most important is the concavity threshold for terminating the decomposition, -t or --threshold, in the range 0.01 to 1 with a default of 0.05. Lower values mean more splitting and a closer approximation of the original shape; higher values mean fewer parts and a coarser fit.
The README points at this directly. It provides example meshes and a run_example.sh whose results land in the outputs folder, and the note is that you can adjust the threshold with -t to see results with different quality. That is the tuning loop, and the bundled examples exist to make it cheap.
The examples themselves are chosen to span the two cases that behave differently. Three are from PartNet-M, Bottle.obj, Kettle.obj and KitchenPot.obj, which are non-manifold. Two are from Thingi10K, Octocat-v2.obj and SnowFlake.obj, which are both 2-manifold.
The other parameters follow from that. The preprocessing mode, -pm or --preprocess-mode, chooses between automatically checking the input mesh for manifoldness, and forcing the manifold pre-processing on, with the auto mode added in June 2023 because it produces better results for manifold meshes. The preprocess resolution, -pr or --prep-resolution, runs from 20 to 100 with a default of 50. And -ro or --remesh-output writes the preprocessed mesh out as an .obj, which is the way to see what the preprocessing did to your input before you judge the decomposition.
Unity, and the option to call it at runtime
CoACD is supported in Unity as a package, for Unity 2020.1 or later, with an example project in the unity branch of the repository.
The install is through the Package Manager. Open it from the Window menu, find the plus button in the upper left corner, choose Add package from git URL, and enter:
https://github.com/SarahWeiii/CoACD.git?path=/Packages/info.flandre.coacd#unityThen the workflow is a component. You add a CoACD component to your object and can tweak the parameters in the editor. Right clicking the component header lane gives you Generate Collision Meshes, or Generate Collision Meshes for Hierarchy, which generates collision for the current object or for all the children of the current object that contains a MeshFilter. The Unity mesh colliders are then created in the scene under a Collision child of each object.
There is also a runtime path, which is the one to reach for when the geometry is generated at run time:
public List<Mesh> RunACD(Mesh mesh);Calling it as a method of the CoACD component is the alternative to the editor workflow, and it is what a game that streams or procedurally builds its meshes needs.
The GPU successor and the preprocessing tool
The news items at the top of the README point at two newer tools, and they are worth reading as the maintainer's own recommendations rather than as marketing.
The September 2026 item points at CuACD, described as a fully GPU-resident approximate convex decomposition implementing the same lookahead-search formulation as CoACD, up to about a hundred times faster, around 0.25 seconds per mesh on an RTX 4090, at matched or better quality. That is a substantial change in the cost model, and it is aimed at the case where you are decomposing thousands of meshes rather than authoring one by hand.
The September 2025 item points at PaMO, which converts any mesh into a low-poly, manifold, intersection-free mesh in seconds and requires CUDA. The README's description of it is that it is perfect as a preprocessing tool for CoACD, which makes sense given that CoACD's own preprocessing and manifold handling are the fiddly part of the pipeline and that the auto mode only improved results for manifold inputs.
Taken together, the two tools bracket CoACD's weaknesses: PaMO fixes the input, CuACD fixes the speed. What remains for CoACD is the case where you want a single well-understood reference implementation of the SIGGRAPH 2022 method, with a documented parameter set, a Python package, a Unity integration and a stable interface that has been used in production since 2023.
The releases reflect a project still being maintained, with 1.0.14 from 2026-08-28, 1.0.13 from 2026-08-19 and 1.0.12 from 2026-08-13, and the last push was on 2026-09-23. The Python packaging is careful in one respect worth noting, since the custom bdist_wheel class tags the wheels abi3, making them compatible back to Python 3.6 on CPython, and the extension is built through a custom CMake-backed setuptools extension class.
Editorial conclusion
Adopt CoACD if you are building physics or collision for concave geometry and need convex proxies that preserve the shape's collision behaviour, and start with the Python package and a threshold sweep before you tune anything else. Do not adopt it if your meshes are already convex, or if you need a watertight, manifold result, since the output is a set of convex hulls rather than a repaired solid. Before you deploy, check the threading flags for your platform, because the OpenMP and std::thread backends are mutually exclusive by design, and note that the maintainer now points at CuACD for GPU-resident decomposition and PaMO for manifold preprocessing.
Frequently asked questions
What does CoACD do to a mesh?
It performs approximate convex decomposition, splitting a mesh into a set of convex parts so that algorithms designed for convex shapes, such as collision detection, can be used on concave geometry. The method is a tree search over concavity that aims to preserve the collision conditions of the input shape with fewer components.
How do I run CoACD from Python?
Install it with pip install coacd, load a mesh with trimesh, wrap it in coacd.Mesh, and call coacd.run_coacd, which returns a list of convex hulls. A complete script is included at python/package/bin/coacd and takes input and output paths, and the input mesh must be a triangle mesh.
What is the concavity threshold in CoACD and what is its default?
The -t or --threshold option is the concavity threshold for terminating the decomposition, in the range 0.01 to 1, with a default of 0.05. The README suggests adjusting it with the bundled example meshes and run_example.sh to see results with different quality, and the 2026-04 release added a real metric mode for specifying the threshold in meters.
How does CoACD handle OpenMP and thread backends?
WITH_OPENMP defaults to on for Linux and Windows and off for macOS, and prefers OpenMP when found. WITH_STD_THREADS defaults to on and is a C++17 std::thread fallback used only when OpenMP is disabled or missing, never alongside it, so a fully sequential build turns both off. For Python wheels built from source, COACD_WITH_OPENMP=0 forces the std::thread backend.
Can CoACD be used inside Unity?
Yes, for Unity 2020.1 or later, installed through the Package Manager by adding the package from a git URL. You add a CoACD component to an object and choose Generate Collision Meshes from the component header, or call the runtime API public List<Mesh> RunACD(Mesh mesh) as a method of that component.
Official sources
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.
[](https://hysenlabs.com/projects/sarahweiii-coacd)Was this useful?