A Splat Should Be a Primitivehoudini_usd_gsplat, and the Cost of Being a Guest Format in the USD Scene Graph
Gaussian splatting produces photographic reconstructions faster than modelling can, and then strands them outside the pipeline as a foreign format that composes with nothing. We argue the fix is not a better importer but a change of status: define splats as first-class USD primitives with their own schema, imaging adapter and Hydra delegate, and every composition feature in USD applies to them for free.
Context
3D Gaussian Splatting arrived quickly and landed awkwardly. As a reconstruction technique it is remarkable: it takes photographs of a real place and returns something a camera can move through, at a level of realism that hand-modelling does not reach and on a schedule that hand-modelling cannot match.
As a pipeline citizen it has been a problem, and the reason is structural rather than technical. Splats arrive as a foreign format. Every integration to date has treated them as a guest: a viewer, a viewport overlay, a custom drawable, a special-cased path bolted alongside the real scene graph. Guests do not compose. A guest format cannot be referenced, layered, variant-switched or payload-loaded, so the moment a capture needs to sit in a shot with everything else, an artist is back to a chain of exports and workarounds that breaks whenever anything upstream changes.
This publication is about that status problem, and about the claim that the correct response is not a better importer.
houdini_usd_gsplat is our test of that claim: an open-source integration that makes a Gaussian splat capture a first-class USD primitive in Houdini Solaris, with its own schema, imaging adapter and Hydra render delegate.
Why This Matters
If you do not live inside USD, here is what this does.
Gaussian splatting is a way of capturing a real place from photographs and rebuilding it as somewhere you can move a camera. The catch has always been that the result lives outside the pipeline, so getting one into a shot means a chain of conversions that break the moment anything changes.
This project makes splats ordinary. A capture becomes a first-class primitive, which means it sits in the same scene graph as every other asset, obeys the same rules, and renders through the same viewport as everything else. An artist can light it, cut a camera through it, and place built geometry inside it without leaving Solaris.
That matters because it moves photographic capture from a novelty into something a supervisor can plan a sequence around. The technology widens what is achievable inside a schedule. The decisions about what to shoot, where to put the camera, and what the shot is for stay with the directors and artists making them. This is the kind of tool we build so our people can attempt more, not so the work can be handed over.
The Argument: Primitive, Not Viewer
The design rests on a single decision, and everything else follows from it: a splat capture is a USD primitive, not a drawable the renderer knows about specially.
The distinction sounds academic and is not. USD's value was never its file format; it is the composition engine. Referencing, layering, variants, payloads, instancing and the whole opinion-resolution model are the reason a large scene can be assembled by many people without collapsing. Those features are not implemented per prim type. They operate on the scene graph itself.
Which means status is the whole game. Anything that is genuinely a prim inherits every one of those capabilities at no additional cost, and anything that merely renders alongside prims inherits none of them and must reimplement each one badly, forever.
So the interesting question is not "how do we display splats in Houdini." It is "what is the minimum required to make a splat an ordinary inhabitant of the scene graph." The answer turns out to be three pieces that correspond exactly to the contract Hydra already defines.
Architecture
The implementation follows the standard Hydra data flow, which is the point: nothing here is a bypass.
Schema. ParticleField3DGaussianSplat is a USD prim schema encoding every per-Gaussian attribute directly in the scene graph: position, opacity, covariance scale and rotation, and the spherical harmonic coefficients that carry view-dependent colour. Because these are real USD attributes on a real prim, a splat authored against this schema composes, references, layers and variant-switches like anything else.
Imaging adapter. UsdVolParticleFieldImaging bridges the schema to Hydra. It reads ParticleField3DGaussianSplat prims and populates the Hydra render index, so any delegate, including the native viewport, consumes them without bespoke format handling. The name preserves an early prototyping lineage, since Gaussian splats share compositing characteristics with USD volumes, and it is kept as-is for pipeline compatibility rather than tidiness.
Render delegate. HdParticleField is a CPU rasteriser built as a Hydra delegate. It performs EWA splatting, an elliptical weighted average filter that keeps splat edges sharp rather than aliased, evaluates spherical harmonics per Gaussian at render time for view-dependent colour, and composites back to front with depth sorting.
The chain is schema, then imaging adapter, then render index, then delegate. That is Hydra's own contract, unmodified, which is why downstream tools that speak USD can address splat prims through the standard imaging API instead of through us.
The authoring surface is deliberately thin, because once the primitive exists there is not much left to build. A Ply Import LOP ingests standard .ply captures straight into the stage as splat prims with no intermediate conversion. A Gsplat Instancer LOP places and scatters captures using standard USD instancing semantics, shown above, which is a good illustration of the argument: instancing was not implemented for splats, it simply applies to them. A ply2usd CLI does the same conversion outside Houdini for existing USD tooling, and a Uruk LOP handles composition for splat-heavy scenes.
What It Costs
Being honest about the price is part of the argument, because a design with no cost is usually a design that has not been built.
Rasterisation is on the CPU. HdParticleField is a CPU delegate. This was the right call for a first-class implementation, since it makes the delegate portable and keeps the focus on the scene graph question rather than on a GPU pipeline, but it is a real ceiling. A CPU rasteriser will not match a purpose-built GPU splat renderer for interactive throughput, and any team evaluating this for heavy realtime work should expect that.
Back-to-front compositing is order-dependent. Depth-sorted alpha compositing is standard for 3DGS and carries the standard consequence: correctness depends on sort order, and sorting is per view. This is a property of the technique rather than of this implementation, but it does not stop being true because it is inherited.
The schema is ours. ParticleField3DGaussianSplat is not a standard USD type. Anything reading these prims needs the schema and adapter available. That is the unavoidable cost of first-class status ahead of standardisation, and it is the correct trade against the alternative, but it is a dependency and worth naming as one.
Limitations and Validity
- Platform coverage is narrow. Built and tested on macOS ARM64. The Linux RPATH is wired but untested, and we are not going to describe untested platforms as supported.
- Houdini version. Requires Houdini 21.0.559 or later, with CMake 3.20 or later to build.
- No published performance measurements. We have not benchmarked this and are not going to imply numbers we do not have. The claims made above are architectural, about what composition buys you, and they should be read as claims about capability rather than speed. See Open Questions.
- The adapter name is misleading by inheritance.
UsdVolParticleFieldImagingreads as volume tooling because it began as volume tooling. Preserved deliberately for compatibility, confusing on first contact.
Open Questions
What does this actually cost per frame? The honest answer is that we have not measured it. The comparison that would matter is a splat prim rendered through this Hydra path against the same capture in a dedicated GPU splat viewer, on identical scenes, reporting the interactivity gap that first-class status is being traded for. Until that exists, treat the CPU ceiling above as a stated constraint rather than a quantified one.
Does a GPU delegate change the argument? We think not, and that is the interesting part. The schema and adapter are delegate-independent by construction, so a GPU rasteriser should be a substitution rather than a redesign. That claim is untested and it is the most valuable thing to test.
Where should a splat schema actually live? A per-studio schema is the right move today and the wrong shape long-term. The version of this that matters is a shared one.
Availability
Open source under MIT, for production use, modification, and redistribution.
GitHub: github.com/plattipus/houdini-gsplat
| Dependency | Version |
|---|---|
| Houdini | 21.0.559 or later |
| CMake | 3.20 or later |
| Platform | macOS ARM64 (Linux RPATH wired, untested) |
| License | MIT |
From the Lab
houdini_usd_gsplat comes out of our open research practice, where methods found in live production are published in full rather than kept in-house, including the parts we have not finished measuring.
It shares a thesis with Crucible, which argues that the irreversible step in a pipeline should happen as late as possible, and with our work on NVIDIA Warp in Houdini, which found that the expensive part of a pipeline is rarely the computation but the crossings between systems. Being a guest format is the most expensive crossing of all. The capture and pipeline work this enables runs straight into our visual effects and animation and film and commercial production projects.