C: 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.mdl lets 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 with non-stochastic compositing off and on

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 with default emissive and SH diffuse Gaussian materials

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 Scenes#

Follow the C API setup and GPU requirements. From the ovrtx repository root, build and run the example for your platform:

cd examples/c/gaussian-splats
cmake -B build
cmake --build build --config Release
.\build\static\Release\gaussian-splats.exe `
  ../../python/gaussian-splats/non_stochastic.usda non-stochastic.png
.\build\shared\Release\gaussian-splats-dynamic.exe `
  ../../python/gaussian-splats/sh_diffuse.usda sh-diffuse.png
cd examples/c/gaussian-splats
cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build
./build/static/gaussian-splats \
  ../../python/gaussian-splats/non_stochastic.usda non-stochastic.png
./build/shared/gaussian-splats-dynamic \
  ../../python/gaussian-splats/sh_diffuse.usda sh-diffuse.png

Both loaders accept the same scene layers. Use stochastic.usda for the close-up with non-stochastic rendering disabled, or gaussian_splats.usda for the wider view with the default emissive material.

The C example saves one frame. The diffuse comparison above was rendered with 32 frames using the Python example.

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 Gaussian Splats for the Gaussian attribute layout, render-mode support, and feature limitations.