Training Gaussian Splats From Renders, Not Photos

Most 3DGS pipelines start with a camera and end with a scene you look at. Mine starts with a mesh and ends with a boss you shoot apart. Here is what changes.

Most 3DGS pipelines start with a camera and end with a scene you look at. Mine starts with a mesh and ends with a boss you shoot apart. Here is what changes.

zakons

zakons is a solo developer making AsterMaster, a beat-driven roguelite with destructible Gaussian-splat bosses, in Godot. Steam: AsterMaster · site: aster-master.com · info@aster-master.com

Lightning Aviator in a fight in AsterMaster

Three months before my Steam demo I didn't know what gsplat was. I make games alone, I can't draw, and I needed bosses whose damage you could read on the hull itself, not on a health bar. Splats turned out to be the answer — just not in the way this field usually uses them.

The player's drone, a splat cloud, after a few hits

In AsterMaster, a beat-driven roguelite on a hex grid built in Godot 4.6, the player's drone and the bosses are not meshes. Each one is a cloud of about 6,000 Gaussians, trained from Blender renders and drawn as a single instanced mesh. When a boss takes a hit, splats are pushed inward into craters, the same spot deepens layer by layer, and whole pieces tear off as rigid bodies — all in the vertex shader. RadianceFields covered the game in October; this piece is about the part a trailer doesn't show: what happens to 3DGS when the ground truth is a render, the budget is fixed in advance, and the result has to live inside a game engine.

1. A particle system in the shape of a model

On screen my drone is 72 pixels tall and a boss is about 112. Photorealism is not the goal; readability is. A mesh at that size dies boringly: play an animation, dissolve, gone. I wanted a dented side to tell the story of the fight.

A frame from the demo with 1:1 close-ups: the splat drone, a splat boss and a regular mesh enemy

Seen from a game developer's side, a trained splat cloud is something very specific: thousands of instances, each with its own position, orientation, size and colour, already arranged into the shape of the model. That is a particle system. The same data structure draws the hull, takes damage and becomes the debris. And it is small: the source meshes are 25–55 MB each, while the trained drone ships at about 0.5 MB and a boss at about 0.4 MB.

The source mesh (left) and the trained splat hull (right)

2. When the ground truth is a render

Training from synthetic renders removes the hardest parts of capture. Poses are exact, so there is no structure-from-motion step. Alpha masks come for free. You can render as many views as you like, under any lighting you choose. A headless Blender script renders 120–200 views at 1024² with alpha in about 30 seconds per model.

It also lets you shape the camera distribution to match how the asset will be seen. My game camera looks down at 32–50° and models only rotate around the vertical axis, so training views sit on a golden spiral inside that elevation belt. The underside is never seen in the game — which later let me delete about 10% of the splats outright.

But renders bring their own failure modes, and they are easy to miss because renders always look clean:

The splat learns your lighting. I trained one drone on three material variants: a toon shader baked in Blender, flat albedo, and diffuse shading under a white dome. The toon version doubled up with the game's own cel bands; flat albedo came out as a pancake; the dome-lit version kept its volume without fighting the runtime light. In capture, lighting is a given. In synthesis it is a design decision with consequences downstream.

The same drone trained on three lighting variants: cel, flat and ao

The dataset is only as good as the file you render. For weeks the bosses "lacked detail". I blamed the splat budget and the trainer. The real cause: the datasets had been rendered from game-ready files whose textures an old optimisation pass had squeezed to 128². The 2048² sources sat in the next folder. Retraining from them brought back panel lines and teeth that no budget increase could have recovered.

Crimson Skull trained from 128² textures vs the 2048² sources

Perfect poses don't kill floaters. With a black background, a dark splat hanging under a gun barrel costs almost nothing in the loss and even helps shade the hull — a "proxy shadow". Compositing over a random grey background at every step makes any splat outside the silhouette expensive from every view. What helped most was in the dataset again: extending the camera belt down to 14° and raising train views from 120 to 200, so low grazing views supervise the silhouette from below. Splats sticking out of the silhouette went from 18 to 9 after the retrain, and to 7 after an export-time cull. One instrumentation lesson cost me more than any of these: dark floaters are invisible on a black stand. I now judge silhouettes only on grey, and only at game scale.

The same floaters on a black and on a grey background

3. The budget is an input, and opacity is binary

Games need exactly N splats per model, not "however many the densification heuristic decides". gsplat's MCMCStrategy gives exactly that: instead of cloning Gaussians it relocates dead ones onto live ones, so the count never exceeds cap_max. Bosses and the drone get 6,000. A hologram decoy that copies the player's drone uses a separate cloud retrained with cap_max=1800 — taking the top 1,800 splats from the 6,000 model left holes; letting MCMC distribute a smaller budget did not.

