A Gaussian's spread lives in world units — meters, say. A screen is measured in pixels. Before any of the alpha-compositing from the last chapter can run, every Gaussian has to be projected onto the image plane first, in the right order.
Drag the depth slider. The Gaussian's world-space spread never changes, but its footprint on screen shrinks the farther away it gets pushed — the same perspective shrink a camera applies to a point's position, just applied to a blob's size instead.
Approximating the camera as looking straight at each Gaussian, its projected screen-space spread is world spread scaled by focal length over depth — the exact same ratio that turns a 3D point's position into a pixel:
Gaussians must then be alpha-composited nearest-first, exactly like NeRF's ray samples. Once rendered, 3DGS drops the neural network entirely: every Gaussian's own parameters — opacity, position, color, covariance — get updated directly by gradient descent against a rendering loss:
- — a Gaussian's spread before and after projection.
- , depth — focal length and the Gaussian's distance from the camera.
- — any one of a Gaussian's own parameters (here, opacity); — the learning rate.
- — squared-error loss between the rendered pixel and its target color.
- Two Gaussians, same screen position, different depths
A near, half-opaque red Gaussian (depth 5) and a far, mostly-opaque blue one (depth 10), both centered exactly on the query pixel with the same projected spread. Composited nearest-first: red claims of the pixel, blue claims of what's left — result .
- The same two Gaussians, composited in the wrong order
Farthest first instead: blue claims of the pixel outright, red only gets of the leftover — result . Same scene, same Gaussians, a completely different pixel — because "nearest first" isn't a stylistic choice, it's what makes occlusion correct.
Step through a single Gaussian's opacity being optimized by gradient descent, starting far from the target color. No MLP, no ray march — just this one parameter (and, in a real scene, thousands like it) nudged directly against the rendering loss until the rendered pixel matches the photograph it's being fit to.
Two more depths for the same world spread (, ):
- depth = 10
.
- depth = 20 — twice as far
— exactly half the previous spread. Doubling depth always halves projected spread, for any Gaussian.
And the first gradient step on opacity, starting at (color red, target , learning rate ):
- Loss at the start
Rendered . Loss (red channel matches exactly, so it contributes nothing).
- Gradient and one step
Since rendered , the chain rule gives per channel:
- Red:
- Green:
- Blue:
Summing: exactly. One step: — closer to the target, and the loss at is lower than at .
Drag the learning rate until one gradient step from the starting opacity (0.5) lands on ≈ 0.8.
Rendering a 3DGS scene is projection (world spread shrinks with depth) plus depth-ordered compositing (the same math as the last chapter); training it is nothing more exotic than gradient descent on each Gaussian's own parameters. Neither of those Gaussians has to come from a real 3D scan, though — the next chapter looks at generating one from scratch, out of nothing but a text prompt or a single photo.