Nodes/Gaussian Splat Shot Render/Gaussian Shot Render
ComfyUI Node

Gaussian Shot Render

Frame a camera in a 3D splat scene and render it to a plain image

By EnviralDesign·Created 5 months ago·Updated 3 months ago· 0
Gaussian Shot Render
  • extrinsics
  • intrinsics
  • image
camera_lockedfalse
pivot_x0.0000
pivot_y0.0000
pivot_z0.0000
cam_yaw_deg0.00
cam_pitch_deg0.00
cam_roll_deg0.00
cam_distance0.0000
interactive_state{"pivot_x":0,"pivot_y":0,"pivot_z":0,"yaw_deg":0,"pitch_deg":0,"roll_deg":0,"distance":0}
output_width1024
output_height1024
use_source_resolutionfalse
show_viewer_hudtrue
enable_viewertrue
seed0
rand_tx_min0.0000
rand_tx_max0.0000
rand_ty_min0.0000
rand_ty_max0.0000
rand_tz_min0.0000
rand_tz_max0.0000
rand_yaw_min0.00
rand_yaw_max0.00
rand_pitch_min0.00
rand_pitch_max0.00
rand_roll_min0.00
rand_roll_max0.00
rand_loc_pitch_min0.00
rand_loc_pitch_max0.00
rand_loc_yaw_min0.00
rand_loc_yaw_max0.00
gaussian_scale1.0
max_gaussians0
backgroundblack
ply_path

Gaussian Shot Render is the "press the shutter" node of the gaussian-splat-shot-render pack. Feed it a Gaussian Splatting PLY scene and it renders a camera shot - yaw, pitch, roll, distance around a pivot - and hands you a completely ordinary IMAGE on the other end. That's the whole point: it's not a 3D tool that happens to live in ComfyUI, it's a way to turn a 3D scene into images you can push through img2img, inpainting, ControlNet or upscaling like any other tensor.

The fun part is the interactive WebGL scout viewer that lives inside the node. You orbit, dolly and tilt in real time in the browser, and the actual raster stays aligned with what you're looking at. The node is one half of a two-shot workflow this pack ships: point it at a PLY you already have, or pair it with the pack's SHARP nodes (Load SHARP Model + SHARP Predict) to go from a single photo straight to a splat scene, then start framing shots. Single image → 3D → cinematic camera moves, all in the graph.

How it works