The trainer is about 150 lines on top of gsplat, with direct RGB instead of spherical harmonics (the style comes from the data). A run is 6,000 steps at 400² and takes 21–22 seconds on an RTX 3060; retraining every boss is a few minutes. That short loop is what made dozens of experiments with datasets, budgets and penalties possible.

Training at step 0, 500 and 6,000 (about 22 s)

The most consequential trick is an entropy penalty on opacity, o·(1−o), switched on only for the last 40% of training. It pushes opacities to 0 or 1, and about 98% of splats end up fully opaque. Switch it on from the start and it fights the soft silhouette edges; the shape never settles.

Binary opacity is what makes the runtime cheap. Splats above 0.9 opacity form an opaque core, drawn as octagons fitted to each splat's visible disc, with an ordinary z-buffer: no sorting, no discard, MSAA works. The remaining ~200 splats form a thin semi-transparent shell that does need back-to-front order — but since the camera tilt is fixed and models only turn in yaw, the order depends on one angle, so I precompute 64 orders at export. The whole thing runs on Godot's Compatibility renderer without compute shaders, and a full scene with a boss and a crowd holds a 4.6–5.4 ms median frame on an RTX 3060. The trade is explicit: you give up the soft, view-dependent look of a capture and get a depth buffer back.

4. Bake what a camera can't see

In capture, the photos are the only truth. In a game pipeline the splat is a cache of a richer source — the mesh — and anything you can compute from the mesh can be baked into the splats after training:

  • Normals, snapped from the nearest face. They take no part in the loss and cost nothing, but give cel lighting and muzzle flashes from a point light.

  • Part ID (clusters over mesh islands, or hand-labelled parts): rigid part animation and per-part damage.

  • Ambient occlusion from a 24-ray hemisphere: a "depth" mask that decides what glows through the seams and what is inside the hull.

  • Emission, chosen by rarity. "Saturated and bright" lit up 2,572 of 4,200 splats on a red boss; "far from the model's median colour" left 877 — the eyes, the lightning, the jaw.

  • Material class and chunk ID for destruction (below).

Everything fits into one vec4 of per-instance data plus the colour alpha. One engine detail worth knowing: in Godot's Compatibility renderer that per-instance data is stored as half-float, so integers above 2048 are silently rounded (4482 becomes 4480). Every baked channel in the project now stays at or below 255.

Baking from a mesh also means inheriting its bugs. The generated source meshes are assembled from hundreds of open "plates" — Crimson Skull has 558 — and about 40% of them were wound inward. The snapped normals inherited the flip, and craters bulged outward. Volume-based repair doesn't work on open shells; a twenty-line area-weighted vote per component did, and flipped 56% of the Skull's splat normals.

5. Destruction is where splats pay

Destruction treats the opaque core as an array of slots. A hit picks candidates by attack type — a narrow band for a shot, a wide one for a blast, a channel for a railgun slug. A knocked-out splat is not removed: it is pushed inward, which gives a crater a dark bottom instead of a see-through hole. Hit the same spot again and the slot reincarnates one layer deeper, through procedural layers (underlay, frame, innards, a smouldering core). These layers are invented — a generated mesh has no ground truth for its insides — and that is fine for a game.

Five hits on the same side: the hole deepens layer by layer

A neighbourhood graph built once at load time catches islands cut off from the hull and tears them off. The step that made destruction readable was moving from splats to chunks: material- and part-aware k-means++ with equal area per chunk, so a plate breaks as a plate. Size was the key number: 25 splats (about 10 pixels on screen) read as confetti; about 100 splats (20 pixels) read as a piece.

Crimson Skull on the weapon test stand: chunks in flight, then cooled wounds

Animation is just as simple. Each model has up to eight rigid parts driven by uniform arrays — one bone per part, binary weights. A rigid rotation of trained Gaussians is exact, so wings flap and barrels recoil with no loss of quality and no skinning.

6. Where splats didn't pay

Not everything belongs on splats. For one week every enemy was a splat cloud; then ordinary enemies went back to meshes with a matching toon shader. At 60–90 pixels, splat destruction doesn't read and doesn't pay for its content cost. Splats stayed where damage is visible: the player's drone, the bosses, and — since the latest build — the larger turrets.

Two research branches also lost to plain Gaussians. A custom differentiable superellipsoid rasterizer gave charming 500-primitive models but ran at 0.7 s per step against gsplat's 21 seconds per run, with worse loss (0.0137 vs 0.008), and at runtime it needed either ray marching or depth output from the fragment shader. A sparse volumetric lattice was more stable over time, but its SDF variant broke in the renderer, where a ray passes through 15–20 overlapping cells. Half of what they taught me survived as baked data: analytic normals became mesh normals, "panel equals primitive" became part ID, and exact depth without sorting became binarized opacity.

7. Splats as a delivery format for games

