Skip to content

Releases: dreamrec/ComfyUI-Pixal3D

v0.1.10 — 1536_cascade unlocked + save_obj side-export

Choose a tag to compare

@dreamrec dreamrec released this 14 May 21:17

🎯 1536_cascade actually fits on a 34 GB GPU

Empirical finding from 20 mesh-generation runs on RTX 5090: 1536_cascade works in standalone mode as long as low_vram=True is on. The README's previous claim that 1536 OOMs on ≤34 GB cards was only true under eager device placement (low_vram=False); with low_vram=True, upstream Pixal3D offloads the 4× DinoV3 image_cond_model extractors to CPU between stages, which frees enough headroom for the shape-1536 NAF attention to land.

Verified on RTX 5090: 3 back-to-back successful runs with 1536_cascade + low_vram=True + max_num_tokens=49152 + texture_size=4096 + 16/16/16 steps + 300k decimation — every run completed in 64-71 seconds warm, peak allocated ~32 GB.

Bundled workflow changes

Both demo workflows now ship the verified-good 1536 recipe:

Widget Was (v0.1.9) Now (v0.1.10)
pipeline_type 1024_cascade 1536_cascade
max_num_tokens 32768 49152
save_obj (new widget) True
low_vram true true (unchanged)

New: save_obj widget on Pixal3DImageToMesh

When True alongside save_to_output_dir=True, after writing the GLB the node calls glb.export() again with .obj extension. trimesh writes .obj + .mtl sidecar + a base-color PNG next to it.

OBJ is base-color-only (the format has no standard metallic/roughness slots) — keep the GLB as the canonical PBR artifact and use the OBJ for DCC tools that prefer it (Blender, ZBrush, Marmoset, older pipelines).

The widget is appended at the end of the node's optional inputs so old workflow JSONs keep parsing — their widgets_values lists just default to False until updated.

README rewrites

  • Memory + performance table promotes 1536_cascade as the top row with verified-on-5090 numbers (~32 GB peak, ~65-70 s warm).
  • New "1536_cascade unlock" subsection explains why low_vram=True is the key, with the 3-runs-in-a-row evidence.
  • Fragmentation footnote: 1024_cascade + low_vram=False + 49k tokens succeeded 10 times then OOMed on the 11th in the same session. If you hit this, queue Pixal3D: Free Pipeline between batches or restart ComfyUI.
  • Upstream roadmap rephrased: visualbruno's use_tiled_decoder would unlock 1536 on 24 GB cards (we already fit it on 34 GB via low_vram=True).

Full Changelog: v0.1.9...v0.1.10

v0.1.9 — safer bundled demo defaults for standalone mode

Choose a tag to compare

@dreamrec dreamrec released this 14 May 19:59

Why this exists

v0.1.7+ runs Pixal3D in ComfyUI Desktop's .venv (standalone mode) where
comfy-aimdo is loaded and pre-allocates a 16 GB cudaMallocAsync cast
buffer
on top of Pixal3D's own ~14 GB of weights + activations. The old
v0.1.3 demo defaults (16/16/16 steps, max_num_tokens=65536,
low_vram=False) were tuned for pozzettiandrea's TRELLIS2 worker
subprocess where mmgp is NOT loaded — peak ~14 GB. In standalone mode
the same workflow OOMs at ~29-30 GB on a 5090 (34 GB ceiling), specifically
in get_proj_cond_shape's NAF attention at shape-1024 resolution.

What changed

Bundled workflow widget defaults (both pixal3d_image_to_mesh.json and
pixal3d_image_to_mesh_with_external_rembg.json):

Widget Was Now
low_vram false true
max_num_tokens 65536 32768

These are the standalone-mode-safe settings that fit on 16-24 GB cards.
On 32 GB+ cards (RTX 5090, A6000-class), flip low_vram back to false
in the widget to cut wall time roughly in half.

The in-workflow Note node explains both the new defaults and the
flip-to-low_vram=false speed-up path.

README

The "Memory + performance" table is rewritten for standalone-mode
reality — all peak-VRAM numbers now reflect what users actually
measure. A new bullet calls out the comfy-aimdo cast-buffer tax
explicitly so the next Googler who hits "OOM on demo workflow"
lands directly on the cause.

What didn't change

No code changes — pyproject.toml version bump only. v0.1.8's runtime
device-placement fix + v0.1.7's mmgp / snapshot_download / install
fallback all carry forward.

