๐ผ๏ธ GLB Preview
See the mesh before you wire it into anything expensive
- glb_path
Image-to-3D is a lottery, and the honest state of the field is that you get a decent silhouette bolted to garbage topology - the model's own author admitted as much about the flagship. So the useful question after a generation isn't "is the file valid", it's "does this thing look like the prompt". GLBPreview answers that in the graph, at any point, with a rotatable viewer. You can check the mesh before you spend ten minutes rigging it.
Why it exists
The ComfyUI-3D-Pack viewer is a nice piece of work - it hooks into a node's output UI data under the key three_model and renders it with Three.js in an iframe. The problem is that most mesh-producing nodes aren't output nodes, and the ones that are write their GLB somewhere the browser can't fetch it. GLBPreview is the bridge: point it at any GLB path and it makes the viewer work.
That includes files nowhere near ComfyUI. A mesh sitting in /tmp, or on a mounted scratch disk, gets symlinked into output/ so ComfyUI's /view endpoint can serve it to the browser. Zero copy, zero disk cost.
How it works
You feed it a path. It resolves your input in this order: as an absolute path, then relative to input/, then relative to output/. Not found in any of those, and it errors rather than passing a dead string downstream.
If the file is already inside output/, it just reports the relative filename and subfolder. If it's anywhere else, it creates a symlink in output/ named preview_<original_filename>. If symlinking fails - cross-device, or a filesystem that won't do it - it falls back to a real copy, but only under 500 MB. Larger than that and you get a clear error telling you to move the file into output/ yourself. That cap is a good decision; silently copying a 3 GB splat-adjacent asset into your output folder is the kind of thing you only notice when your drive is full.
The actual preview is rendered by a small frontend extension in the pack (web/js/glb_preview.js), which loads ComfyUI-3D-Pack's threeVisualizer.html in an iframe on the node and feeds it the filename the Python side returned. Orbit, zoom, pan - it's the 3D-Pack viewer, not a reimplementation.
Inputs and output
glb_path - a STRING. The source marks it a forced input, so in practice you wire it (from GLBLoader, from a generation node's string output, from a primitive) rather than typing it. It also means a typo can't creep in, which is the point.
glb_path (output) - the same string, unchanged. Passthrough, so you can slot the preview in the middle of a chain without breaking it: generate โ preview โ rig. It's an output node, so it always executes.
Installing it
cd /path/to/ComfyUI/custom_nodes
git clone https://github.com/JayDataEngineer/melite-utility-nodes.git
Restart ComfyUI. In ComfyUI Manager, search Melite Utility Nodes, or install by Git URL. The pack's requirements.txt (and the matching pyproject.toml) pulls matplotlib and av; neither is needed for this node, they're for the plot and decode nodes elsewhere in the pack.
The viewer itself needs ComfyUI-3D-Pack installed - that's where the Three.js bundle and the iframe page come from. And this is the real cost of the whole affair, so don't let anyone undersell it: 3D-Pack builds a stack of compiled CUDA extensions (pointnet2_ops, simple-knn, diff-gaussian-rasterization and friends) against your exact torch and CUDA versions, ships prebuilt wheels for one pinned target, and its issue tracker reads like a support group. If you only want the preview and not the models, that's a lot of build pain for a viewport.
Where it bites
- No 3D-Pack, no inline viewer. The node doesn't fail - it renders an overlay saying the pack is required, and the passthrough still works. The GLB is still symlinked into
output/, so you can click it in the output list and get your OS's default viewer instead. Just don't file a bug about the black rectangle. - Same-named meshes fight. The symlink is named from the file's basename with a
preview_prefix. Two previews of two differentmesh.glbfiles in different folders are two writers to one destination, and the second one deletes the first's link to install its own. Rename one. - Empty input is an error, not a blank viewer. You'll get a ValueError for an empty path; check the wire before you blame the renderer.
- It re-previews on file mtime, which is the behaviour you want for a file that a node upstream just rewrote - and also means a mesh regenerated with identical content will still re-render the viewer.
Inputs (1)
| Name | Type | Default | Description |
|---|---|---|---|
| glb_path | STRING | Path to a GLB/GLTF/OBJ/FBX file. Can be absolute or relative to ComfyUI's input/ and output/ directories. |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| glb_path | STRING | โ |