One trained cloud now feeds three consumers. The game loads a small custom binary with the opaque core, the shell, 64 sort orders and the baked channels. The game's website renders the same models in the browser with Spark on top of three.js: the drone there is a 16k-splat cloud packed into SPZ at 229 KB, bestiary enemies are about 39 KB each, and Crimson Skull is 85 KB — while the game-ready meshes, with their 128² textures, did not survive close-ups at all. The hologram decoy is the third consumer, with its own budget.

That experience leaves me with a short wish list for the tools around 3DGS:

  1. Per-splat custom attributes as a first-class idea. The KHR_gaussian_splatting release candidate standardises the core. glTF already allows application-specific attributes with a leading underscore; a shared convention for things like part, occlusion and material would let a game ship splats in glTF instead of a private binary like mine.

  2. Synthetic training as a first-class path. Most tools assume photos and structure-from-motion. Rendering from a DCC tool with exact poses, alpha and a camera distribution taken from the target view deserves its own presets.

  3. Budgets and opacity regularisation as standard knobs. For games, an exact splat count and opaque splats matter more than spherical harmonics.

  4. An engine path without compute shaders. Most engine integrations I found are viewers built around compute-based sorting. Opaque splats with a small presorted shell run on much more modest rendering paths.

If you are building tools in this space, I would be glad to compare notes.

Lightning Aviator in a fight

AsterMaster launches on Steam on January 12; the demo is free now. The full technical write-up, with code and the numbers behind everything above, is on the game's devlog.

Transparency: as disclosed on the Steam page, some promo art and item icons, a few source 3D meshes, the background music and some flavor text were made with generative-AI tools and curated by me; nothing is generated at runtime. The splat pipeline, shaders and destruction described here are my own work, with part of the code written in pair with an AI coding agent.

Thumbnail for Gaussian Splatting News episode 12

11:38

Watch · New every Monday

Splats Come to Fortnite, Nike Shoots in 4D, Splats on a Nintendo 3DS

Episode 12 · Nov 9, 2026

Epic’s UEFN 43.00 brings Gaussian splats into the Unreal Editor for Fortnite, importing PLY and SPZ files that render on every platform UEFN supports, mobile included.

Featured

Recents

Platforms

SpAItial Opens Its Echo-3 API to Every Developer Account

SpAItial's Echo-3 API is now open to every developer account, turning a ZIP of phone frames into a metric-scale Gaussian splat for 900 credits plus 1 per frame.

Michael Rubloff

Nov 11, 2026

Platforms

SpAItial Opens Its Echo-3 API to Every Developer Account

SpAItial's Echo-3 API is now open to every developer account, turning a ZIP of phone frames into a metric-scale Gaussian splat for 900 credits plus 1 per frame.

Michael Rubloff

Platforms

Esri Adds Viewshed and Shadow Cast Analysis to Splats

ArcGIS Maps SDK for JavaScript 5.2 adds Viewshed and Shadow Cast analysis to Gaussian Splat layers, with Esri noting that splat artifacts may show in results.

Michael Rubloff

Nov 11, 2026

Platforms

Esri Adds Viewshed and Shadow Cast Analysis to Splats

ArcGIS Maps SDK for JavaScript 5.2 adds Viewshed and Shadow Cast analysis to Gaussian Splat layers, with Esri noting that splat artifacts may show in results.

Michael Rubloff

Research

Spaghetti Splatting Swaps Gaussian Points for Curves

Spaghetti Splatting replaces Gaussian points with connected curves, matching 3D Gaussian Splatting on general scenes and producing strands ready for simulation.

Michael Rubloff

Nov 11, 2026

Research

Spaghetti Splatting Swaps Gaussian Points for Curves

Spaghetti Splatting replaces Gaussian points with connected curves, matching 3D Gaussian Splatting on general scenes and producing strands ready for simulation.

Michael Rubloff

Platforms

design4real Releases Splatmania, a Free Splat Editor

Splatmania is a free browser Gaussian splat editor by design4real, built on SuperSplat with a multi-camera cut timeline, depth selection and stereo 360 output.

Michael Rubloff

Nov 11, 2026

Platforms

design4real Releases Splatmania, a Free Splat Editor

Splatmania is a free browser Gaussian splat editor by design4real, built on SuperSplat with a multi-camera cut timeline, depth selection and stereo 360 output.

Michael Rubloff

Trending Articles
  1. TRENDING
    Loading...
  2. TRENDING
    Loading...
  3. TRENDING
    Loading...

New to Gaussian Splatting? Start here

Radiance fields, explained from the ground up: what a Gaussian splat is, how to capture one, and which tools and gear to start with.

Newsletter

Keep up with the field.

New research, tools and captures from the Radiance Fields newsroom, in your inbox. Free, no spam.

Gaussian Splatting News on YouTube

The week in radiance fields, every Monday.

Gaussian Splatting News on YouTube

The week in radiance fields, every Monday.

Gaussian Splatting News on YouTube

The week in radiance fields, every Monday.

Gaussian Splatting News on YouTube

The week in radiance fields, every Monday.