Log inGet started
World

Builtin Library

Branchmain
Branchesmainpublish
Commit3bb1da2647

README.md

gaussianSplats

Draws every Gaussian splat cloud registered in @builtin::systems.gaussianSplats.gaussianSplats.

On an entity's first frame the feature decodes its capture (renderer.splat.components) and uploads the packed record pool — plus the spherical-harmonics pool when the capture carries one — to named GPU buffers. Every frame after that it sorts each cloud against the camera being drawn, then enqueues one kind = "splat", channel = "gaussian" pass per cloud into a feature-owned RGBA16F target. A full-screen pass at afterLighting lays that target over the scene colour with a premultiplied "over".

An empty registry enqueues nothing.

Velocity

A cloud is placed rigidly by its entity's world transform, so every splat in it undergoes the same screen-space displacement. The draw is handed where the transform stood last frame alongside where it stands now, and writes each splat's displacement into a second target — composited "over" under exactly the alpha its colour was, so the target resolves to (coverage-weighted mean displacement, coverage).

Two more passes fold that into the frame's velocity buffer: splat_velocity_merge weights the clouds' displacement against what the geometry passes wrote by that coverage, and a copy lays the result back over @scene.motion, because a pass cannot sample the attachment it renders into.

All three passes run at afterLighting, ahead of the passes that read the scene colour and the velocity buffer together — a denoiser's history term (order 50), motion blur (310) and the temporal antialiasing resolve (600) — so the cloud is in the image and the cloud's motion is in the velocity buffer by the time any of them looks. gaussianSplats.setVelocity(false) turns the chain off for the whole feature — the clouds share one accumulation target, so what lands in it is a property of the frame rather than of a single cloud — and with it off neither velocity target is allocated and neither pass is enqueued.

The sort

splat_cull assigns each splat a log-spaced depth bucket and seeds the identity permutation. A stable LSD radix sort then orders the cloud on that key, eight bits per pass; each pass runs the shared gpuSort passes radix_hist → radix_scan → radix_scatter, and they ping-pong the permutation between the order buffer and a scratch buffer so the last one lands in order.

Alpha compositing is order dependent and the correct order changes with the camera, so it cannot be baked into the capture. A splat's slot comes from its rank among earlier same-digit splats in its own block, which makes the permutation a function of the capture and the camera alone — the same camera produces the same pixels.

A culled splat takes the key one past the last real bucket, so it lands in the tail; the last pass resolves it to 0xffffffff, and that slot collapses its quad. This is what lets the pass issue a fixed instance count with no read-back and no indirect draw arguments.

Buffers per cloud

BufferContents
gaussianSplats.rec.<id>Packed splat records (vertex-pulled by the draw).
gaussianSplats.sh.<id>Quantized higher-order SH, when the capture has any.
gaussianSplats.view.<id>CullUniforms for the frame's camera.
gaussianSplats.keys.<id>Per-splat depth bucket.
gaussianSplats.order.<id>The sort's output — the draw order.
gaussianSplats.scratch.<id>The permutation the radix passes ping-pong through.
gaussianSplats.hist.<id>Per-block digit populations, then their prefix sum.
gaussianSplats.stats.<id>Surviving splat count.
gaussianSplats.sort.<id>.<n>Constants for radix pass n.

They are freed when the entity leaves the registry, despawns, or points itself at a different capture.

Feature-owned targets

Screen-sized RGBA16F, one set for the whole feature rather than one per cloud.

TargetContentsAllocated
gaussian_splats_accumEvery cloud's premultiplied colour, composited "over".The first frame a cloud draws.
gaussian_splats_velocityEvery drawn cloud's displacement and coverage.The first frame a cloud draws while the clouds report their motion.
gaussian_splats_velocity_mergedThe frame's velocity buffer with the clouds folded in.Beside the one above.

They are released when the feature is destroyed.