This is where you need to calibrate expectations. The inline viewer is WebGL (gsplat, vendored in the repo so you don't need any extra 3D pack) running on your GPU, and it's smooth. The final raster - the thing that actually becomes your image - is a CPU splatter written in NumPy, optionally Numba-JIT compiled. Preview and capture are completely different code paths. Realtime preview absolutely does not imply a fast render. When you hit "run," the node decodes the PLY, builds a camera state from your pivot and angle inputs (or from SHARP's extrinsics/intrinsics if you've connected them), splats the in-frustum gaussians onto a canvas, and returns the image plus a JSON blob of camera state for the viewer to sync with.

The inputs that actually matter

Most of the widget list is camera math you can poke from the viewer and let sync back, but a few you'll set by hand:

  • ply_path - the PLY file. It's marked optional in the schema because it can be wired in, but there's no render without it; the node throws if it's missing.
  • extrinsics / intrinsics - SHARP's camera metadata. Connect them and use_source_resolution makes the output match the source photo's size, ignoring output_width/output_height.
  • output_width / output_height - raster resolution (64–4096); the viewer matches the aspect.
  • camera_locked - commit to the procedural output camera instead of following your interactive preview.
  • seed plus the rand_* min/max pairs - jitter translation, yaw, pitch, roll per seed. Handy for generating a batch of subtly different "takes" off one framing.
  • max_gaussians (0 = uncapped, or top-N by importance), gaussian_scale, background (black / mid-gray / white).

Output is a single image (IMAGE tensor). Wire it straight into your downstream nodes.

Installing it

Grab it through ComfyUI Manager (search "Gaussian Splat Shot Render"), or the usual way:

cd ComfyUI/custom_nodes
git clone https://github.com/EnviralDesign/gaussian-splat-shot-render-comfyui
pip install -r gaussian-splat-shot-render-comfyui/requirements.txt

Then restart ComfyUI and refresh the browser. The requirements are light - numpy, plyfile, huggingface-hub - plus numba, which is listed as strongly recommended rather than mandatory. No model download for the render node itself; you just need a PLY. (The SHARP path pulls a checkpoint from Hugging Face on first use.)

Where people get burned

  • The raster is CPU. Install numba or a 1024² render of a dense splat will feel like a long bath. The first splat in a session may pause while LLVM compiles; later runs are fast. Disk cache is off by default - set GAUSSIAN_SHOT_NUMBA_DISK_CACHE=1 on a stable machine to keep the compile.
  • VRAM confusion. The node never runs the splat on CUDA. GPU memory you see afterwards is SHARP, preview caches, or the browser's WebGL tab, not this node.
  • RAM creep. One decoded PLY is cached in-process (path + mtime keyed), which is great for repeat runs and heavy on big clouds. GAUSSIAN_SHOT_DISABLE_PLY_CACHE=1 trades I/O for memory if it bites.
  • License. The original code is MIT, but the bundled WebGL viewer is GPL-3.0-or-later (from comfy-3d-viewers) - fine for personal use, just know it's in the third-party notices.

Compared to a full 3D viewport pack like Action Director, this is a scalpel: it doesn't animate rigs or emit depth/normal passes, it frames shots and bakes them to images. If that's the job, it does it without dragging a whole 3D pipeline into your graph.

CategoryGaussian Splat Shot

Inputs (37)

NameTypeDefaultDescription
camera_lockedBOOLEANfalse
pivot_xFLOAT0.0000-1000000–1000000Orbit / look-at pivot in scene units (PLY space).
pivot_yFLOAT0.0000-1000000–1000000
pivot_zFLOAT0.0000-1000000–1000000
cam_yaw_degFLOAT0.00-1000000–1000000
cam_pitch_degFLOAT0.00-1000000–1000000
cam_roll_degFLOAT0.00-1000000–1000000
cam_distanceFLOAT0.0000-1000000–1000000
interactive_stateSTRING{"pivot_x":0,"pivot_y":0,"pivot_z":0,"yaw_deg":0,"pitch_deg":0,"roll_deg":0,"distance":0}
output_widthINT102464–4096Raster width; viewer uses same aspect.
output_heightINT102464–4096Raster height; viewer uses same aspect.
use_source_resolutionBOOLEANfalseIf True and SHARP intrinsics are connected, render at the source image size (ignores width/height).
show_viewer_hudBOOLEANtrueShow the interactive viewer info overlay (camera, pivot, resolution).
enable_viewerBOOLEANtrueMount the interactive viewer iframe. Disable to fully unload the viewer UI and WebGL context for this node.
seedINT00–18446744073709550000Locked-shot variation seed.
rand_tx_minFLOAT0.0000-1000000–1000000Locked shot: world-space X translation (scene units) added last, after orbit placement along composed view axis.
rand_tx_maxFLOAT0.0000-1000000–1000000
rand_ty_minFLOAT0.0000-1000000–1000000
rand_ty_maxFLOAT0.0000-1000000–1000000
rand_tz_minFLOAT0.0000-1000000–1000000
rand_tz_maxFLOAT0.0000-1000000–1000000
rand_yaw_minFLOAT0.00-1000000–1000000Locked shot: world-stage yaw (deg) as part of Rδ (Rz·Ry·Rx) left-applied after panel rotation.
rand_yaw_maxFLOAT0.00-1000000–1000000
rand_pitch_minFLOAT0.00-1000000–1000000
rand_pitch_maxFLOAT0.00-1000000–1000000
rand_roll_minFLOAT0.00-1000000–1000000Final downstream roll jitter (deg).
rand_roll_maxFLOAT0.00-1000000–1000000
rand_loc_pitch_minFLOAT0.00-1000000–1000000Locked shot: camera-local pitch jitter (deg), right-applied after world Rδ (same Rz·Ry·Rx order in camera frame).
rand_loc_pitch_maxFLOAT0.00-1000000–1000000
rand_loc_yaw_minFLOAT0.00-1000000–1000000
rand_loc_yaw_maxFLOAT0.00-1000000–1000000
gaussian_scaleFLOAT1.00.1–64
max_gaussiansINT00–2000000 = no cap (all in-frustum splats). >0 keeps top-N by importance.
backgroundCOMBOblack3 options: black, mid-gray, white
ply_pathoptSTRINGPath to a Gaussian Splatting PLY file
extrinsicsoptEXTRINSICSCamera extrinsics from SHARP
intrinsicsoptINTRINSICSCamera intrinsics from SHARP

Outputs (1)

NameTypeDescription
imageIMAGE