Full Changelog: v0.1.8...v0.1.9

v0.1.8 — fix device-mismatch on cache-hit low_vram toggle

Choose a tag to compare

@dreamrec dreamrec released this 14 May 17:33

Fix: Input type (cuda.FloatTensor) and weight type (torch.FloatTensor) should be the same

Running the bundled demo workflow (low_vram=False) after a prior queue run
that used low_vram=True would crash with the device-mismatch error above,
at image_conditioned_proj.py:511 (DinoV3 image extractor forward).

Root cause

load_pipeline's cache-hit fast path was just setting _pipeline.low_vram = low_vram
and returning. Three submodel groups end up scattered across devices after a
low_vram=True run, and none of them get re-moved on toggle:

  1. self.models (SS / shape / tex flow + decoders) — upstream Pipeline.to()
    iterates self.models.values(), but only when low_vram=False.
  2. self.rembg_model — upstream pipeline.to() moves it when
    low_vram=False; in low_vram=True mode preprocess_image() does it lazily.
  3. self.image_cond_model_{ss, shape_512, shape_1024, tex_1024} (4x DinoV3
    projection extractors) — these are not touched by upstream pipeline.to().
    Each get_proj_cond_* does if self.low_vram: m.to(device); …; m.cpu()
    after use, so a prior low_vram=True run parks all four on CPU. A follow-up
    low_vram=False run skips the lazy move and forward fails.

Fix

On cache hit, set self.low_vram first (so upstream's pipeline.to() picks the
correct branch), then call pipeline.to(device). When transitioning to
low_vram=False, additionally re-move the four image_cond_model_* extractors
to the device — matching what the initial-load path already does.

Verified

End-to-end with the actual toggle sequence:

  • fresh load low_vram=True → 98s GLB
  • cache hit, toggle to low_vram=False63s GLB, no device error

Full Changelog: v0.1.7...v0.1.8

v0.1.7 — standalone load_pipeline fix

Choose a tag to compare

@dreamrec dreamrec released this 14 May 16:18

Fix: Standalone install actually works now

v0.1.6 shipped to the Comfy Registry but failed at first run with a misleading
Repository Not Found for url: https://huggingface.co/ckpts/... 404. v0.1.7
fixes the real root cause (three layers deep) and adds standalone-mode install support.

Root cause analysis

  1. comfy-aimdo's mmgp lib (shipped in ComfyUI Desktop's .venv)
    monkey-patches safetensors.torch.load_file with a memory-mapped reader.
    Its dtype map at mmgp/safetensors2.py:33 omits complex dtypes; one
    Pixal3D decoder checkpoint contains a single C64 (complex64) tensor →
    KeyError: 'C64' blows up the load.
  2. Upstream Pixal3D's pipelines/base.py:43-46 has a bare except Exception
    that silently swallows that KeyError and retries with the relative path.
  3. The retry path in models/__init__.py:60 misparses relative paths like
    "ckpts/ss_flow_..." as Hugging Face repo IDs and emits the bogus 404 we see.

Fixes (nodes/pixal3d_stages.py)

  • snapshot_download(model_path) resolves to an absolute local snapshot dir
    before from_pretrained, so the loader's os.path.exists check (relative
    to CWD) always succeeds.
  • Pre-extend mmgp.safetensors2._map_to_dtype with C64/C128 so the mmap
    reader handles complex tensors.
  • Wrap from_pretrained in torch.inference_mode(False) as belt-and-suspenders
    against load_state_dict version-counter errors on freshly-constructed
    nn.Module parameters under ComfyUI's outer inference_mode.

Fixes (install.py)

  • Standalone-mode fallback: if no pozzettiandrea/ComfyUI-TRELLIS2
    sibling exists, install deps into sys.executable instead of hard-failing.
    This matches how Comfy Registry / Manager invoke install.py with the
    .venv's python — fresh Registry installs now work out of the box.
  • Worker python search prefers C:\ce\_env_* (the real comfy-env worker
    pool) over any in-plugin stub Scripts/python.exe.
  • install_requirements splits requirements.txt into VCS / hashed / plain
    buckets so pip's --require-hashes mode doesn't reject the VCS MoGe entry.
  • Error message: visualbrunopozzettiandrea (correct upstream fork).

Verified

End-to-end on ComfyUI Desktop + RTX 5090: 56.5s warm run with 8/8/8 steps +
1024 texture + low_vram=True → 8.6 MB GLB output.

