Nodes/ComfyUI_Antonioilev_Lightpack/🧷 UV-Safe Hard Weld
ComfyUI Node

🧷 UV-Safe Hard Weld

Weld Your Mesh Without Wrecking the UVs

By AntonioilevΒ·Created 2 days agoΒ·Updated a day agoΒ· 0
🧷 UV-Safe Hard Weld
  • input_mesh
  • mesh
  • info
β—„merge_distance0β–Ί
β—„fix_normalstrueβ–Ί
β—„fill_holestrueβ–Ί

What it's actually for

Generated meshes arrive split. The seam between two UV charts is a physical split in the vertex list - duplicate vertices sitting on top of each other, one per chart - which is how UVed meshes work, but it means the "solid" object isn't one shell. Watertightness checks fail, hole detection finds phantom borders, remeshers get confused, and half the tools in this pack will tell you your pristine Hunyuan3D asset has 400 holes.

This node is the fix that doesn't cost you your texture mapping. It merges coincident vertices - the hard weld in the name - while keeping the UV data, then optionally fixes normals and closes whatever holes the weld exposed.

How it works

The mechanism is coordinate rounding rather than a distance search. merge_distance gets converted to a decimal precision (-log10(distance)), and vertices that agree to that many digits are collapsed into one, with the face indices remapped through the same table. That's cheap and deterministic on big meshes.

After the weld it removes duplicate and degenerate faces (zero-length edges, repeated indices), drops unreferenced vertices, clears the mesh's internal cache so it doesn't report stale watertightness, and then - if you left the flags on - runs fix_normals() and, when the mesh still isn't watertight, fill_holes().

The "UV-Safe" claim is real: if the mesh's visual supports it, the node converts to a texture visual before touching vertices, so the UV array travels with the geometry instead of being dropped. That's the entire reason to prefer this over a blunt merge-vertices call.

The inputs that matter

  • input_mesh - the TRIMESH. Required, nothing else is.
  • merge_distance (default 1e-05) - how close counts as coincident. The default is right for meshes normalised to roughly unit scale. If your mesh is in millimetres and 300 units across, the default does nothing; if it's tiny, it'll collapse your detail. Scale first, then weld.
  • fix_normals (default on) - recomputes consistent facing. Leave it on for generated meshes, which routinely have inverted patches.
  • fill_holes (default on) - closes boundary loops after welding. Turn it off if the open boundary is intentional (a skirt, a water plane, a shell you're going to solidify later).

Outputs are mesh and info. The info string is the useful one: it reports the watertight verdict, vertex count and face count - Watertight OK versus Repaired is your signal that the fill actually closed it. It also reports Critical Error: ... if something threw, which is how you find out the node bailed instead of silently passing the mesh through.

Install

cd ComfyUI/custom_nodes
git clone https://github.com/Antonioilev/ComfyUI_Antonioilev_Lightpack.git
# restart ComfyUI

Or install "Antonioilev Light Pack" through ComfyUI Manager. No requirements file ships with the repo, and __init__.py swallows module import errors with a printed count instead of failing loudly - if the node's missing from the Antonioilev/Research menu, that console line is your starting point. This one is pure numpy + trimesh, both of which you almost certainly already have.

Where people get burned

  • Welding at the wrong scale is the #1 mistake. A merge distance that's too large fuses distinct geometry and creates a soup of collapsed faces; too small and nothing happens and you conclude the node is broken.
  • Weld before you unwrap, not after. Welding an already-unwrapped mesh is fine, but welding and then re-unwrapping is the right order - xatlas on a split mesh produces the island explosion people complain about.
  • It won't fix an inside-out shell that's already closed. fix_normals handles inconsistent winding; a fully inverted mesh needs the pack's normals fixer.
  • Don't expect watertight from a mesh with real openings. A model with a mouth cavity or an open backside stays open, and the info string will honestly say Repaired rather than Watertight OK. That's not a failure - it's the node telling you the geometry, not the repair, is the problem.
CategoryAntonioilev/Research

Inputs (4)

NameTypeDefaultDescription
input_meshTRIMESHβ€”
merge_distanceoptFLOAT01e-8–0.01β€”
fix_normalsoptBOOLEANtrueβ€”
fill_holesoptBOOLEANtrueβ€”

Outputs (2)

NameTypeDescription
meshTRIMESHβ€”
infoSTRINGβ€”