π Refine Mesh Structural V3.5
A smoother that shows you what it decided to protect
- trimesh
- refined_mesh
- info
Every generated mesh has two surfaces fighting each other: the shape you want, and the noise the reconstruction left everywhere. A plain Laplacian smooth kills both - you get a soft, dead object with melted features. A plain "don't smooth" leaves the noise.
Refine Mesh is a feature-preserving smoother built specifically for AI-generated geometry, and it does the one thing that makes this class of node trustworthy: it paints the mesh so you can see what it chose to protect.
How it decides
First, per-vertex curvature: it computes discrete mean curvature and clips it to the 0.5β99.5 percentile range so a few insane vertices can't dominate.
Then two masks are built.
The crease mask. Face-adjacency angles above crease_angle (default 35Β°) mark a crease - but only if the edge is short (under 2.5Γ average edge length), which filters out the long stretched edges that generated topology is full of and that would otherwise make every edge look like a crease. Those vertices get a protection value scaled by ridge_multiplier, then the mask is dilated outward for analysis_radius rings with a cubic falloff - so the protection fades out over the neighbourhood instead of ending abruptly, which is what stops the visible "seam" around smoothed regions.
The finger mask. From the highest-curvature vertices - tips, thin features, finger ends - it flood-fills outward while local curvature stays above a thickness_threshold-scaled bar. This is the node's thin-feature guard: fingers, ears, hair strands and straps get protected wholesale, because those are the things that vanish if you smooth them.
Combined, they become a per-vertex multiplier applied to the smoothing as 1 β protection. Protected vertices barely move; unprotected ones get smoothed hard.
The three modes
standard_taubin(the default, and the third item in the dropdown - yes, the dropdown order is different from the default, don't let it confuse you). Uses trimesh's Taubin filter, then re-aligns the result to the original vertices with a KD-tree query. That re-alignment is the important bit: it guarantees vertex ordering and count are preserved, so your UVs and any downstream mapping survive. It also runs an extra pass that pulls unprotected vertices back toward their neighbours' centroid when they've drifted more than 0.001, killing the micro-chatter the KD-tree step can introduce.edge_tension_laplace- a plain weighted Laplacian. Faster, more aggressive, more feature-eating.semantic_hc_smooth- an HC-style ("humphrey classes") pass that alternates shrinkage and re-inflation. Smoother-looking results, harder to predict.
The inputs
trimesh(TRIMESH) - note the socket is namedtrimesh, not the obviousmesh.smooth_iterations(default 100) andsmooth_factor(default 0.8) - these defaults are not timid. On a mesh you like, start at 20/0.5 and work up.logic_mode- pick the mode first, then tune.crease_angle(default 35Β°) - lower means more things count as creases, so more protection, so less smoothing. This is your main "how much do I trust the features" dial.analysis_radius(default 5) - how far the crease protection spreads. Bigger = softer transitions.feature_protection(default 1.0) - the global multiplier on both masks. At 0 the masks are ignored and you get a uniform smooth, which is the "melt it" setting. This is the first dial to touch if the result is too conservative.ridge_multiplier(1.5),thickness_threshold(0.1) - the strength of crease protection and the sensitivity of the thin-feature flood fill.
Outputs: refined_mesh first, then info.
The painter, which is the feature
At the end it writes vertex colours: red marks the finger/thin-feature mask, green marks the crease protection, white means "smoothed freely". Look at the result in a 3D preview and you can read the node's mind - if a feature you cared about is dark red, it was protected; if it's white, that's why it melted. Then adjust crease_angle or feature_protection and look again.
And that's the catch: it overwrites the visual block. Vertex colours you set with Mesh Colorizer, or a texture material from the GLB, get replaced by the red/green debug colours. Run this before you colour or texture - not after.
Install
cd ComfyUI/custom_nodes
git clone https://github.com/Antonioilev/ComfyUI_Antonioilev_Lightpack.git
python -m pip install trimesh scipy
Restart ComfyUI. Manager can install the pack by name (Antonioilev Light Pack), but it can't resolve the pack's dependencies - there is no requirements.txt and no install.py in the repo - and this node needs trimesh and scipy (scipy usually ships with ComfyUI already). The startup line [Antonioilev_Light_pack] Loaded N nodes (M failed) names any module that failed to import.
Where it belongs: after the destructive repair passes (Clean Mesh, Mesh Fixer Fast), before colouring, texturing, and export. It's the last geometry node in a sane chain - which is also why the community's summary of this whole pipeline holds: the generation took a minute, and the cleanup after it is where the evening went. At least this one shows you what it did.
Inputs (9)
| Name | Type | Default | Description |
|---|---|---|---|
| trimesh | TRIMESH | β | |
| smooth_iterations | INT | 1000β1000 | β |
| smooth_factor | FLOAT | 0.800β1 | β |
| analysis_radius | INT | 50β100 | β |
| logic_mode | COMBO | standard_taubin | 3 options: semantic_hc_smooth, edge_tension_laplace, standard_taubin |
| crease_angle | FLOAT | 350β180 | β |
| feature_protection | FLOAT | 1.000β1 | β |
| ridge_multiplier | FLOAT | 1.51β5 | β |
| thickness_threshold | FLOAT | 0.100β1 | β |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| refined_mesh | TRIMESH | β |
| info | STRING | β |