Full Changelog: v0.1.6...v0.1.7

v0.1.6 — docs: correct upstream TRELLIS2 fork attribution

Choose a tag to compare

@dreamrec dreamrec released this 14 May 14:24

Documentation-only fix. No code, workflow, or demo image changes.

The bug

The README and NOTICE.md were pointing at `visualbruno/ComfyUI-Trellis2` as our TRELLIS2 upstream. That's wrong — the wrapper that actually gets installed via ComfyUI Manager (and that this plugin's `install.py` looks for under `custom_nodes/ComfyUI-TRELLIS2/`) is pozzettiandrea/ComfyUI-TRELLIS2.

The two forks share the Microsoft TRELLIS.2 lineage but have different `init.py` structure, different node organization, and divergent commit histories. The mistaken attribution was caught when investigating which fork "the new TRELLIS2 commits" actually came from — the deployed install matched pozzettiandrea byte-for-byte; visualbruno's pixal3d-branch commits are unrelated to what users actually have.

What changed

  • README.md: 5 install/requirements/credits references updated to pozzettiandrea. One remaining mention of visualbruno is kept intentionally in the Upstream Roadmap section as a pointer to their experimental pixal3d branch (`use_tiled_decoder`, etc.) — labeled as a separate experimental fork, not as our actual upstream.
  • NOTICE.md: third-party-licenses table updated.

What didn't change

No code, no workflows, no demo images. Just the docs.

Full diff: v0.1.5...v0.1.6

v0.1.5 — STRING output path + custom save prefix + optional auto-save

Choose a tag to compare

@dreamrec dreamrec released this 14 May 13:52

Three additive widget upgrades on `Pixal3DImageToMesh`. Purely wrapper-layer; the underlying `pipeline.run()` integration is byte-identical to v0.1.4 and remains live-validated. Defaults preserve existing behavior.

New widgets

  • `save_to_output_dir` (BOOLEAN, default `True`) — when `False`, skip the auto-save of the GLB to `ComfyUI/output/`. Useful for chained workflows that export downstream via `Trellis2ExportTrimesh` / `SaveGLB`.
  • `output_filename_prefix` (STRING, default `"pixal3d"`) — customize the saved GLB's filename prefix. Final name: `<unix_ns>.glb`. Sanitized to ASCII alnum + `_-` so no path traversal.
  • `keep_warm` (from v0.1.4) unchanged.

New output port

`RETURN_TYPES` extended 4-tuple → 5-tuple:

  • `glb_path` (STRING) — absolute path of the saved GLB. Connect directly into `Preview3D`'s `model_file` slot to skip the explicit `Trellis2ExportTrimesh` hop. Empty string when `save_to_output_dir=False`.

Diagnostic logging

`Pixal3DLoadPipeline` now logs per-stage timing (pipeline load, MoGe load, total). When a cold-load takes 8+ minutes, users can see which phase is the bottleneck instead of staring at silence.

What we deliberately didn't add

