Use a Built-In Node#
Goal. Get a common operation without writing any GPU code.
Before you start. Publish, Overwrite and Read Back AOVs.
The Shape#
A built-in node is named rather than sourced. There is no GPU file and no launch script:
def Shader "AddNode"
{
uniform token info:implementationSource = "id"
uniform token info:id = "spg:rtx.spg.stdlib/Add"
opaque inputs:A.connect = <../LdrColor.omni:rtx:aov>
opaque inputs:B.connect = <../LdrColor.omni:rtx:aov>
opaque outputs:Result
}
How It Works#
The scene adds LdrColor to itself with the built-in Add node, doubling brightness with
saturating arithmetic, then halves the resolution with the built-in Scale node. Highlighted:
the two lines that name each one.
stdlib_scene.usda, from the runnable built-in nodes example#def Scope "Render"
{
def RenderProduct "StdlibDemo"
{
uniform int2 resolution = (1280, 720)
rel camera = </World/Camera>
rel orderedVars = [ <LdrColor>, <Downscaled> ]
def RenderVar "LdrColor"
{
uniform string sourceName = "LdrColor"
opaque omni:rtx:aov
}
def RenderVar "Downscaled"
{
uniform string sourceName = "Downscaled"
opaque omni:rtx:aov.connect = <../ScaleNode.outputs:Output>
}
def Shader "AddNode"
{
uniform token info:implementationSource = "id"
uniform token info:id = "spg:rtx.spg.stdlib/Add"
opaque inputs:A.connect = <../LdrColor.omni:rtx:aov>
opaque inputs:B.connect = <../LdrColor.omni:rtx:aov>
opaque outputs:Result
}
def Shader "ScaleNode"
{
uniform token info:implementationSource = "id"
uniform token info:id = "spg:rtx.spg.stdlib/Scale"
float inputs:scaleX = 0.5
float inputs:scaleY = 0.5
opaque inputs:Input.connect = <../AddNode.outputs:Result>
opaque outputs:Output
}
}
}
info:implementationSource = "id"tells SPG this shader is identified by an SPG node ID, not a source asset.info:idnames the built-in node ("spg:rtx.spg.stdlib/Add","spg:rtx.spg.stdlib/Scale"). Thespg:prefix scopes SPG node IDs away from MaterialX and UsdPreview shader IDs.No external shader definition is needed either. The entire graph is defined inline in the scene file.
Shader-to-shader chaining works the same way as for nodes you write yourself:
ScaleNode.inputs:Inputconnects directly toAddNode.outputs:Result.Value-inputs (
scaleX,scaleY) also behave the same way. Scene files can override defaults per shader instance.orderedVarslists only the input (LdrColor) and final output (Downscaled). The intermediate brightened result from AddNode is internal to the chain.
A built-in is used as it is. You get it by name, with no way to change what it does beyond the value-inputs it declares. The moment you need something it does not do, you are writing a node, and the two cannot be mixed within one shader. The built-ins are listed in Built-In Node Catalogue.
Verify It Worked#
Compare both the dimensions and the values against the input. Add and Scale together double
brightness with saturating arithmetic and halve each dimension, so the output is exactly half the
input’s width and height, and a pixel at value v comes back at min(2v, 255). A value that
did not double means Add never ran; a size that did not halve means Scale never ran. Both
operations are exact in integers, so the output of the
built-in nodes example rebuilt on the host from
its input matches with no tolerance.
When It Goes Wrong#
The node is not found: check the
info:idagainst Built-In Node Catalogue. A misspelling is the usual cause. An ID outside that table may belong to another renderer component; it is not a supported authoring surface.The node rejects its input: these operate on 2D textures only, and not on integer formats.