Merge Vertices
The cleanup step your watertight check quietly depends on
- mesh
- merged_mesh
- info
Meshes from CAD tools, game exporters, and 3D reconstruction pipelines come out with duplicate vertices all the time - two vertices sitting on top of each other where the file writer forgot to weld them. Your eye can't see it, but the math can: the mesh isn't watertight, normals are inconsistent, and every downstream step that assumes a clean manifold quietly degrades. Merge Vertices is the weld tool. It collapses vertices that are within a distance tolerance of each other, and it's the kind of thing you do first, before quality checks, remeshing, or anything that touches topology.
It's part of ComfyUI-GeometryPack ("ComfyUI libigl"), Andrea Pozzetti's geometry toolkit for ComfyUI. The pack is GPL-3.0-or-later and installs via the experimental comfy-env package - more on that below.
How it works
Under the hood it's trimesh's merge_vertices, driven by a single float. The tolerance input (default 1e-5, range 1e-8 to 0.01) is the distance within which two vertices count as the same point. The node converts that distance into a decimal-precision setting for the merge - 1e-5 means "match to 5 decimal places" - then welds, remaps the faces, and reports the damage.
The author's tooltip calls 1e-5 "recommended for CAD meshes," and that's good advice as a starting point. CAD exports commonly have coordinate noise around that scale. Crank it up toward 0.01 if you genuinely want to snap nearby-but-separate geometry together (say, almost-touching parts you intend to join); keep it tiny if you're just welding exact duplicates, because too large a tolerance starts eating real detail.
Inputs and outputs
mesh- theTRIMESHto clean.tolerance- the weld distance. Default1e-5; start there.
Outputs:
merged_mesh- the weldedTRIMESH. It's a copy; your input is untouched, so you can branch off the original.info- aSTRINGreport showing vertex/face counts before and after, how many duplicates got removed, and whether the mesh is now fully connected or still has multiple disconnected components. It even flags a[WARN]if components remain - read it, it's telling you the mesh is still in pieces.
Where it fits and where it bites
Use it right after loading CAD/exported geometry and before watertight-dependent steps. A common loop: Load → Merge Vertices → Fix Normals → check with Mesh Info → remesh. The merge is also a cheap way to make your quality metrics honest, since boundary-edge and watertight tests are meaningless when the geometry is secretly split.
The traps are both about tolerance:
- Too small - you "fix" nothing and the info line quietly says no duplicates were found. If that surprises you, your duplicates are farther apart than
1e-5; the info string tells you what you actually had. - Too big - you weld distinct geometry together and distort the surface. The
0.01max is there to remind you the dial goes a long way.
Install
Search "GeometryPack" in ComfyUI Manager, or:
cd ComfyUI/custom_nodes
git clone https://github.com/PozzettiAndrea/ComfyUI-GeometryPack.git
cd ComfyUI-GeometryPack
pip install -r requirements.txt --upgrade
python install.py
Restart after. The pack's comfy-env installer downloads the pixi package manager and builds an isolated environment with heavy 3D dependencies (Blender, CGAL, libigl, VTK), so the first startup is slow. The author ships the pack as WIP with fast releases - if behavior shifts after an update, reinstall clean. Unsexy, but this node is often the difference between "this remesh looks wrong" and "oh, the mesh was in three pieces the whole time."
Inputs (2)
| Name | Type | Default | Description |
|---|---|---|---|
| mesh | TRIMESH | — | |
| tolerance | FLOAT | 0.00001e-8–0.01 | Distance tolerance for merging vertices (1e-5 recommended for CAD meshes) |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| merged_mesh | TRIMESH | — |
| info | STRING | — |