Python: Gaussian Splats#
This example demonstrates two ParticleField rendering features using the same cactus scene:
Smoother Gaussians: non-stochastic rendering reduces transparency noise in RTPT, making fine details smoother from the first frame.
Relighting:
ParticleFieldSHDiffuse.mdllets scene lights illuminate the Gaussians using their captured color as diffuse albedo.
Smoother Gaussians with Non-Stochastic Rendering#
The close-up compares stochastic.usda and non_stochastic.usda through
Camera_close. Both use the default emissive material and identical settings
apart from omni:rtx:rtpt:gaussian:nonStochastic:enabled.
Enabling it reduces the grain around the cactus spines without waiting for
multiple frames to accumulate, at a performance cost. Lighting and shadows can
still contain noise.
Camera_close, RTPT first frame: non-stochastic compositing off (left) and on (right). Matching crops enlarged 3× without smoothing. Only the non-stochastic attribute differs.#
Enable non-stochastic compositing on the RenderProduct. This feature requires RTPT; disable adaptive disocclusion sampling, which would force stochastic rendering:
over "Render" {
over "Camera" {
rel camera = </World/Camera_close>
token omni:rtx:rendermode = "RealTimePathTracing"
bool omni:rtx:rtpt:gaussian:nonStochastic:enabled = true
# Adaptive disocclusion sampling would force stochastic rendering.
bool omni:rtx:rtpt:adaptiveSampling:disocclusion:enabled = false
}
}
product = UsdRender.Product.Get(stage, "/Render/Camera")
product.GetCameraRel().SetTargets(["/World/Camera_close"])
prim = product.GetPrim()
prim.CreateAttribute("omni:rtx:rendermode", Sdf.ValueTypeNames.Token).Set("RealTimePathTracing")
prim.CreateAttribute("omni:rtx:rtpt:gaussian:nonStochastic:enabled", Sdf.ValueTypeNames.Bool).Set(True)
# Adaptive disocclusion sampling would force stochastic rendering.
prim.CreateAttribute(
"omni:rtx:rtpt:adaptiveSampling:disocclusion:enabled", Sdf.ValueTypeNames.Bool
).Set(False)
Relighting with the Diffuse MDL#
The wider view through Camera compares the default emissive appearance with
sh_diffuse.usda under the same studio lighting. The default material displays
the captured appearance; ParticleFieldSHDiffuse uses the SH0 color as diffuse
albedo so scene lights can shade the cactus and pot.
Camera, RTPT after 32 frames: default emissive material (left) and ParticleFieldSHDiffuse with normal tone mapping (right).#
ovrtx supplies ParticleFieldSHDiffuse.mdl with its runtime materials, at
bin/mdl/ParticleFieldSHDiffuse.mdl in the extracted SDK package. You do not
need to write an MDL material; see Supplied Material Source. The snippet below references and binds the
supplied material to the ParticleField and enables normal tone mapping.
Diffuse relighting works in PT and RTPT and uses stochastic transparency.
Captured lighting remains in SH0, so this does not recover unlit surface color.
over "World" {
def Material "SHDiffuse" {
token outputs:mdl:surface.connect = </World/SHDiffuse/Shader.outputs:out>
def Shader "Shader" {
uniform token info:implementationSource = "sourceAsset"
uniform asset info:mdl:sourceAsset = @ParticleFieldSHDiffuse.mdl@
uniform token info:mdl:sourceAsset:subIdentifier = "ParticleFieldSHDiffuse"
token outputs:out (renderType = "material")
}
}
over "Splats" (
prepend apiSchemas = ["MaterialBindingAPI"]
) {
rel material:binding = </World/SHDiffuse>
}
}
over "Render" {
over "Camera" {
# Render scene-lit color through the normal color pipeline.
bool omni:rtx:gaussian:skipTonemapping:enabled = false
bool omni:rtx:rtpt:gaussian:nonStochastic:enabled = false
}
}
material = UsdShade.Material.Define(stage, "/World/SHDiffuse")
shader = UsdShade.Shader.Define(stage, "/World/SHDiffuse/Shader")
shader.SetSourceAsset(Sdf.AssetPath("ParticleFieldSHDiffuse.mdl"), "mdl")
shader.SetSourceAssetSubIdentifier("ParticleFieldSHDiffuse", "mdl")
output = shader.CreateOutput("out", Sdf.ValueTypeNames.Token)
output.SetRenderType("material")
material.CreateSurfaceOutput("mdl").ConnectToSource(output)
# Bind to the existing ParticleField; its SH0 data becomes diffuse albedo.
splats = stage.GetPrimAtPath("/World/Splats")
UsdShade.MaterialBindingAPI.Apply(splats).Bind(material)
product = stage.GetPrimAtPath("/Render/Camera")
# Render scene-lit color through the normal color pipeline.
product.CreateAttribute("omni:rtx:gaussian:skipTonemapping:enabled", Sdf.ValueTypeNames.Bool).Set(False)
product.CreateAttribute("omni:rtx:rtpt:gaussian:nonStochastic:enabled", Sdf.ValueTypeNames.Bool).Set(False)
Run the Comparisons#
Follow the Python setup and GPU requirements, then run from the ovrtx repository root:
cd examples/python/gaussian-splats
uv run main.py --scene stochastic.usda --png _output/stochastic.png
uv run main.py --scene non_stochastic.usda --png _output/non-stochastic.png
uv run main.py --scene gaussian_splats.usda --steps 32 --png _output/emissive.png
uv run main.py --scene sh_diffuse.usda --steps 32 --png _output/sh-diffuse.png
RTPT is the default. The first two commands render one frame; the material
comparison renders 32 frames. Add --mode pt to render the diffuse scene in PT.
The first run may take longer while shaders compile.
Scene and Source#
The scene references cactus-100.usdc and requires internet access on first load. The capture is by Steam Studio, released under CC0-1.0; see the original dataset.
See Output Configuration for this setup. If adapting the USDA
example in the Inline Composition section of Loading USD,
rename its RenderProduct from DocsCamera to Camera beneath
/Render. The Camera prim itself can retain its name.
See Gaussian Splats for the Gaussian attribute layout, render-mode support, and feature limitations.