Tutorials
April 30, 2026
c++booleanstutorial

Fast Mesh Booleans in C++

Learn how to perform fast mesh boolean operations in C++. Union, intersection, and difference at interactive speed on million-polygon meshes. Exact arithmetic, with support for non-manifold topology and coplanar primitives.

Žiga Sajovic, Polydera

Also available in Python and JavaScript.

trueform is the fastest C++ mesh boolean library for real-world meshes — performing exact boolean union, intersection, and difference at interactive speed. This tutorial covers the basics: loading meshes, running booleans, and working with results. It then shows how to precompute spatial and topological structures and apply transformations to avoid rebuilding them, enabling boolean operations on moving geometry at real-time rates.

trueform GitHub Documentation Try it live

We will use the Stanford Dragon to demonstrate boolean union, intersection, and difference between two offset copies of the same mesh.

Dragon
Dragon500K triangles
Union
UnionA ∪ B
Difference
DifferenceA \ B
Intersection
IntersectionA ∩ B

Each boolean under 14ms on 2×500K polygons. Let's begin by installing trueform.

Install

Header-only. Add it to your project via CMake FetchContent:

FetchContent_Declare(
  trueform
  GIT_REPOSITORY https://github.com/polydera/trueform
)
FetchContent_MakeAvailable(trueform)
target_link_libraries(my_app PRIVATE tf::trueform)

Also available via conan, nuget, and pip. See the installation guide for all options.

Loading the mesh

Include the library:

#include <trueform/trueform.hpp>

All functions live in the tf:: namespace. To load a mesh from a file:

auto dragon_buffer = tf::read_stl("stanford_dragon.stl");
// semantic view into the data
auto dragon = dragon_buffer.polygons();

If you already have vertex and face data in memory, construct views directly — no copy required:

std::vector<float> flat_points;
std::vector<int> flat_triangles;

auto dragon = tf::make_polygons(
    tf::make_faces<3>(flat_triangles),
    tf::make_points<3>(flat_points));

The resulting dragon gives you full mesh semantics on the views:

auto [id0, id1, id2] = dragon.faces().front();
auto [pt0, pt1, pt2] = dragon.front();
auto pt = dragon.points().front();

auto pt3 = pt0 + (pt2 - pt1) / 2;

For details on working with geometric ranges, see the Geometry Walkthrough.

Translated views

To perform a boolean between two copies of the dragon at different positions, we tag a transformation onto the form. The underlying data is shared — no vertices are copied.

auto T = tf::make_transformation_from_translation(
    tf::make_vector(0.f, 1.f, 0.f));

auto translated = dragon | tf::tag(T);

translated retains the full API of dragon through the policy system. Any operation that accepts dragon also accepts translated.

Boolean operations

With the two forms ready, a boolean is a single call. Full documentation.

Union

auto [result_buffer, labels, face_labels] = tf::make_boolean(
    dragon, translated, tf::boolean_op::merge);

Difference

auto [result_buffer, labels, face_labels] = tf::make_boolean(
    dragon, translated, tf::boolean_op::left_difference);

left_difference keeps the left mesh minus the right. right_difference does the opposite.

Intersection

auto [result_buffer, labels, face_labels] = tf::make_boolean(
    dragon, translated, tf::boolean_op::intersection);

Working with results

Every boolean returns three values. result_buffer holds the output mesh. labels marks each output face — 0 for faces originating from the first input, 1 from the second. face_labels maps each output face back to the index of its source face in the input, enabling attribute transfer.

To split the result into separate meshes by label:

auto [components, component_labels] =
    tf::split_into_components(result_buffer.polygons(), labels);

Write the two halves to file:

tf::write_stl(components[0].polygons(), "first.stl");
tf::write_obj(components[1].polygons(), "second.obj");

Precomputed structures

When running multiple booleans on the same geometry — for example, subtracting a tool at different positions along a path — rebuilding spatial and topological structures every time is wasteful. Build the aabb_tree, face_membership, and manifold_edge_link once, then tag them onto the form:

tf::aabb_tree<int, float, 3> tree;
tree.build(dragon, tf::config_tree(4, 4));

auto fm = tf::make_face_membership(dragon);
auto mel = tf::make_manifold_edge_link(dragon);

auto tagged = dragon
    | tf::tag(tree)
    | tf::tag(fm)
    | tf::tag(mel);

Now boolean at different positions. The structures are reused — only the transformation changes:

for (float t = 0.1f; t <= 1.0f; t += 0.1f) {
    auto T = tf::make_transformation_from_translation(
        tf::make_vector(0.f, t, 0.f));

    auto [result, labels, face_labels] = tf::make_boolean(
        tagged,
        tagged | tf::tag(T),
        tf::boolean_op::left_difference);
}

10 booleans on 2×500K polygon meshes in under 140ms total. Spatial and topological structures computed once.

Extracting intersection curves

Any boolean can also return the intersection boundary as polylines embedded on the surface. Pass tf::return_curves as an additional argument:

auto [result, labels, face_labels, curves] = tf::make_boolean(
    dragon, translated,
    tf::boolean_op::left_difference,
    tf::return_curves);

auto paths = curves.paths_buffer();
auto points = curves.points_buffer();

If only the intersection curves are needed without the boolean itself:

auto curves_buffer = tf::make_intersection_curves(dragon, translated);

Higher precision

By default, trueform uses int32 coordinates with int64 intermediates and int128 predicates. For meshes spanning very large coordinate ranges, switch to int64 base precision:

auto [result, labels, face_labels] =
    tf::make_boolean<tf::exact::int64>(
        dragon, translated,
        tf::boolean_op::left_difference);

Same API. Wider coordinate range.

Performance and robustness

All operations run at interactive speed on million-polygon meshes.

3.5msIntersection curves2×500K polygons
14msBoolean union2×500K polygons
86msPolygon arrangements2×500K polygons

Apple M4 Max 16 threads Clang -O3 mimalloc

Real meshes are not ideal manifolds. trueform handles them directly — no preprocessing, no manifold requirement.

FeatureHandlingConvex polygonsNative — not limited to trianglesNon-manifold edgesHandled directlyInconsistent windingBayesian classificationSelf-intersecting inputResolved via polygon arrangementsCoplanar primitivesExact — aligned/opposing boundary classificationContour crossingsResolved via indirect predicates

trueform provides a robust alternative to CGAL, MeshLib, and libigl for fast and exact mesh boolean operations.

Full benchmarks and methodology · How the algorithm works

Cite as
@article{polydera:fast-mesh-booleans-in-cpp,
  title={Fast Mesh Booleans in C++},
  author={Sajovic, {\v{Z}}iga, Polydera},
  year={2026},
  url={https://polydera.com/tutorials/fast-mesh-booleans-in-cpp},
  organization={Polydera}
}