Investigated and ruled out:

  • `use_tiled_decoder` widget (TRELLIS2's 1536_cascade fix) — lives in their wrapper layer that calls Pixal3D sub-methods directly. Adopting it = rewriting our single-node design into a multi-node graph. See README's Upstream Roadmap.
  • `pipeline_type` modes `"512"` and `"1024"` (non-cascade) — Tencent's `pipeline.run()` raises `ValueError("Invalid pipeline type for Pixal3D proj mode")` for those values. They only exist in TRELLIS2's per-stage architecture.
  • Pixal3D-T model variant — separate Tencent model marked "not compatible with all nodes" upstream. Defer.

Backward compatibility

Every existing workflow JSON keeps loading. The new widgets have defaults that produce the v0.1.4 behavior. The new STRING return port is the 5th slot — existing workflows wired to ports 0-3 keep working unchanged.

Full diff: v0.1.4...v0.1.5

v0.1.4 — keep_warm widget + memory hygiene + upstream roadmap

Choose a tag to compare

@dreamrec dreamrec released this 14 May 13:25

Targeted refactor after auditing the visualbruno/ComfyUI-Trellis2 pixal3d branch recent commits. No node-API breakage — drop-in over v0.1.3.

What's new

keep_warm widget on Pixal3DImageToMesh

New BOOLEAN widget (default True). When False, the ~14 GB Pixal3D pipeline singleton is freed at the end of the run instead of being kept resident. Default preserves prior behavior (warm singleton → next call ~3 min; cold → ~7-10 min).

Use keep_warm=False when you have a single Pixal3D-then-other-stuff workflow and want the VRAM back without queuing a separate Pixal3D: Free Pipeline node.

Tighter memory hygiene in the post-sampling stages

run_pixal3d now drops latent / mesh references in the right order so peak VRAM during mesh extraction has the most possible headroom:

  • tex_slat (larger) is freed before shape_slat
  • mesh_list is dropped after the single mesh is taken
  • raw mesh (vertices, coords, voxel attrs — ~1-2 GB on 1536_cascade) freed after GLB bake
  • explicit gc.collect() + torch.cuda.empty_cache() between stages

No behavior change — just earlier release of references we no longer need.

README: upstream roadmap section

Documents the TRELLIS2 pixal3d branch in flight — use_tiled_decoder, expanded pipeline_type, per-stage memory management, standard natten 0.21.6 wheel — so anyone reading the docs knows what's coming and why this plugin stays on 1024_cascade defaults for now.

Memory + performance table refreshed

Bundled-workflow row added; 1536_cascade OOM ceiling explicitly called out (~30 GB Pixal3D models + ~16 GB comfy-aimdo cast buffer = 46 GB > 34 GB on a 5090).

What we deliberately didn't change

TRELLIS2's per-stage memory wins come from calling Pixal3D's pipeline sub-methods directly across separate ComfyUI nodes. Our plugin uses pipeline.run() monolithically — same model, same outputs, different control surface. The use_tiled_decoder knob also lives in TRELLIS2's wrapper layer, not in Tencent's Pixal3D pipeline itself. Both of those become accessible to us only when:

  1. Tencent's upstream pixal3d/pipelines/pixal3d_image_to_3d.py exposes the tiled-decoder hook, OR
  2. We rewrite our run_pixal3d to call Pixal3D's sub-methods (SS / shape / tex / decoders) directly, like TRELLIS2's wrapper does.

Option 2 is a significant rewrite and would couple us tightly to Pixal3D's internal API. Holding off until upstream lands either.

Full diff: v0.1.3...v0.1.4

v0.1.3 — workflow polish + demo refresh + rescue speedup

Choose a tag to compare

@dreamrec dreamrec released this 14 May 12:40

Workflow polish, fresh demo images, and a one-line speedup to the cold-load path. No node-API changes — drop-in replacement for v0.1.2.

Changes since v0.1.2

Code

  • nodes/pixal3d_stages.py_rescue_inference_tensors now short-circuits when the caller has already disabled inference_mode. run_pixal3d wraps the whole pipeline call in torch.inference_mode(mode=False), so any tensor allocated inside is already a regular tensor and the rescue is a no-op — but iterating 4× DinoV3 ViT-L + Pixal3D parameters at Python loop speed was costing ~20 minutes single-threaded on cold-load. Now it returns immediately.

Workflows (workflows/pixal3d_image_to_mesh.json + _with_external_rembg.json)

  • Interactive 3D viewer: added Trellis2ExportTrimeshPreview3D chain so users see the textured mesh rotated in-canvas. The redundant 8-view Trellis2RenderPreview was removed (Preview3D is more useful for inspection).
  • Three-lane grid layout: Inputs (LoadImage + optional rembg) → Pipeline (Pixal3DImageToMesh sized 380×950 so every widget is visible) → Outputs (PreviewImage + Save GLB + Preview3D), all on a clean integer grid. The viewport extra.ds is pre-framed for 1080p.
  • In-canvas Note node with the verified low-VRAM tweak ladder for 12–16 GB cards.
  • Higher-quality safe defaults: 1024_cascade + 16/16/16 sampling steps + 65k tokens + 300k decimation + 4096 texture. ~3 min wall time when the pipeline is warm; ~7–10 min on the first run after a ComfyUI restart. Verified live on RTX 5090 — does NOT trip the comfy-aimdo 16 GB cast-buffer + 1536_cascade OOM ceiling.

Demo images (docs/images/)

  • demo_4view.png — 4 PBR-textured views (front / right-3/4 / back / left-3/4) of the new demo subject, rendered offline via pyrender at 2× SSAA with three-point lighting. Bypasses Trellis2RenderPreview's spike/aliasing artifacts.
  • demo_mesh_frontal.png — clay-shaded frontal view of the same mesh so reviewers can read geometry quality independent of the PBR bake.
  • New demo subject (examples/test_image.png) — significantly harder than the previous painted-miniature turtle; better showcase of what the pipeline does on intricate compositions.

README

  • Hero block updated with both demo images + clarifying captions (textured + clay).
  • VRAM-requirements line now points at the workflow's in-canvas Note for low-VRAM tuning.

Install paths

  • ComfyUI Desktop (via Comfy Registry): in-app node browser → search "Pixal3D". The bumped pyproject.toml auto-triggers a fresh registry publish.
  • ComfyUI Manager: search "Pixal3D".
  • Manual: cd ComfyUI/custom_nodes && git clone https://github.com/dreamrec/ComfyUI-Pixal3D && cd ComfyUI-Pixal3D && python install.py

Full diff: v0.1.2...v0.1.3

v0.1.2 — audit fixes: installer detection + packaging polish

Choose a tag to compare

@dreamrec dreamrec released this 14 May 07:19

Maintenance release driven by a full-repo audit. No node-behavior or model changes — the Pixal3D pipeline, Trellis2 dependency, and Windows + RTX 30/40/50 requirements are identical to v0.1.1.

Changes since v0.1.1

  • install.py — replaced fragile string-split TOML parsing with tomllib, and broadened worker-python detection so the installer now handles the newer comfy-env-manager layouts:
    • in-plugin <trellis2>/_env_*/Scripts/python.exe (Windows venv)
    • <env_root>/env/python.exe (symlink to .pixi/envs/default/)
    • legacy <env_root>/.pixi/envs/default/python.exe
    • SystemExit now enumerates every path it probed, so it's actually diagnostic when detection fails.
  • pyproject.toml — added requires-python = ">=3.12" and the Programming Language :: Python :: 3.12 classifier so pip refuses incompatible interpreters up-front instead of failing at runtime with an opaque ABI mismatch.
  • prestartup_script.py — clarifying note in the module docstring: the SubprocessWorker timeout patch is defensive (the new in-process registration model means Pixal3D nodes don't go through comfy_env), kept as cheap insurance.
  • nodes/nodes_pixal3d.py — removed dead import os and import folder_paths (folder_paths is only used inside pixal3d_stages._run_pixal3d_body).
  • Docsdocs/BUILD_NATTEN.md and NOTICE.md corrected to reference the actual bundled wheel name natten-0.21.0+winsm89ptx-cp312-cp312-win_amd64.whl (was winsm89 without the ptx build tag).
  • workflows/pixal3d_image_to_mesh_with_external_rembg.json — appended "gray" to widgets_values so it matches the current node schema. (The sibling workflow JSON already had it; this one was authored before background_color was added.)

Install paths

  • ComfyUI Desktop (via Comfy Registry): in-app node browser → search "Pixal3D".
  • ComfyUI Manager: search "Pixal3D" once Comfy-Org/ComfyUI-Manager#2874 merges.
  • Manual: cd ComfyUI/custom_nodes && git clone https://github.com/dreamrec/ComfyUI-Pixal3D && cd ComfyUI-Pixal3D && python install.py

Full diff: v0.1.1...v0.1.2

v0.1.1 — Registry metadata + auto-publish

Choose a tag to compare

@dreamrec dreamrec released this 13 May 20:41

Metadata-only release that wires the project into the ComfyUI Registry publish flow and populates platform fields.

Changes since v0.1.0

  • pyproject.toml added with [tool.comfy] block (PublisherId = "dreamrec", DisplayName = "ComfyUI-Pixal3D").
  • GitHub Action publish-comfy-registry.yml auto-publishes the node on every pyproject.toml bump pushed to main.
  • Platform classifiers added so the in-app installer can filter correctly:
    • Operating System :: Microsoft :: Windows
    • Environment :: GPU :: NVIDIA CUDA
  • Banner wired to docs/images/demo_4view.png (raw GitHub URL).

Install paths

  • ComfyUI Desktop (via Comfy Registry): in-app node browser → search "Pixal3D".
  • ComfyUI Manager (custom_nodes path): Comfy-Org/ComfyUI-Manager#2874 is open and awaiting maintainer merge.
  • Manual: cd ComfyUI/custom_nodes && git clone https://github.com/dreamrec/ComfyUI-Pixal3D

No node-behavior or model changes vs v0.1.0 — same Pixal3D pipeline, same Trellis2 dependency, same Windows + RTX 30/40/50 requirements.