πππ¦ 3D View Save Load
The 3D Node That Parks a Mesh on Disk So You Don't Regenerate It
- trimesh
- mesh
- coords
- shape_slat
- env_hdr
- trimesh_scene
- trimesh_merged
- mesh_out
- raw_coords
- shape_slat
What it's actually for
Generating a mesh is the expensive part of any 3D graph, and ComfyUI's habit of re-running upstream nodes means you do it again and again while you fiddle with the downstream half. This node is the fix, and it's the most ambitious thing in the pack: one node that accepts whichever 3D representation your pipeline happens to be carrying, displays it in a full viewport, and caches it to disk so the next run can load it back instead of regenerating.
It also carries a sidecar channel that the rest of the pack cares about: a curvature array, stashed in an .npz next to the mesh, which survives the round trip and gets attached to whatever the node outputs. If your downstream nodes (retopo, curvature-driven tools) depend on per-vertex data, this is the node that keeps it alive across a save/load.
Be warned: this one is opinionated and assumes the author's workflow. Nobody on the internet has written about this pack, so there's no corpus of "here's how I use it" to fall back on. Read the schema and it makes sense.
How it works
The context picker. You feed one of four object types - trimesh, mesh, coords, or a shape_slat - and whichever is connected defines the active context. The node then dispatches to the matching handler for save/preview. If nothing is connected, fallback_input_type decides which context to pretend you're in. This is what makes it a drop-in: generating a gaussian/SLAT/something else this week? Change which socket you plug in, leave the node and everything after it alone.
The mode. Auto (Load if empty) is the useful one: if any 3D input is connected it saves to your path, and if nothing is connected it loads from it instead. Save Only, Load Only, and Preview Only do exactly what they say - the last one skips disk entirely and is the safe setting while you're exploring.
What lands on disk. It splits full_path into a directory and a filename, takes the extension as the save format (defaulting to .fbx if you didn't give one), and writes the mesh there. FBX export is done by writing a temporary GLB and converting it with the Assimp CLI - so that's a hard dependency. Separately it always exports antonioilev_preview_{seed}.glb into ComfyUI's output directory for the viewport to load. And on the load side it looks for a {basename}.npz next to the mesh; if that file has a curvature key, that array is read and re-attached to the outputs' metadata as curvature_scalar, where curvature-aware nodes pick it up.
The viewport. Bounds, extents, vertex and face counts, and the active context go to the UI, along with an optional HDR environment (env_hdr), which gets saved alongside for image-based lighting. brightness, fix_lighting, soft_edges and point_size are display controls; sparse_structure_resolution controls how fine the coords branch is shown.
The inputs that matter
- full_path - the one to change immediately. The default is
/mnt/l/Game_2/Art/; that's the author's drive. Include a filename and an extension you actually want (.glb,.fbx,.obj). - mode - start on
Preview Onlywhile you're wiring, switch toAuto (Load if empty)once you're happy. That single switch is the whole time-saving trick. - brightness / point_size / fix_lighting / soft_edges - viewport cosmetics.
fix_lightingandsoft_edgesare on by default and make generated meshes look considerably less faceted. - env_hdr - optional IMAGE, gives the preview real reflections. Optional in the literal sense; skip it.
- seed - used in the preview GLB filename, and, via
IS_CHANGED, to decide whether the node re-executes at all. Change it to force a re-run.
Five outputs: trimesh_scene and trimesh_merged (both TRIMESH - scene means multi-part kept separate, merged means concatenated), mesh_out (passes through MESH/TRIMESH/MESHWITHVOXEL), raw_coords (wildcard, the sparse points), and shape_slat (SHAPE_SLAT). Wire whichever matches your downstream node; the others pass through untouched, so an unused socket is harmless.
Install
cd ComfyUI/custom_nodes
git clone https://github.com/Antonioilev/ComfyUI_Antonioilev_Lightpack.git ComfyUI_Antonioilev
# restart ComfyUI, then hard-refresh the browser tab
Two notes. The folder name matters: several of the pack's viewer scripts hardcode /extensions/ComfyUI_Antonioilev/, and the pack's own init_lowvram.sh launch script documents the same folder layout. Clone it as ComfyUI_Antonioilev and the iframe resolves. And there's no requirements.txt - __init__.py catches import errors and prints a loaded/failed count instead of raising. You'll want trimesh, plus Assimp for FBX:
sudo apt install assimp-utils # provides the `assimp` CLI
Where people get burned
- Blank or empty viewport. Either the folder-name mismatch, or the preview GLB wasn't written. Check the console - this node is chatty, and its failure messages are explicit.
Save Onlysilently writes a.fbxyou didn't ask for becausefull_pathhad no extension. Give it one.- FBX conversion fails without Assimp, with an error explaining exactly that. No Assimp, no FBX; stick to glTF-based formats if you can't install it.
- The curvature sidecar only survives if you saved it. Load a mesh with no
.npzbeside it and the curvature isn't there - the node prints that it skipped the attach. If a downstream retopo node misbehaves after a load, that's why. - A wrongly-wired graph can look fine. If nothing is connected and
fallback_input_typedoesn't match your intent, you get a load or an empty preview rather than an error.
Inputs (15)
| Name | Type | Default | Description |
|---|---|---|---|
| full_path | STRING | /mnt/l/Game_2/Art/ | β |
| mode | COMBO | 4 options: Auto (Load if empty), Save Only, Load Only, Preview Only | |
| fallback_input_type | COMBO | Trimesh | 4 options: Trimesh, Mesh, Coords (Sparse), Shape Slat |
| brightness | FLOAT | 1.20.1β5 | β |
| seed | INT | 00β18446744073709550000 | β |
| show_preview | BOOLEAN | true | β |
| trimeshopt | TRIMESH | β | |
| meshopt | MESH,TRIMESH,MESHWITHVOXEL | β | |
| coordsopt | COORDS | β | |
| shape_slatopt | SHAPE_SLAT | β | |
| env_hdropt | IMAGE | β | |
| sparse_structure_resolutionopt | INT | 328β512 | β |
| point_sizeopt | FLOAT | 1.00.1β10 | β |
| fix_lightingopt | BOOLEAN | true | β |
| soft_edgesopt | BOOLEAN | true | β |
Outputs (5)
| Name | Type | Description |
|---|---|---|
| trimesh_scene | TRIMESH | β |
| trimesh_merged | TRIMESH | β |
| mesh_out | TRIMESH,MESH,MESHWITHVOXEL | β |
| raw_coords | * | β |
| shape_slat | SHAPE_SLAT | β |