Mesh Simplifier
Shave a Million Faces Off Your ComfyUI 3D Mesh Without Melting the Textures
- mesh
- simplified_mesh
The name is a lie - Mesh Simplifier doesn't do any AI. It's a 3D mesh utility wearing a diffusion-workflow costume, and honestly that's the best thing about it. When ComfyUI-3D-Pack hands you a StableFast3D, Hunyuan3D, or ZeroScope3D mesh, it's usually carrying tens of thousands to millions of triangles that your target engine, game, or Blender scene doesn't need. This node drags that down to a sane face count while keeping the texture map on it, so you get a model that still looks like the original instead of a melted wireframe. The author (roundyyy on GitHub, r0undyy on Reddit) built it to clean up his own StableFast3D workflow after getting sick of the messy, intersecting geometry these models ship - so it's a dogfooded utility, not a demo.
How it works
Under the hood it's a file-based roundtrip: your mesh gets written to a temporary OBJ, PyMeshLab loads it into a MeshSet, runs decimation, and the result is read back into ComfyUI-3D-Pack's MESH format. No GPU involved - this is CPU number-crunching from the VCGLib mesh-processing library.
The actual decimation is Quadric Edge Collapse, the workhorse algorithm behind most mesh-simplification tools. For meshes with UV coordinates it runs the texture-aware variant (meshing_decimation_quadric_edge_collapse_with_texture) that folds texture distortion into its cost function; for naked meshes it runs the plain version. If pre_clean is on, it first merges close vertices, drops unreferenced vertices, and kills duplicate faces - which fixes a lot of the "jumbling" that raw 3D-gen output is famous for. It then runs a planar edge-flip optimization as a polish pass and copies your albedo and metallic-roughness maps back onto the simplified mesh.
The inputs that actually matter
There are eleven knobs, but you'll live most of your life on four:
- simplify_method -
target_facesorpercentage_reduction. Pick one strategy; the other parameter gets ignored. - target_faces - exactly how many faces you want out (default 1000). This is the one I'd reach for: "give me 5k faces" is easier to reason about than a percentage.
- percentage_reduction - the fraction to remove, not keep. 0.75 means "cut 75% of the faces," which confuses everyone once.
- pre_clean - merge close vertices and delete duplicates first. Great for 3D-gen output, but it's also the setting that can trigger the texture-coordinate error below, so keep it in mind when things break.
The rest - quality_threshold, texture_weight, preserve_boundary, boundary_weight, optimal_position, preserve_normal, planar_simplification - are quality dials you can leave at defaults until you care. The one output, simplified_mesh, is a MESH that wires straight into 3D-Pack's Save 3D Mesh node.
Install
Two dependencies first: ComfyUI-3D-Pack is a hard requirement - the MESH type comes from it, not from this node - and PyMeshLab gets pulled in automatically. In ComfyUI Manager, search "Mesh Simplifier" and hit install. Manual route:
cd ComfyUI/custom_nodes
git clone https://github.com/roundyyy/ComfyUI-mesh-simplifier
cd ComfyUI-mesh-simplifier
pip install -r requirements.txt
Then restart ComfyUI. Note the requirements pin trimesh==4.4.1 and numpy==1.26.4 exactly - the classic ComfyUI pain point, since every node shares one Python environment and another node's newer numpy can silently break this one. If simplification starts throwing odd errors after you installed something else, check those pins. Also: the whole thing is GPL-3.0 because PyMeshLab is GPL, which matters only if you're doing something weird with commercial redistribution.
Where people get burned
The README's known issues, straight from the author:
- "Current mesh does not have Per Wedge Texture Coords" - UVs got lost somewhere. Try gentler simplification (fewer faces removed) or turn
pre_cleanoff. - Missing textures after export - the node transfers albedo/metallic-roughness itself, so connect
simplified_meshdirectly into a Save 3D Mesh node rather than running it through anything else first. - Big meshes crash or eat RAM - PyMeshLab loads the whole thing into memory and it roundtrips through disk. If it dies on a giant model, raise
target_facesor lowerpercentage_reduction.
One honest caveat: the OBJ roundtrip is lossy for fancy PBR setups, and very aggressive decimation will smear fine detail even with texture preservation. For a game-ready character you'd want a real retopo pass in Blender afterward. But for "I need this model at a fifth of the poly count and it has to keep its skin," this is the node the community was quietly asking for.
Inputs (12)
| Name | Type | Default | Description |
|---|---|---|---|
| mesh | MESH | — | |
| simplify_method | COMBO | target_faces | 2 options: target_faces, percentage_reduction |
| target_faces | INT | 100010–1000000 | — |
| percentage_reduction | FLOAT | 0.750.01–0.99 | — |
| quality_threshold | FLOAT | 0.50.1–1 | — |
| texture_weight | FLOAT | 1.00–2 | — |
| preserve_boundary | COMBO | True | 2 options: True, False |
| boundary_weight | FLOAT | 1.00–2 | — |
| optimal_position | COMBO | True | 2 options: True, False |
| preserve_normal | COMBO | True | 2 options: True, False |
| planar_simplification | COMBO | True | 2 options: True, False |
| pre_clean | COMBO | True | 2 options: True, False |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| simplified_mesh | MESH | — |