Nodes/ComfyUI-TurntableGSViewer/Gaussian Merge to Target
ComfyUI Node

Gaussian Merge to Target

Cut a million splats down to 200k without wrecking the scene

By PozzettiAndrea·Created 4 months ago·Updated 7 days ago· 6
Gaussian Merge to Target
    • ply_path
    ply_path
    target_count200000
    output_filenamemerged
    opacity_threshold0.10
    k16
    backendtorch_gpu

    Every 3D Gaussian Splatting fan eventually hits the wall: your trained scene is a million splats and 200 MB, previews crawl, uploads stall, and half the splats are invisible anyway. Naively deleting every fifth splat looks awful - the scene crumbles into holes and flicker. GaussianMerge is the fix: it decimates a PLY to a target splat count using proper pairwise merging, so the scene keeps its shape and color instead of collapsing.

    This is one of the workhorses of the GaussianPack family (repo ComfyUI-TurntableGSViewer, self-labeled "GaussianPack" - same author as ComfyUI's HyWorld2 and TRELLIS.2 wrappers). If you're doing any end-to-end splat work - generate, merge, preview - this is the node between "too big to use" and "actually usable."

    How it works

    The algorithm is NanoGS's MPMM - mass-preserving moment matching. It builds a k-nearest-neighbors graph over splat centers, considers each edge as a candidate pair to merge, and then greedily selects pairs by merge cost. When two splats merge, their positions, colors, and opacities are combined so the total "mass" (and thus the appearance) is preserved rather than just dropped. It's the same idea PlayCanvas's splat-transform --decimate uses, reimplemented in Python.

    Two backends:

    • torch_gpu (default) - the merge runs through PyTorch on CUDA / ROCm / MPS, with an automatic fallback to CPU torch if no accelerator is available. Roughly 5–10x faster than the original.
    • nanogs_cpu - the upstream NumPy/SciPy implementation. Slower but bit-for-bit the reference algorithm, handy when torch isn't behaving.

    For reference, a 1M → 200k merge takes on the order of 10–30 seconds on a modern CPU. Results are cached beside ComfyUI's output directory, keyed on the input's mtime and your settings, so re-running a finished merge doesn't redo the work.

    Inputs that matter

    • ply_path - the splat PLY to decimate.
    • target_count (default 200,000) - approximate output count. Internally it's passed to NanoGS as a ratio (target / input_count), and if your target is larger than the input, the file just passes through unchanged. Not a bug.
    • k (default 16) - how many neighbor pairs each splat gets to consider. 16 is the upstream sweet spot. 8 makes a fast draft; 24–32 helps on specular-heavy scenes; beyond 32 it rarely pays for the extra RAM. Edges grow O(N×k), so high k on a big scene gets memory-hungry.
    • opacity_threshold (default 0.1) - splats below min(threshold, median(opacity)) are pruned before merging, a cheap way to drop the nearly-invisible clutter first.
    • output_filename - basename for the output PLY.

    The single output, ply_path, is the absolute path to the merged file - wire it straight into a preview node, an export, or another merge.

    Installing it

    cd ComfyUI/custom_nodes
    git clone https://github.com/PozzettiAndrea/ComfyUI-TurntableGSViewer.git
    cd ComfyUI-TurntableGSViewer
    pip install -r requirements.txt --upgrade
    python install.py
    

    Restart afterwards. Or ComfyUI Manager → search "GaussianPack". The pack's requirements pull plyfile, the NanoGS git dependency, and the experimental comfy-env installer (it downloads the pixi package manager on first install - expect that, it's deliberate). No model weights to fetch.

    Gotchas

    Where people get burned: feeding a huge scene with k cranked to 64 and wondering why RAM blew up - keep k at 16 unless you have a reason. And if the output looks identical to the input, check target_count against the real splat count (run GaussianAnalysis on it); you probably asked to merge up, which is a passthrough. The result is a decimated scene, not a re-optimized one, so don't expect quality to improve - expect it to survive.

    Categoryviewer

    Inputs (6)

    NameTypeDefaultDescription
    ply_pathSTRINGPath to a Gaussian Splatting PLY file
    target_countINT2000001000–10000000Approximate output Gaussian count. NanoGS works in ratio terms - target / input_count is passed as `--ratio`. If target >= input count, the input is passed through unchanged.
    output_filenameSTRINGmergedBasename for the output PLY (no extension).
    opacity_thresholdFLOAT0.100–1Splats with opacity below min(threshold, median(opacity)) are pruned before merging.
    kINT164–64k nearest neighbors per splat that the merge graph considers as candidate pairs. Higher k -> slightly better quality (more options for the greedy selector) but more RAM + slower (O(N*k) edges). 16 is the upstream sweet spot. 8 = fast draft. 24-32 helps on specular-heavy scenes; 32+ rarely pays off.
    backendCOMBOtorch_gputorch_gpu - MPMM on GPU via PyTorch (CUDA / ROCm / MPS, falls back to CPU torch). ~5-10x faster than nanogs_cpu. nanogs_cpu - original NanoGS NumPy/SciPy backend.

    Outputs (1)

    NameTypeDescription
    ply_pathSTRING