While developing a pipeline for version management of lookdev within a shot we ran into a peculiar behaviour where a variant selection was being made in a referenced layer, Usd reports the correct variant selection in the composed stage, but the values being set by the variant are not coming through.
I’ve managed to reproduce the problem with the following simplified layer (this is using usd-23.08):
#usda 1.0
def "Element" (
add references = [
</LookSelectionLayer/Element>,
</LookdevLayer/main>,
]
)
{
}
def "LookSelectionLayer"
{
over "Element" (
variants = {
string look = "variantA"
}
)
{
}
}
def "LookdevLayer"
{
def "main" (
prepend references = </LookdevLayer/__BASE_LOOK__>
prepend variantSets = "look"
)
{
variantSet "look" = {
"variantA"
{
def "LookdevInterface"
{
string foo = "variantA value"
}
}
}
}
def "__BASE_LOOK__"
{
def Scope "mtl"
{
def Material "MyMaterial" (
prepend inherits = </LookdevLayer/__BASE_LOOK__/LookdevInterface>
)
{
}
}
def "LookdevInterface"
{
string foo = "base value"
}
}
}
If you query the selected look variant in the composed stage for /Element
it reports “variantA” like I expect:
>>> print(stage.GetPrimAtPath("/Element").GetVariantSet("look").GetVariantSelection())
variantA
However, when you get the value of /Element/mtl/MyMaterial.foo
it returns “base value” where I’m expecting it to be “variantA value”:
>>> print(stage.GetObjectAtPath("/Element/mtl/MyMaterial.foo").Get())
base value
I’ve looked at the PrimIndex dot graph and the variant opinion is listed as #6 and the base look’s LookdevInterface opinion is listed as #9 so the variant opinion should be winning. However if you inspect the property stack for the attr, it only contains a single entry from the base look’s LookdevInterface:
>>> stage.GetObjectAtPath("/Element/mtl/MyMaterial.foo").GetPropertyStack()
[Sdf.Find(..., '/LookdevLayer/__BASE_LOOK__/LookdevInterface.foo')]
So somehow the variant’s AttributeSpec is getting lost.
Doing any of the following will give the expected “variantA value” value:
- select
look="variantA"
directly on/Element
rather than via a reference
>>> stage.GetPrimAtPath("/Element").GetVariantSet("look").SetVariantSelection("variantA")
True
>>> print(stage.GetObjectAtPath("/Element/mtl/MyMaterial.foo").Get())
variantA value
- remove the LookdevInterface indirection and just set
foo
directly on MyMaterial - remove the intermediate “mtl” prim from the layer (this one was quite surprising!)
Am I misunderstanding something about value resolution or is this a bug?