I’m trying to understand how I can reuse NodeGraphs while still being able to pass material properties down to them from multiple materials that may use the same NodeGraph.
This is my attempt at finding an alternative to the primvar route (currently not working, as outlined here: Getting custom primvars to work inside materials/shaders - #4 by herbst ).
I believe this is the authorative documentation on the topic: UsdShade : USD Shading Schema
Now, I see two paths to making this work:
- I would need a way to override the nodegraph inputs from materials using that nodegraph. I would prefer that, but I haven’t found a mechanism to do so. Maybe that’s just primvars?
- I could instance the entire nodegraph into the material, thus providing me with a way to “override” the inputs. (I’m still not entirely sure about the terminology differences between “prepend references”, “references”, and “over”, so please bear with me if my terms are somewhat incorrect).
Here’s my attempt at (2) – good thing is, it works in usdview and in Reality Composer Pro. Now to the question: is this reasonable, or overly complicated? Is there an easier way? Ultimately I would want to bring the properties, ColorIn in this case, up to the geometry prim.
Providing property overrides to instanced materials
#usda 1.0
(
defaultPrim = "Root"
metersPerUnit = 1
upAxis = "Y"
)
def Xform "Root"
{
def Sphere "Sphere" (
active = true
prepend apiSchemas = ["MaterialBindingAPI"]
)
{
rel material:binding = </Root/Material>
double radius = 0.08
}
def Sphere "Sphere2" (
active = true
prepend apiSchemas = ["MaterialBindingAPI"]
)
{
rel material:binding = </Root/Material2>
double radius = 0.10
float3 xformOp:translate = (0.3, 0, 0)
uniform token[] xformOpOrder = ["xformOp:translate"]
}
def Material "Material"
{
color3f inputs:MyColor = (0.94591796, 0.60906976, 0.08387404)
prepend token outputs:mtlx:surface.connect = <PreviewSurface.outputs:out>
token outputs:realitykit:vertex
float2 ui:nodegraph:realitykit:subgraphOutputs:pos = (568.75, 102.25)
def Shader "PreviewSurface"
{
uniform token info:id = "ND_UsdPreviewSurface_surfaceshader"
color3f inputs:diffuseColor.connect = <ColorGraphInstance.outputs:HSVAdjust_out>
float inputs:metallic = 1
float inputs:roughness = 0
token outputs:out
# Instance of the shared node graph
def NodeGraph "ColorGraphInstance" (
instanceable = true
references = </Root/nodegraph>
)
{
color3f inputs:ColorIn = (0, 1, 0)
}
}
}
def Material "Material2"
{
color3f inputs:MyColor = (0.94591796, 0.60906976, 0.08387404)
prepend token outputs:mtlx:surface.connect = <PreviewSurface.outputs:out>
def Shader "PreviewSurface"
{
uniform token info:id = "ND_UsdPreviewSurface_surfaceshader"
color3f inputs:diffuseColor.connect = <ColorGraphInstance.outputs:HSVAdjust_out>
float inputs:metallic = 0
float inputs:roughness = 0.5
token outputs:out
# Instance of the shared node graph
def NodeGraph "ColorGraphInstance" (
instanceable = true
references = </Root/nodegraph>
)
{
color3f inputs:ColorIn = (1, 0, 0)
}
}
}
# Shared Node Graph
def NodeGraph "nodegraph"
{
color3f inputs:ColorIn
color3f outputs:HSVAdjust_out.connect = <HSV_Adjust.outputs:out>
def Shader "HSV_Adjust"
{
uniform token info:id = "ND_hsvadjust_color3"
float3 inputs:amount = (0, 1, 1)
color3f inputs:in.connect = <../.inputs:ColorIn>
color3f outputs:out
}
}
}
And here’s my attempt at providing the “override values” at the geometry prim level, adding yet another layer of instancing. This still works! But doesn’t feel really clean, so I’d appreciate any insights and feedback. Thanks!
Providing per-prim properties to instanced materials using an instanced nodegraph
#usda 1.0
(
defaultPrim = "Root"
metersPerUnit = 1
upAxis = "Y"
)
def Xform "Root"
{
def Sphere "Sphere" (
active = true
prepend apiSchemas = ["MaterialBindingAPI"]
)
{
rel material:binding = <Material>
double radius = 0.08
# Instance of the shared Material
def Material "Material" (
instanceable = true
references = </Root/Material>
) {
color3f inputs:MyColor = (0, 1, 0)
}
}
def Sphere "Sphere2" (
active = true
prepend apiSchemas = ["MaterialBindingAPI"]
)
{
rel material:binding = <Material>
double radius = 0.10
float3 xformOp:translate = (0.3, 0, 0)
uniform token[] xformOpOrder = ["xformOp:translate"]
# Instance of the shared Material2
def Material "Material" (
instanceable = true
references = </Root/Material2>
) {
color3f inputs:MyColor = (0, 0, 1)
}
}
def Sphere "Sphere3" (
active = true
prepend apiSchemas = ["MaterialBindingAPI"]
)
{
rel material:binding = <Material>
double radius = 0.07
float3 xformOp:translate = (-0.3, 0, 0)
uniform token[] xformOpOrder = ["xformOp:translate"]
# Instance of the shared Material2
def Material "Material" (
instanceable = true
references = </Root/Material2>
) {
color3f inputs:MyColor = (1, 0, 0)
}
}
def Material "Material"
{
color3f inputs:MyColor = (0, 0, 1)
prepend token outputs:mtlx:surface.connect = <PreviewSurface.outputs:out>
token outputs:realitykit:vertex
float2 ui:nodegraph:realitykit:subgraphOutputs:pos = (568.75, 102.25)
def Shader "PreviewSurface"
{
uniform token info:id = "ND_UsdPreviewSurface_surfaceshader"
color3f inputs:diffuseColor.connect = <ColorGraphInstance.outputs:HSVAdjust_out>
float inputs:metallic = 1
float inputs:roughness = 0
token outputs:out
# Instance of the shared node graph
def NodeGraph "ColorGraphInstance" (
instanceable = true
references = </Root/nodegraph>
)
{
color3f inputs:ColorIn = (0, 1, 0)
color3f inputs:ColorIn.connect = <../../.inputs:MyColor>
}
}
}
def Material "Material2"
{
color3f inputs:MyColor = (0.94591796, 0.60906976, 0.08387404)
prepend token outputs:mtlx:surface.connect = <PreviewSurface.outputs:out>
def Shader "PreviewSurface"
{
uniform token info:id = "ND_UsdPreviewSurface_surfaceshader"
color3f inputs:diffuseColor.connect = <ColorGraphInstance.outputs:HSVAdjust_out>
float inputs:metallic = 0
float inputs:roughness = 0.5
token outputs:out
# Instance of the shared node graph
def NodeGraph "ColorGraphInstance" (
instanceable = true
references = </Root/nodegraph>
)
{
color3f inputs:ColorIn = (1, 0, 0)
color3f inputs:ColorIn.connect = <../../.inputs:MyColor>
}
}
}
# Shared Node Graph
def NodeGraph "nodegraph"
{
color3f inputs:ColorIn
color3f outputs:HSVAdjust_out.connect = <HSV_Adjust.outputs:out>
def Shader "HSV_Adjust"
{
uniform token info:id = "ND_hsvadjust_color3"
float3 inputs:amount = (0, 1, 1)
color3f inputs:in.connect = <../.inputs:ColorIn>
color3f outputs:out
}
}
}