Log inGet started
World

Builtin Library

Branchmain
Branchesmainpublish
Commite8beb5604c

README.md

geometry.boolean

Combine two closed meshes into one closed surface: "union" keeps everything either encloses, "intersect" only what both enclose and "subtract" what a encloses and b does not.

Each input is triangulated and welded (core.weld, each merged point standing where its lowest-numbered point stood), then held to what a solid is (one number read back says whether either falls short, and the figures that explain it are read when one does), and refused by name when it is not: an input with fewer than four triangles, one carrying degenerate triangles (collapsed by the weld, or enclosing less area than weld squared), one that is not closed (an edge used by one triangle), not manifold (an edge shared by more than two), wound inconsistently (two triangles run an edge the same way), enclosing no volume, or wound inside-out (negative signed volume). The two are then cut against each other with the intersect kernels, which cut the curve where the surfaces cross and the regions where they coincide:

  1. The bounding volume hierarchy of b (geometry.bvh), then intersect_pairs (a count stage, a prefix sum, a write stage) lists the entries of the cut, three words each (a, b, part), ordered by the triangle of a.
  2. intersect_cuts writes the segment each entry is cut along; intersect_unify gives every endpoint that names the same crossing one identity, so the pieces of a and of b share their cut points. A cut point's position comes from the record that names it: the plane crossing of an edge and a triangle, the crossing of two coplanar edges, or a mesh point.
  3. intersect_retri retriangulates every triangle an entry reaches (side 0 for a, with the entries as they stand; side 1 for b, with the entries sorted by their triangle of b).
  4. Each piece is classified by the winding number of the other mesh just outside and just inside its centre (ray, winding); the kernels' README holds the table of what each operation keeps, which also settles the faces the two meshes share.
  5. The kept pieces are joined and welded. A triangle the weld leaves with two corners at one point encloses nothing and is dropped, and so are two triangles that stand on the same three points: where the cut runs straight across a corner within the weld distance of the line between its neighbours, each mesh keeps the sliver beside that line, and the two slivers face opposite ways over one another. The triangles are put in the order of their sorted corners (sort three times, by the highest, the middle and the lowest corner) so that triangles on the same points stand next to each other.
  6. The surface is refused when it has no triangle (the result is empty) or when it does not close (an edge used by one triangle, by more than two, or run the same way by both), and otherwise every face is given three points of its own and its own normal, so a shaded read of the result agrees with its winding.

Two meshes that never cross skip the cutting and are classified whole.

Inputs

  • a (Surface). The first closed mesh.
  • b (Surface). The second closed mesh.
  • op ("union", "subtract" or "intersect"). Which part of each cut surface survives; swapping a and b changes the result of a subtract. There is no default: a missing op is refused.
  • weld (Number, default 0). The distance below which two positions are one point while the inputs are cleaned and the pieces reassembled. 0 derives it as a hundred-thousandth of the diagonal of the smaller of the two inputs, since a mesh's coordinate precision scales with its size. May not exceed epsilon.
  • epsilon (Number, default 0). The thickness of a plane: how far either side of a piece the other solid is probed is at least this. 0 derives it as the weld distance. At least weld.

Outputs

  • geometry (Geometry). The combined surface: triangles of three points each, with a flat normal on every face.
  • report (Data). The operation, the weld and epsilon the run used, the result's pointCount and triangleCount (the points and triangles of geometry, three points a face), and the volumes enclosed by the two inputs (volumeA, volumeB) and by the result (volume), summed on the device in single precision. It is measured only when asked for.
local cut = g.geometry.boolean({ a = g.mesh.box({}), b = g.geometry.transform({ geometry = g.mesh.box({}), translate = vector.create(0.5, 0.5, 0.5) }), op = "subtract" })