ComfyUI_3DGaussianSplatting
A ComfyUI custom node that renders novel-view previews from image pairs using 3D Gaussian Splatting with sparse scene reconstruction.
ComfyUI 3DGS Preview Node
A ComfyUI custom node that takes two images as input and outputs a novel-view preview rendered with 3D Gaussian Splatting.
Overview
This node reconstructs a sparse 3D scene from a pair of photographs and renders it from a user-defined viewpoint using Gaussian Splatting. No pre-trained model is required — everything runs from scratch using classical computer vision (feature matching + triangulation) followed by a differentiable Gaussian renderer.
[Image 1] ──┐
├──► Feature Matching ──► Camera Pose ──► Triangulation ──► Gaussian Render ──► [Preview]
[Image 2] ──┘
Note: Full 3DGS training typically requires dozens to hundreds of images. With only two images the scene is reconstructed as a sparse point cloud; the output is an informative structural preview, not a dense photorealistic render.
Installation
1. Place the node in ComfyUI
# From your ComfyUI root directory
cd custom_nodes
git clone <this-repo-url> ComfyUI_3DGS
# — or — copy the folder manually into custom_nodes/
2. Install dependencies
pip install -r custom_nodes/ComfyUI_3DGS/requirements.txt
3. Restart ComfyUI
After restart, search for "3DGS Preview" in the node browser (under 3D / Gaussian Splatting).
Requirements
| Package | Minimum Version |
|---------|----------------|
| torch | 2.0.0 |
| opencv-python | 4.7.0 |
| numpy | 1.24.0 |
| Pillow | 9.0.0 |
GPU (CUDA) is used automatically when available; CPU fallback is supported.
Node Reference
Category: 3D / Gaussian Splatting
Node name: GaussianSplattingPreview
Inputs
| Name | Type | Required | Description |
|------|------|----------|-------------|
| image1 | IMAGE | Yes | First input image |
| image2 | IMAGE | Yes | Second input image (different viewpoint of the same scene) |
| render_width | INT | No | Output image width in pixels (default: 512) |
| render_height | INT | No | Output image height in pixels (default: 512) |
| max_gaussians | INT | No | Maximum number of Gaussians (= triangulated points). Range: 100–5000, default: 1000 |
| gaussian_scale | FLOAT | No | Size of each Gaussian relative to focal length. Larger = softer/bigger blobs. Range: 0.001–0.3, default: 0.025 |
| novel_view_yaw | FLOAT | No | Horizontal rotation of the novel viewpoint in degrees. 0 = front, +/− = left/right. Range: −90–90, default: 15 |
| novel_view_pitch | FLOAT | No | Vertical tilt of the novel viewpoint in degrees. Range: −45–45, default: −5 |
| background_color | ENUM | No | Background fill: dark / white / black / transparent (default: dark) |
Outputs
| Name | Type | Description |
|------|------|-------------|
| rendered_preview | IMAGE | Novel-view image rendered with Gaussian Splatting |
How It Works
Step 1 — Feature Detection & Matching
SIFT keypoints are detected in both images (falls back to ORB if SIFT is unavailable). Matches are filtered with Lowe's ratio test (threshold = 0.75).
Step 2 — Camera Pose Estimation
The Essential Matrix is computed via RANSAC, then decomposed into rotation R and translation t between the two cameras.
Step 3 — Point Triangulation
Matched feature pairs are triangulated using the two projection matrices, yielding a sparse 3D point cloud. Points are filtered for validity (finite values, positive depth, depth-outlier removal) and normalized to unit scale.
Step 4 — Gaussian Initialization
Each triangulated 3D point becomes one isotropic Gaussian:
- Position — triangulated 3D coordinate
- Color — sampled from
image1at the feature pixel location - Scale (sigma) — derived from
gaussian_scaleand depth at render time
Step 5 — Novel-View Rendering
A virtual camera is placed at z = 2.5 (normalized scene units) and rotated by the specified yaw/pitch angles. Gaussians are:
- Projected onto the screen using a pinhole camera model
- Sorted back-to-front (painter's algorithm)
- Rendered using batched weighted-additive splatting on PyTorch tensors
- Composited over the chosen background using accumulated opacity
alpha(h,w) = 1 − exp(−weight(h,w) × 2.5)
rgb(h,w) = (Σ gauss_i · color_i) / (Σ gauss_i)
out(h,w) = rgb · alpha + background · (1 − alpha)
Fallback Behavior
If reconstruction fails (too few keypoints, poor matches, degenerate pose), the node falls back to a side-by-side display of the two input images instead of returning an error.
Tips for Best Results
| Situation | Recommendation |
|-----------|----------------|
| Blank or nearly blank output | Increase novel_view_yaw closer to 0, or check that images have enough texture |
| Too sparse / many holes | Increase max_gaussians (up to 5000) or use higher-resolution inputs |
| Blobs too large | Decrease gaussian_scale (try 0.01–0.015) |
| Blobs too small / invisible | Increase gaussian_scale (try 0.04–0.08) |
| Reconstruction always fails | Ensure the two images show the same scene from slightly different viewpoints (10–40° apart works best) |
| Flat / textureless images | SIFT/ORB need texture to find keypoints; add some surface detail |
File Structure
ComfyUI_3DGS/
├── __init__.py # Node registration for ComfyUI
├── gs_preview_node.py # Full pipeline implementation
├── requirements.txt # Python dependencies
└── README.md # This file
Limitations
- Two images only — the scene is reconstructed as a sparse point cloud; dense 3DGS training is out of scope.
- No optimization loop — Gaussians are not refined; colors and scales are fixed at initialization.
- Unknown intrinsics — focal length is estimated as
max(H, W) × 1.2; distorted or fisheye lenses will degrade accuracy. - Baseline sensitivity — very small or very large viewpoint differences between the two images reduce reconstruction quality.
License
MIT