MorphGS: Train & Render
This Is Where the GPU Hours Go
- video_path
- frames
- log
Every other node in this pack is preparation. This is the one that trains. It takes the scene and character the two preprocessing nodes produced, registers them as an experiment, runs MorphGS's training loop, and hands back the rendered result - as a file path and as an image batch you can preview in the graph.
What it does under the hood
The experiment is named <scene_name>_to_<character_name>. That string is the join key for everything: the config lands at configs/demo/<experiment>.yaml, and the results land under output/<experiment>/model/morphgs/. If the config file doesn't exist the node creates it - and note it has to write a valid empty YAML mapping, not an empty file, because an empty file makes yaml.safe_load return None and break MorphGS's config merge. Small detail, real failure.
Then it runs MorphGS's own entry point:
python src/main.py --config demo/<experiment>.yaml --model.opt.iterations=<iterations>
Training writes the deform-network checkpoints and, at the end, output/<experiment>/model/morphgs/render/rendered_video_<iterations>.mp4. The node checks that file exists, raises with the full log if it doesn't, copies it into ComfyUI's own output folder as output/morphgs/<experiment>_<iterations>.mp4, and decodes every frame with OpenCV into a float32 RGB tensor.
That last part is the reason this pack needs opencv-python in ComfyUI's environment at all, and it's why the frames output is a whole video sitting in VRAM as an image batch.
The inputs
scene_name and character_name are text fields with no validation and no dropdown. They have to match exactly what you fed the two preprocessing nodes. Wire them from those nodes' outputs rather than retyping them - a typo here doesn't error immediately, it just trains a fresh experiment against inputs that don't exist and fails deep inside MorphGS, several minutes later.
iterations defaults to 5000, ranges 100 to 100000 in steps of 100 - and it's baked into the output filename, so it's part of the experiment's identity, not a retry knob. Train at 5000, decide you want 8000, and you're not resuming; you're running a new experiment from scratch. Whatever number you settle on, remember it, because you need the same number in MorphGS: Export Animated Mesh to find the matching iteration_<n>.pth checkpoint.
force_retrain re-runs training even when a render for that iteration count already exists. Leave it off and re-running this node with the same value is free.
The outputs
video_path is a plain string - the ComfyUI-local copy under output/morphgs/, not the path inside the pipeline environment. Feed it to whatever you normally use for video saving or Video Combine. frames is the IMAGE batch: same video, decoded. Use it for a quick preview, but on a long render at high resolution that tensor is large, so don't wire it into three branches at once. log is the training output, and it's the thing you read when something's off.
Install
Manager, search ComfyUI-MorphGS, restart. Or by hand:
cd ComfyUI/custom_nodes
git clone https://github.com/Yuvaraj0739X/ComfyUI-MorphGS
Set the MorphGS locations before you launch ComfyUI:
export MORPHGS_HOME=/workspace/MorphGS
export MORPHGS_CONDA_ENV=morphgs
export MORPHGS_CONDA_BASE=/opt/conda
Everything expensive happens in that other environment - the pinned torch build, the compiled CUDA extensions, the gsplat rasteriser. ComfyUI itself only needs numpy and opencv-python from this pack. For once, installing a "3D" node pack doesn't mean compiling anything (docs/knowledge/3d-generation.md will tell you what the alternative looks like).
Where people get burned
No timeout, and no progress. This is the only node in the pack that runs its subprocess with no timeout - deliberately, because training takes as long as it takes. The consequence is that output is captured and only returned at the end. You get nothing in the ComfyUI console while it trains: no iteration counter, no loss, no heartbeat. If it hangs, it hangs quietly. Watch the MorphGS process itself, or tail the file it logs to, rather than staring at the queue.
A cached render can fool you. If rendered_video_<n>.mp4 exists, the node skips training and hands you the old file. Changed something upstream, like the video or a character setting, and forgot to re-run preprocessing? Same silent story - set force_retrain, and make sure the upstream nodes actually re-ran with force_reprocess where you needed them to.
It doesn't validate anything for you. Missing motion sequence, wrong scene name, half-processed video - all of it surfaces as a MorphGS traceback in the log rather than a clean "run Preprocess Video first". Read the log; the pack surfaces stdout and stderr verbatim on purpose.
Inputs (4)
| Name | Type | Default | Description |
|---|---|---|---|
| scene_name | STRING | — | |
| character_name | STRING | — | |
| iterations | INT | 5000100–100000 | — |
| force_retrain | BOOLEAN | false | — |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| video_path | STRING | — |
| frames | IMAGE | — |
| log | STRING | — |