Gaussian Splat Explorer
A working 3D-Gaussian-Splatting renderer, taken apart. Real spherical harmonics, read as view-dependent color rather than directional gain. Drag to orbit, scroll to zoom, click or tap a blob to select it, and hover the image to see how one pixel was assembled.
Color — Spherical Harmonics
Three coefficient sets, one per color channel. Degree 0 is the flat base color; the higher degrees are what changes with the viewing angle.
Scene
Scenes here are authored, not trained: the discs are placed by hand so the primitive is visible in isolation. Real captures reach the same arrangement by gradient descent.
Splat Anatomy
The color this splat shows from every possible direction. The ring marks what currently faces the camera, so orbiting drags that ring across the pattern. This is the identical picture the acoustics explorer draws of a directivity pattern — gain over direction there, emitted color here.
Color Detail (Degree Cap)
Normalization
Two conventions for the same functions. Switching rescales every coefficient by a factor that depends on degree alone, and the rendered image does not move — which is the whole content of the distinction.
Load Your Own Scene
Everything above runs on scenes this page invented. Drop a real one here and every panel on the page — the anatomy sliders, the outlines, the pixel inspector, the storage arithmetic — switches to its numbers. This is for splat scenes and point clouds. The panorama upload further down is a different thing: it takes a 360° photo.
The .zip a capture app hands over works as it is
— no need to unzip. Drop two at once, or shift-click both in the picker, and each is kept with a
button to switch between them.
No file records which way is up, how big the world is, or where its middle sits. The scale and center are taken from percentiles of the data; the axis is a choice, so it is a control. A file that states its own convention is believed.
If a capture app offers both “Splat PLY” and plain “PLY”, take both: the first carries covariance, opacity and spherical-harmonic color and is what makes these panels mean anything; the second is the point cloud training began from, is far smaller, and often reads more clearly at the budget this renderer can afford.
Basis Functions
Rows are degree ℓ, columns order m from −ℓ to +ℓ. These 16 functions are the entire color vocabulary of a splat: its color in any direction is a weighted sum of them, one weight set per channel. Clicking or tapping a cell renders the scene using that single harmonic's share, which shows directly which coefficient is carrying a highlight; clicking or tapping again restores the sum. Cells above the current degree cap are dimmed.
What a Splat Costs
Where the Splats Come From
Everything above treats a splat scene as given. A real one is solved for: a set of photographs, the camera poses recovered from them by structure-from-motion, and then an optimization that moves every splat parameter until rendering from those poses reproduces those photographs. This section runs that comparison live — reference image beside rendered image, with the error between them measured rather than asserted.
Each pyramid is one camera pose. Blue ones are the input views the color fit is allowed to look at; amber ones are held out of it entirely. Drag to orbit.
Capture
Color Fit
Sorting
Blending is not commutative, so the order is part of the answer — and it is only correct for the camera it was computed from. Watch the sort time in the panels below as the splat count rises: that is the half of the problem that never shows up in the picture.
What This Cost
The reference images here are ray-cast from an analytic scene — a shaded sphere over a checkered floor, with a specular highlight and a cast shadow — standing in for photographs, which are not shipped with this page. That ray caster is a genuinely separate renderer: the splats never see anything of it except the pixels of the images above. The poses are given rather than recovered, because running structure-from-motion in a browser tab is not the point being made. The color coefficients, though, really are solved from those images, and every number on this page is measured.
Bring Your Own Photosphere
A 360° panorama is the same kind of object as everything else on this page: radiance as a function of direction, recorded from one point, looking out. So the machinery applies to it directly — it can be tiled with splats, and it can be projected onto the spherical-harmonic basis. What it cannot do is become a scene, and the reason is worth seeing rather than being told.
Source Panorama
This takes a 360° photo, not a splat file. For a
.ply, .splat or point cloud, use Load Your Own Scene higher up
the page.
Using the built-in panorama. An uploaded image is decoded and sampled in this page — it is not sent anywhere.
A photosphere from a phone or a 360 camera is already in the right layout: 2:1, full circle across, zenith at the top. Anything else gets stretched onto the sphere and will look wrong overhead.
Shell
Whole-Sphere Projection
Degree here is applied to the whole panorama at once, not per splat — the environment-map projection, rather than the per-splat color fit above.
Looking out from inside — drag any panel to turn.
The Same Panorama, in a Few Coefficients
At ℓ ≤ 2 this is the nine-coefficient irradiance environment map that real-time renderers have used for ambient lighting since 2001: enough to light a surface convincingly, nowhere near enough to look at. Raising the degree sharpens it slowly and rings around the sun, which is the same band-limiting the per-splat color fit runs into.
How Gaussian Splatting Works (Plain-Language Guide)
This page shares its mathematical core with the
Spherical Harmonics Explorer, part of the
Sonic companion site on audio and acoustics. Both evaluate the same real
spherical harmonics, in the same ACN ordering n = ℓ²+ℓ+m, from the same
associated-Legendre recurrence taken without the Condon–Shortley phase. The only technical
difference is the normalization convention — SN3D there, the orthonormal scaling graphics code
uses here — and that amounts to rescaling each coefficient by a factor depending on its degree,
which the Normalization control demonstrates by leaving the image pixel-identical.
What differs is the reading. There, a coefficient vector is a gain map over direction and the payoff is audible: a microphone pattern, an Ambisonic beam. Here, three of them are the color a blob emits in each direction, and the payoff is a rendered image. The renderer is real — projection, sorting, and blending are carried out in full on every frame — so the diagnostic views below are showing actual intermediate quantities, not illustrations of them.
The Primitive: One Anisotropic Gaussian
A splat is a blob of stuff in space with no surface, no mesh, and no texture. It is described by
four things: a center µ (3 numbers), a covariance Σ giving its size and
orientation, an opacity α, and its color. The covariance is never stored
directly, because an arbitrary 3×3 matrix is not guaranteed to describe a valid ellipsoid
during optimization; instead it is factored into a scale and a rotation,
Σ = R·S·Sᵀ·Rᵀ, and the scale (3 numbers) and the rotation
(a 4-number quaternion) are what get stored and optimized. The Splat Anatomy panel exposes
exactly those numbers for the selected blob.
Is a Splat 2D or 3D?
Both, at different moments, and the word is genuinely used for all three of the following.
- The thing that is stored and optimized is 3D: a blob of density filling a region of space, described by the four items above.
- The thing that is drawn is 2D: project that blob through the camera and it lands as an ellipse on the image. The older literature calls this the footprint, and the technique is named for it — throw a three-dimensional kernel at the image plane and keep the mark it leaves. That mark is the splat.
- After training, the 3D blob has usually become nearly flat: one of its three radii collapses toward zero, because a thin disc lying in the tangent plane is the cheapest way for a Gaussian to represent a piece of opaque surface. So a trained scene is, in practice, a few million oriented discs — 3D objects that have chosen to be almost two-dimensional. Dragging scale z to 0.02 in the One splat scene does by hand what the optimizer does by itself.
Covariance of What, Exactly?
Fair question, and the honest answer is that the name is borrowed rather than earned. The blob's opacity at a point x is
α · exp(−½ · (x−µ)ᵀ · Σ⁻¹ · (x−µ))
which is the functional form of a multivariate normal density with its normalizing constant dropped. In that formula, for an actual Gaussian random vector, the matrix sitting in the middle is that vector's covariance matrix — so the shape parameter here inherits the name.
But nothing in a splat scene is random and no sample is ever drawn. Σ is doing geometry, not
statistics. Its work is this: the set of points where that exponent equals some constant is an
ellipsoid, and every ellipsoid is exactly a rotation plus three radii. The eigenvectors of
Σ are that ellipsoid's three principal axes — the orientation. The square roots of
its eigenvalues are the radii along those axes, one standard deviation each — the size.
That is the whole of what “Σ gives its size and orientation” means, and it is why the
factorization Σ = R·S·Sᵀ·Rᵀ is natural rather than a
trick: it stores the rotation and the radii instead of the matrix they multiply out to. It also keeps
the optimizer honest, since every rotation and every positive radius describes a valid ellipsoid, while
most 3×3 matrices describe none.
If a probabilistic reading is wanted, there is one: Σ is the covariance of a point drawn at random from the blob's own density — a statement about how the blob's mass is spread about its center. That is true, and in practice nobody uses it. The ellipsoid reading is the one that does the work.
The same applies one dimension down. What the rasterizer actually evaluates is Σ′, the 2×2 covariance of the projected footprint: the same borrowed name for the same kind of object, describing the spread of an ellipse on the screen rather than an ellipsoid in space. Turning on Outlines draws that ellipse at three standard deviations.
Why a Gaussian and Not a Triangle
Three properties earn the Gaussian its place. It stays a Gaussian under an affine map, so projecting one to the screen is cheap and exact rather than approximate. It is smooth and differentiable everywhere, including with respect to its own position, scale, and rotation, which is what makes the whole scene trainable by gradient descent. And it has no edge: its influence falls off but never quite stops, so a blob that is nowhere near a pixel still has a gradient pointing toward it, and the optimization can move it a long way. A triangle has none of these — its gradient with respect to a vertex position is zero everywhere except on the silhouette.
From a 3D Blob to a Screen Ellipse
A perspective camera is not an affine map — dividing by depth is not linear — so a 3D
Gaussian does not project to an exact 2D Gaussian. The standard answer, inherited from EWA
splatting, is to linearize the projection at each blob's own center and push the covariance
through that linearization: Σ′ = J·W·Σ·Wᵀ·Jᵀ,
where W is the camera rotation and J is the Jacobian of the perspective divide. Keeping the upper-left
2×2 block gives an ellipse on the screen, and its inverse — the conic — is
what the rasterizer actually evaluates: the opacity at a pixel is
α·exp(−½·dᵀ·conic·d) for the offset d
from the ellipse center. Turning on Outlines draws each of those ellipses at three standard
deviations, which is the footprint the rasterizer walks. Two small corrections ride along: the
Jacobian is evaluated at a point clamped to just outside the frustum, because far off-axis the
linearization diverges and a blob smears across the screen, and a fraction of a pixel is added to
the diagonal of Σ′ so a blob smaller than one pixel cannot vanish between samples.
Sorting, and Why It Cannot Be Skipped
Blobs are semi-transparent, and transparency does not commute: a red veil over a blue one is not
the same color as a blue veil over a red one. So every visible splat is sorted by depth and
blended front to back, carrying a running transmittance T — the fraction of light from
behind that still gets through. Each splat in turn contributes T·αᵢ of
its own color and leaves T·(1−αᵢ) for everything behind it. Once
T falls near zero the remaining splats are skipped, which is what keeps the cost bounded in a dense
scene. The Unsorted button blends in storage order instead, and the image falls apart.
Sorting also explains the one artifact every splat viewer has: when the camera crosses the plane
where two overlapping blobs swap depth order, the sort result flips and the pixel jumps. The
Two splats scene makes that visible in isolation.
Reading One Pixel
Hovering the image breaks the pixel under the pointer into the list of splats that covered it, in
the order they were blended, with each one's α, the transmittance that was left when its turn
came, and the weight T·α it therefore contributed. The weights sum to the
coverage, and whatever is left over is background showing through. That table is the entire
compositing step for one pixel, written out.
Color: Where the Spherical Harmonics Come In
A splat that stored one RGB color would look the same from every angle — no gloss, no
sheen, no wet look, nothing that distinguishes a polished floor from a chalky one. So the color is
stored as a function of viewing direction, and that function is expanded in the same real
spherical harmonics used for directivity patterns in acoustics:
c(ω) = ½ + Σ cₙ·Yₙ(ω), once per color channel.
Degree 0 is a single number per channel — the flat base color. Degrees 1 through 3 add
progressively finer variation with angle. At the usual cap of degree 3 that is 16 coefficients per
channel, 48 per splat.
The highlight on the glossy ball is worth following carefully, because it is a common source of confusion. Each disc's coefficients are fixed; nothing about them changes when the camera moves. What is stored is a lobe pointing in the mirror direction of the light about that disc's own normal. The highlight appears to slide across the ball as the camera orbits only because the camera is walking into and out of each disc's lobe in turn. The Splat Anatomy preview shows the whole lobe at once, with a ring marking the part of it currently aimed at the camera.
Why Degree 3, and Not More
Two reasons, and the page shows both. The first is cost: at degree 3 the color is 48 of a splat's 59 numbers, over 80% of the file. Every step up in degree is quadratic, so degree 4 would add 27 more. The What a Splat Costs panel keeps the arithmetic live while the cap is stepped.
The second is that the extra degrees would not buy what one might hope. A truncated spherical-harmonic sum is band-limited and simply cannot draw a sharp feature: the Sharp highlight preset asks for a tight specular spot and gets back a blur wrapped in a ring — the spherical version of the Gibbs phenomenon. Pushing the sharpness κ up makes this worse, not better. Methods that need crisp mirror reflections therefore abandon this basis and store the color in spherical Gaussians instead, whose building block is one tight lobe rather than a sum of smooth waves.
What Training Does (Not Simulated Here)
The scenes on this page are authored by hand so that the primitive can be seen in isolation. A real capture starts from a sparse point cloud recovered by structure-from-motion, puts one small isotropic splat at each point, and then runs gradient descent: render the current splats from a known camera, compare against the photograph taken from that camera, and push every parameter — position, scale, rotation, opacity, and all 48 color coefficients — down the gradient of that error. Interleaved with it is adaptive density control: splats whose gradients stay large are cloned if they are small (an under-covered region) or split if they are large (one blob straddling detail it cannot represent), and splats whose opacity decays below a threshold are pruned. A scene typically arrives at a few million splats after half an hour. The reason the discs here are laid flat against the surface is that this is where training reliably lands: a thin disc in the tangent plane is the cheapest way for a Gaussian to represent a piece of opaque surface.
Where the Splats Come From: Images, Poses, and a Fit
The section above the guide is the other half of splatting. A capture is a set of photographs and the camera poses recovered from them by structure-from-motion; the splats are then whatever minimizes the difference between rendering from those poses and the photographs themselves. There is no surface prior and no geometry term in that objective. A splat scene is not a model of the world — it is a thing that happens to look right from the places a camera has been.
What is real on this page and what is a stand-in is worth being exact about. The reference images are ray-cast from an analytic scene — a shaded sphere over a checkered floor, with a specular highlight and a cast shadow — because photographs are not shipped with it. The poses are given rather than recovered. But the colors really are fitted: each splat's spherical-harmonic coefficients are the regularized least-squares solution over the input views that can see it, reading the observed color out of the rendered image at the splat's projected center, and every error figure is measured against the reference rather than asserted.
Why a Novel View Is Not Free
Each splat is seen by only some of the cameras, from only those directions. Its color in every other direction is an extrapolation from that handful of samples. So the held-out views tell two different stories, and it is worth loading both. Novel — between two inputs sits inside the ring of cameras at an ordinary height, and costs almost nothing: interpolating between directions that were actually observed is what the basis is good at. Novel — above every input is outside the distribution entirely, and the ball goes pale and blotchy there, because nothing in the data says what the top of it looks like from above.
Two controls make that concrete. Raising Input views narrows the gap — there is simply more of the sphere of directions covered. Lowering Regularization λ widens it: with sixteen unknowns per channel and a handful of observations the system is underdetermined, and without a penalty the high-order terms take large opposing values that reproduce the input views exactly and diverge everywhere else. That is overfitting, visible as a number.
What the Splat Count Buys
The count slider is a budget, and it is spent on two things at once: more primitives, and smaller ones, since the disc radius here falls as one over the square root of the count the way densification shrinks splats during training. The reference is a smooth sphere with a hard-edged shadow on a fine checkerboard, and it is the shadow edge and the checker that go first. Stepping the count up moves the error steadily but with diminishing returns, exactly as the storage cost climbs linearly.
Sorting: Wrong, and Expensive
The order the splats are blended in is part of the answer, and it belongs to the camera it was computed from. Reuse Input 1’s order shows what amortizing a sort across frames costs: at Input 1 it is exactly as good as sorting properly, because it is sorting properly; from a camera on the far side of the object it collapses by several decibels, because the frozen order is now reversed and the far side of the ball is painted over the near side.
None is more interesting than it looks, and the honest reading takes a moment. On this scene it often scores a higher PSNR than correct sorting — while visibly losing the cast shadow, smearing the floor, and letting patches of the far surface bleed through the ball. Two things are going on. The scene is almost all opaque surface, so most pixels are covered by a few nearly co-located splats rather than by a deep stack; and blending them in a scrambled order averages several estimates together, which smooths away per-splat fitting noise. A squared-error metric mildly rewards that smoothing. The difference map does not, and neither does the eye. It is a small demonstration of why papers in this area report perceptual metrics alongside PSNR rather than trusting it alone.
The other half of the sorting problem never appears in the picture at all: it is the time. The per-view sort is the one cost that grows faster than the splat count, and it has to be paid again for every frame and every camera. The readouts beneath each comparison show it climbing as the budget rises.
A Photosphere Is a Function on the Sphere, Not a Scene
A 360° panorama records the light arriving at one point from every direction. That is the same kind of object as a directivity pattern or a splat's color: a function on the sphere. So the basis applies to it unchanged, and the last section does two things with it. It tiles the sphere of directions with splats, fitting each one to the part of the image it covers; and it projects the whole panorama onto spherical harmonics and rebuilds it from the coefficients.
That second view is worth a moment. At ℓ ≤ 2 the rebuilt panorama is nine numbers
per channel — the irradiance environment map that real-time renderers have used for ambient
lighting since 2001. It is enough to light a surface convincingly and nowhere near enough to look at.
Raising the degree sharpens it slowly and rings around the sun, which is the same band-limit the
per-splat color fit runs into, seen on a much larger canvas.
Why One Panorama Cannot Become a Splat Scene
Splatting recovers geometry from parallax: the same surface seen from several places, shifting against its background by an amount that depends on how far away it is. A single viewpoint has no parallax. The depth is not merely hard to recover from one photosphere — it is not present in the data at all.
The section demonstrates that rather than asserting it. Two shells of splats are built from the same panorama at different radii, identical in every other respect. From the center they render to the same picture, pixel for pixel: the readout says so. Nothing in a panorama distinguishes a nearby small world from a distant large one. Step the camera away from the center and the two shells diverge steadily — but the panorama never recorded what is visible from off center, so there is no evidence favoring either. Both are inventions, and the honest reading of an uploaded photosphere is that it yields a painted shell at an arbitrary radius.
One consequence lands on the color model too. Every splat on that shell is observed from exactly one direction, so of the sixteen coefficients per channel only the first is determined. The view-dependent part of a splat's color — the whole reason the higher degrees exist — is entirely unconstrained by a single panorama. The splat count therefore buys angular resolution and nothing else, because from one viewpoint there is nothing else on offer.
None of which makes panoramas useless to the method: a ring of photospheres taken a few paces apart does have parallax, and that is a real capture strategy. What one photosphere gives is an environment, and the section shows exactly how far that goes.
Loading a Real Scene, and Which Formats Are Worth It
Everything above runs on scenes this page invented. Load a Real Scene, in the Scene panel, points the whole apparatus at a file instead. Two kinds are worth loading, for opposite reasons.
A trained splat scene — a .ply from the reference implementation, or the
compact .splat — is the obvious one: every panel here exists to display exactly those
fields, so the anatomy sliders, the footprint outlines, the pixel inspector and the storage arithmetic
all switch over to real numbers. The file stores raw optimizer variables rather than render-ready ones,
and all of it has to be undone on the way in: the opacity is a logit, the three scales are logs, the
quaternion is unnormalized, and the spherical harmonics carry the Condon–Shortley phase that the
basis used on this site omits — a factor of (−1)|m|, which if missed does not
throw but quietly tints the scene as the camera turns.
Either can be dropped in as the .zip a capture app hands over: the archive is opened in
the page and the first scene file inside it is taken, so there is no need to unzip anything first.
Several files can be dropped at once, or shift-clicked together in the picker, and each is kept with a
button to switch between them — which is the quickest way to see what training did, since the two
exports of one capture differ in exactly the way the buttons name.
A plain point cloud — .ply, .xyz, .pts — is
worth loading because it is where splatting begins. Structure-from-motion emits a sparse cloud;
training puts one isotropic Gaussian at each point and sets its radius from the distance to its nearest
neighbors, so dense regions start with small splats and sparse ones with large. Dropping a cloud here
runs that initialization and stops, which turns the one stage the rest of this page only describes into
something on the screen.
“Splat PLY” and “PLY” Are Two Different Objects
Capture apps commonly offer both, under names that suggest one is a variant of the other. They are not. The two exports of one real scan, a statue and the square around it, make the difference concrete:
- PLY — 366,630 vertices, each three double-precision coordinates and three color bytes. 27 bytes a point, 9.9 MB. That is the whole file: where and what color. No size, no orientation, no opacity, and no view-dependence. It is the photogrammetric point cloud, which is the input to training, and it opens in anything.
- Splat PLY — 1,609,700 vertices, each 62 floats: position, an unused normal, 48 spherical-harmonic color coefficients, an opacity, three scales and a four-component rotation. 248 bytes a splat, 399 MB. That is the trained radiance field, the output, and only splat software reads it.
The count is worth noticing too. Training did not keep the 366,630 points it started from; it finished with 1.6 million primitives, because adaptive density control cloned and split them wherever the error stayed high. The 40× size difference is a 4.4× increase in primitives multiplied by a 9× increase in what each one stores, and of those 248 bytes, 192 are color.
Both load here, and loading each in turn shows something neither shows alone. At the same budget the point cloud fills in more solidly than the splat scene does — because its splats are sized here, from the spacing of the points that survived thinning, while the trained scene's splats keep the sizes they were optimized to have and simply become sparse when 99% of their neighbors are dropped. Which is the whole argument for densification, arrived at backwards.
One more thing that pair revealed, which is easy to assume away. The two exports are not in the same coordinate system. The point cloud came out Z-up, its ground plane at z=0 and the whole scan spanning 23 units; the splat export of the same scan declared Y-axis-down and spanned 61. Different orientation, different scale, different origin. So loading both here frames each on its own terms and the view shifts when switching between them, which is honest: making them coincide would take registration, not a shared scale factor. The page says so when it detects the disagreement rather than leaving the jump unexplained. The order the files are loaded in makes no difference.
Two practical notes from that same file. Its header reads Gaussian Splats generated by Polycam
with Y-axis down — when a file states its axis convention, this page believes it rather
than making the reader guess. And about a fifth of its opacities are written as positive infinity, which
reaches full opacity through the logistic function rather than becoming a hole, but only if the loader
is expecting it.
Why There Is No Box to Paste a Capture Link Into
Capture apps hand out share links that look as though they name a file — a capture URL with
something like ?export=ply on the end. It is a reasonable thing to want to paste in here,
and it cannot work. Checking one such link settles it three times over. The address returns
HTML, about 34 KB of web application, not a model: the parameter is a hint to that application
about which dialog to open, and dropping it changes the response by twenty-seven bytes. The file itself
is produced afterwards, for a signed-in user, from a temporary storage address the page mints on the
spot. And the server sends no cross-origin headers at all — its preflight answers 400
— so a browser would refuse to let a page on another domain read the response even if it were the
file.
None of that is a fault in the service; a capture is private, and an export that any site could read would be the surprising design. It does mean the route here is the one the app already offers: export the file, then drop it. Which has the advantage the page relies on anyway — the file is read in the browser and goes nowhere, and a paste-a-link feature would have to fetch it through a relay somewhere to get around the same restrictions, quietly turning a local page into one that handles other people's captures.
Other formats were considered and left out, which is worth saying plainly rather than leaving as a
gap. LAS/LAZ is ordinary LiDAR and perfectly parseable in principle, but the compressed variant
needs a decoder this page would have to carry, and the files are usually geo-referenced and enormous;
the same data exported as .xyz or .ply loads today. DXF is a CAD
interchange format that rarely carries points at all. The mesh formats are a different object
altogether — surfaces rather than samples — and would need sampling into points before any
of this applied. Of those, glTF/GLB is the one worth doing, because a single .glb
carries geometry, materials and textures together; OBJ and STL would arrive with no color
at all, since OBJ keeps its materials in separate files and STL has no notion of color, and
FBX, DAE and USDZ each need a substantial parser for a result the analytic scene in
the capture section already demonstrates.
One limit is honest and unavoidable. A real trained scene holds one to several million splats; this is a CPU rasterizer in a browser tab and manages a few thousand at an interactive rate. Imports are therefore thinned to a budget, which is its own lesson — watching a real capture lose its detail as the budget falls says more about what the count buys than any authored scene can.
Where This Renderer Differs From the Real Thing
Honesty about the model matters more than polish. This renderer sorts every splat globally, in JavaScript, on the CPU; the reference implementation sorts by a combined tile and depth key on the GPU and rasterizes tile by tile, which is what makes it real-time on millions of primitives rather than hundreds. There is no spherical-harmonic compression, no half-precision storage, no anti-aliasing beyond the single dilation term, and the frame is rasterized at reduced resolution while the camera is moving. None of those change the arithmetic the diagnostic views report — they change how fast it runs and at what scale.
Suggested Exercises
- Take one splat apart. On the One splat scene, turn on Outlines and drag scale z down to about 0.02. The ellipsoid flattens into a disc. Drag pitch and yaw and watch the screen ellipse change shape as the disc turns, thinning to a line when it comes edge-on: the projected covariance is the 3D one seen through the camera, and nothing more.
- Watch the falloff. Hover the pointer from the center of a blob toward its edge and follow the α column. It is highest at the center — but never above the stored opacity — and decays as a Gaussian outward. There is no boundary anywhere in that number; the visible edge is only where α drops below what a pixel can show.
- Break the blending. Load Two splats and hover over the overlap: the table lists both, and the second one's weight is smaller because the first already spent some transmittance. Now click or tap Unsorted and turn on Orbit. The overlap snaps between two readings as the camera goes around — the same failure, permanently on, that sorting exists to prevent.
- See view-dependent color move. Load Glossy ball and turn on Orbit. A
white highlight travels across the surface. Now set the degree cap to
ℓ ≤ 0: the ball goes flat and dead, because one number per channel cannot hold a direction. Stepping back up through 1, 2, and 3 restores the sheen in visibly coarser-to-finer steps. - Find the coefficient carrying the sheen. With the glossy ball orbiting, click or tap cells in the degree-1 row of Basis Functions. Each renders the scene from that harmonic alone, and the one aligned with the highlight's direction lights up while the other two stay nearly flat. Clicking or tapping the same cell again restores the full sum.
- Ask for a highlight that will not fit. On the glossy ball, drag Highlight sharpness κ from 14 up to 70 and watch the coefficient values in the panel collapse toward zero: the projection of a tight lobe onto sixteen smooth functions keeps almost none of its peak, and the ball goes nearly matte however bright the highlight asked to be. The Sharp highlight preset on the One splat scene shows the same failure in close-up, in the anatomy preview: what should be a small dot is a broad smear with a faint ring around it, the spherical counterpart of the Gibbs overshoot. Raising the degree cap barely improves either. That ceiling, not an implementation limit, is what caps splat color at degree 3.
- Look at the cost map. On the glossy ball, switch to Overdraw: bright regions are pixels where dozens of splats were blended before the transmittance ran out. Compare against Coverage, which shows how much of each pixel was actually paid for, and against Centers, which strips every blob back to the bare point it started as.
- Drop the camera to the deck. Load Ball and floor and drag the view down until the floor is nearly edge-on. It thins and turns translucent, because a splat with almost no thickness projects to almost no area when viewed along its flat axis. Real captures show exactly this, and it is why grazing-angle views of splat scenes look papery.
- Watch a view the fit never saw. In Where the Splats Come From, set the lower panel to Novel — between two inputs and note the error; then switch it to Novel — above every input. The first is nearly as good as an input view, the second is visibly worse. Interpolating between observed directions is cheap; extrapolating past them is not.
- Buy the gap back. With the lower panel on the extrapolated view, drag Input views from 3 up to 16. The error falls the whole way. Then drop Regularization λ to its minimum and watch it come apart again: the fit is free to overfit the views it has.
- Spend the splat budget. Drag Splats from 60 to 3000 and watch which parts of the difference map give way first — the shadow edge and the checkerboard, both of them high-frequency detail that a small number of large discs cannot hold. The sort time in the readout climbs at the same time; that is the bill.
- Break the sort, precisely. Set the upper panel to Input 1 and click or tap Reuse Input 1’s order: nothing changes, because for that camera the reused order is the correct one. Now switch the upper panel to Input 5, on the far side. The image collapses and the error jumps several decibels. A sort is only valid for the camera it was computed from.
- Distrust the metric. Still in that section, compare Per view against None. The unsorted render loses the cast shadow outright and lets the far side of the ball bleed through the near side — and on this scene it still scores the higher PSNR, because scrambling the order averages several splats together and squared error mildly likes the smoothing. Read the difference map instead.
- Prove the depth is missing. In Bring Your Own Photosphere, read the line under the three panels: a second shell at a different radius renders with no difference at all from the center. Now drag Step away from the center and watch the two disagree more and more. Neither is right, because the panorama never recorded anything from off center — that is what it means for depth to be absent from the data rather than merely hard to extract.
- Watch a panorama become nine numbers. Drag Degree down to 2 and compare the rebuilt strip against the source. That is the irradiance environment map, enough to light a scene and useless to look at. Take the degree up to 12 and it is still soft, with rings around the sun: 169 coefficients against a megabyte and a half of image.
- Upload one of your own. Any equirectangular photosphere from a phone or a 360 camera will load; the file is decoded in the page and goes nowhere. Then drag Splats and find the count at which the detail that matters in that particular image survives. The file never leaves the browser.
- Compare the two exports of one scan. If a capture app offers both “PLY” and “Splat PLY”, take both and load them one after the other. The first is the point cloud training began from, the second is what training produced — more primitives, far more per primitive, and view-dependent color the first does not have at all.
- Point it at something real. Drop a trained
.plyor.splaton Load a Real Scene. Every panel switches to that file's own numbers: click or tap a blob and the anatomy sliders show its actual covariance and opacity, and the coefficient editor shows the spherical harmonics the optimizer arrived at. Then drag Render at most down and watch a real capture thin out. - Watch training start. Drop a plain point cloud instead — a
.ply,.xyzor.ptswith no splat fields. Each point becomes one isotropic Gaussian sized from its neighbors, which is step zero of the optimization and nothing more. Switch the display to Centers to see the cloud it came from, and back again. - Read the budget. Step the degree cap 0 → 3 and watch What a Splat Costs. Color goes from 20% of a splat to over 80%, and the projected size of a million-splat capture goes up roughly fourfold. Every compression scheme in this field starts at that line.
Acknowledgements
Developed in consultation with Jens Herder of Hochschule Düsseldorf (University of Applied Sciences), whose advice on the subject and on how to present it is gratefully acknowledged.
Sources & Inspiration
- The method — Kerbl, Kopanas, Leimkühler and Drettakis, 3D Gaussian Splatting for Real-Time Radiance Field Rendering, SIGGRAPH 2023 — source of the primitive, the tile rasterizer, and the adaptive density control described above.
- The projection — Zwicker, Pfister, van Baar and Gross, EWA Splatting (2002), where the linearized covariance transform and the screen-space dilation come from.
- Spherical harmonics for appearance — Ramamoorthi and Hanrahan, An Efficient Representation for Irradiance Environment Maps (2001); Sloan's Stupid Spherical Harmonics Tricks (2008) for the projection identities used to build the lobes here.
- Poses from photographs — Schönberger and Frahm, Structure-from-Motion Revisited (CVPR 2016), the COLMAP pipeline every capture in this field starts from.
- The same basis, read as directivity — with the audio demonstrations, at the Spherical Harmonics Explorer, part of the Sonic companion site (Begault & Cohen, Sonic: Sound · Audio · Acoustics).