Nodes/ComfyUI-GGUF-Loader/TripoSG Decode Mesh ⚡
ComfyUI Node

TripoSG Decode Mesh ⚡

TripoSG's Marching Cubes Step

By ChrisColeTech·Created 2 months ago·Updated 4 days ago· 24
TripoSG Decode Mesh ⚡
  • triposg_model
  • shape_latent
  • mesh
◄dense_octree_depth8►
◄hierarchical_octree_depth9►
◄bounds1.005►

This is the node that hands you something you can actually use. A shape latent goes in, a ComfyUI core MESH comes out - watertight, untextured, and dense as hell. Everything about the geometry quality of a TripoSG run is settled here, in three integers.

What it does

TripoSG's VAE isn't an image VAE. It's an SDF decoder: given a latent and a 3D coordinate, it tells you how far that point is from the surface. So to get a mesh you sample the field and run marching cubes, and the whole trick of this node is where you sample.

  • A dense occupancy grid at 2^dense_octree_depth per axis - default 8, so 256³. Cheap, coarse, and enough to find roughly where the surface lives.
  • Then a hierarchical octree refined to 2^hierarchical_octree_depth - default 9, so 512³ - but evaluated only in cells near the surface. That's the whole economy of the thing: 512³ of resolution without paying for 134 million field evaluations in empty space.
  • Lewiner marching cubes (via scikit-image) extracts the isosurface from that hierarchy, inside a cube of half-extent bounds.
  • The result is batched into core's MESH, with padded vertices/faces and explicit counts when you feed it more than one latent - so a batch of images decodes to a batch of meshes without cross-contamination.

The output mesh is core's own type, which is the nicest sentence in this article. SaveGLB, Preview 3D, Mesh To File 3D, Decimate Mesh, Fill Holes, Unwrap Mesh, Save 3D Model - all of them take it directly, no conversion, no adapter.

The three numbers

  • dense_octree_depth - 5 to 10, default 8. Sets the coarse grid. Raising it finds the surface more reliably on sparse geometry but costs memory fast; 2¹⁰ per axis is 1024³ booleans and you'll feel it.
  • hierarchical_octree_depth - 5 to 11, default 9. This is effectively your output resolution. 9 gives 512³ - sub-millimetre detail on a 10cm object, and hundreds of thousands of faces. Push to 10 for a print-ready surface on a small object, drop to 8 if you're iterating and don't care yet. It must be at least dense_octree_depth; the node checks and raises if you invert them, which saves you from a confusing "why is my mesh empty".
  • bounds - 0.5 to 2.0, default 1.005, step 0.005. Half-extent of the sampled cube. The POC's 1.005 is deliberate: slightly more than 1.0 so the surface isn't clipped at the model's normalised extent. Shrink it to zoom in on a detail; grow it if your shape is getting cut off at the edges. Both are unusual moves - the default is right almost always.

Output cost, honestly: at the POC defaults you get a mesh with hundreds of thousands of faces. That's not a bug, it's marching cubes at 512³, and every refinement step quadruples the face count in the areas it touches. If you're shipping into a game engine or a slicer, put Decimate Mesh after this and aim for what your target actually wants.

Install

cd ComfyUI/custom_nodes
git clone https://github.com/ChrisColeTech/ComfyUI-GGUF-Loader
pip install -r ComfyUI/custom_nodes/ComfyUI-GGUF-Loader/requirements.txt

Manager install is fine. The one dependency that matters here is scikit-image:

pip install scikit-image

Skip it and the node fails with "TripoSG Decode Mesh needs scikit-image (pip install scikit-image; listed in requirements.txt)" - which is a better error than most, and mildly annoying because pip install --upgrade gguf (the README's headline install) doesn't pull it.

Traps and honest limits

The mesh is watertight but it is not clean. Lewiner marching cubes gives you a closed, printable surface with sane normals - no holes on a manifold it understood - but the topology is uniform triangles following a voxel grid, not edge loops. This is the field-wide problem the KB keeps landing on: great for a static prop or a 3D print, useless for anything that has to deform. Rigging a mesh like this means retopology first, and UniRig's skinning stage in this same pack will bind to whatever you feed it, voxel-ish triangles included.

No texture, no UV. TripoSG is shape only. Come in expecting to unwrap and paint, or accept grey.

Empty or blobby mesh? In order: check the octree depths aren't inverted (it raises, but people swap the widgets and don't read the traceback), check bounds hasn't been shrunk so far the surface is outside the cube, and check you didn't sample at 20 steps with guidance_scale at 2. The decode node is faithfully extracting whatever the sampler imagined.

Batch of meshes, one saved file. SaveGLB handles batches differently from what you might expect, and padded batches carry zeroed vertices past each item's count. Decode one at a time if you want one file per object; the padding is for correctness, not for saving.

Category🤖 CCTech/TripoSG

Inputs (5)

NameTypeDefaultDescription
triposg_modelCCTECH_TRIPOSG_MODEL—
shape_latentCCTECH_TRIPOSG_LATENT—
dense_octree_depthINT85–10Dense occupancy grid = 2^depth per axis (POC: 8 -> 256^3).
hierarchical_octree_depthINT95–11Final surface resolution = 2^depth per axis, refined only near the surface (POC: 9 -> 512^3). Must be >= dense depth.
boundsFLOAT1.0050.5–2Half-extent of the sampled cube (POC: 1.005).

Outputs (1)

NameTypeDescription
meshMESH—