Nodes/ComfyUI_Antonioilev_Lightpack/🎯 Detail Recover (Iterative)
ComfyUI Node

🎯 Detail Recover (Iterative)

Shrinkwrap your clean topology onto the noisy original

By AntonioilevΒ·Created 2 days agoΒ·Updated a day agoΒ· 0
🎯 Detail Recover (Iterative)
  • source_mesh
  • target_mesh
  • mesh
  • info
β—„iterations25β–Ί
β—„step_ratio0.55β–Ί
β—„smooth_weight0.15β–Ί
β—„max_distance0.00β–Ί
β—„edge_update_every5β–Ί
β—„final_snap_iters5β–Ί

Here's the problem this node exists for. You generated a mesh, then you smoothed it, decimated it, welded it, and filled its holes - and in the process you rounded off exactly the detail that made it look like anything: the creases of the ears, the ridge of the nose, the fine surface variation in the cloth. The mesh is clean now and slightly dead.

Detail Recover takes the two meshes - the cleaned one, and the original noisy one - and walks the clean vertices toward the original surface, step by step, so the crisp shape comes back onto the topology you like.

How the mechanism works

It's a constrained closest-point projection, and the constraints are what make it usable rather than a tangle generator.

  1. It builds the vertex adjacency of the source mesh (the one that moves).
  2. Every iteration it queries the closest point on the target surface (target_mesh.nearest.on_surface) for every source vertex, giving each vertex a displacement vector.
  3. Each displacement is clamped to avg_edge_length Γ— step_ratio - so a vertex can't teleport across the model in one pass. This is the key safety property: instead of snapping to the nearest point (which is how projection flips vertices across thin features and inside-out), it walks in bounded steps and lets intermediate geometry settle.
  4. Average edge length is recomputed every edge_update_every iterations, so the step size adapts as the mesh contracts.
  5. A Laplacian smoothing pass is blended in at smooth_weight for the early iterations only - the last final_snap_iters iterations are pure attraction, so the surface ends up crisp rather than pre-smoothed.
  6. Optional max_distance (0 = off) freezes any vertex whose closest point is further than that, which is how you stop a bad region from being dragged.

Direction matters and is easy to get backwards: source_mesh moves; target_mesh is the reference and doesn't change. So source = your clean/decimated topology, target = the dense original with detail.

The info output reports iterations, step ratio, smoothing and the mean vertex movement - that last number is genuinely informative. A mean move of 0.00002 means nothing happened (the meshes were already coincident); 0.04 on a unit-scale model means the geometry was rebuilt.

Inputs

  • source_mesh (TRIMESH) - the one being moved.
  • target_mesh (TRIMESH) - the detailed reference. Feed it straight from the generator output branch, before you cleaned it.
  • iterations (default 25, up to 500) - more iterations converge further, with diminishing returns around 30–50.
  • step_ratio (default 0.55) - the per-iteration fraction of average edge length. Lower is slower and safer; above ~0.8 you're back to snapping and the tangle risk returns.
  • smooth_weight (default 0.15) - mid-run smoothing. 0 gives a faithful but occasionally lumpy copy; 0.3+ starts erasing the detail you came for.
  • max_distance (default 0 = unlimited) - set it to a fraction of your model's extent when you only trust part of the reference.
  • edge_update_every (default 5), final_snap_iters (default 5) - scheduling knobs. The defaults are fine.

Outputs: mesh then info.

Two things to expect

It's CPU Python and it's slow. The nearest-surface query is vectorised, but the adjacency build, the edge-length calculation and the smoothing pass are per-vertex Python loops. On a 50k-vertex mesh, 25 iterations is seconds; on a 500k-vertex generated monster, minutes - and it will hold the queue while it runs. Iterate on a decimated copy and project once.

Thin features are still the risk. The step clamp helps a lot, but a hand with fingers 2mm apart is a geometry problem no projection pass can fully solve. Set max_distance so a vertex on one finger can't grab a point on the adjacent one.

Why this is a real workflow, not a curiosity

This is the ComfyUI-side version of a standard DCC move: retopo or decimate, then transfer detail back. In an image-to-3D pipeline where the mesh you get is triangle soup with ugly topology but great surface, the practical play is: clean the shape, then project the detail back on. It also makes a decent poor-man's delighter of smoothed scans - project a smoothed shell onto the original to re-acquire surface noise selectively.

Install

cd ComfyUI/custom_nodes
git clone https://github.com/Antonioilev/ComfyUI_Antonioilev_Lightpack.git
python -m pip install trimesh

Restart ComfyUI, and check that the pack's startup banner reports no failures: [Antonioilev_Light_pack] Loaded N nodes (M failed). Manager can install the pack by name (Antonioilev Light Pack) but the repo has no requirements.txt, so trimesh - this node's only dependency - is on you, in ComfyUI's own Python environment.

Note the category: it's filed under Antonioilev/Research, alongside the UV watertight experiments. That's honest labelling from the author - the algorithm works, but it's the kind of node you keep in a workflow after testing it on your own assets, not one to drop into a production graph untried.

CategoryAntonioilev/Research

Inputs (8)

NameTypeDefaultDescription
source_meshTRIMESHβ€”
target_meshTRIMESHβ€”
iterationsINT251–500β€”
step_ratiooptFLOAT0.550.05–1β€”
smooth_weightoptFLOAT0.150–1β€”
max_distanceoptFLOAT0.000–10β€”
edge_update_everyoptINT51–50β€”
final_snap_itersoptINT50–50β€”

Outputs (2)

NameTypeDescription
meshTRIMESHβ€”
infoSTRINGβ€”