I figured this out with a little bit of reading the C++ source code. In short, it’s the case that the second call to Usd.VariantSet.GetVariantEditTarget
after having set the edit target on the stage will now generate a “nested” edit target with the variant set path mapping.
Let’s give this a go. Here’s a reproducable stage, single prim with some variants:
from pxr import Usd
# Create a stage with a root xform
stage = Usd.Stage.CreateInMemory()
prim = stage.DefinePrim("/root", "Xform")
# Add variant set
variant_sets = prim.GetVariantSets()
variant_set = variant_sets.AddVariantSet("model")
# Add some variants
variant_set.AddVariant("main")
variant_set.AddVariant("damaged")
variant_set.AddVariant("ice")
# Set the variant selection
variant_set.SetVariantSelection("main")
Now, as we have a selected variant for the variant set we can define the edit target:
edit_target = variant_set.GetVariantEditTarget()
stage.SetEditTarget(edit_target)
Now let’s debug that edit target:
print(edit_target.layer())
# as expected, will be the stage's root layer
mapping = edit_target.GetMapFunction()
print(mapping.sourceToTargetMap)
# {Sdf.Path('/'): Sdf.Path('/'), Sdf.Path('/root{model=main}'): Sdf.Path('/root')}
As we can see it understands the variant set’s mapping in the edit target.
Now however if I would call the variant_set.GetVariantEditTarget()
again I’m appending that variant selection for the path mapping:
edit_target = variant_set.GetVariantEditTarget()
mapping = edit_target.GetMapFunction()
print(mapping.sourceToTargetMap)
# {Sdf.Path('/'): Sdf.Path('/'), Sdf.Path('/root{model=main}{model=main}'): Sdf.Path('/root')}
Which might be a bit unexpected for this particular case but I suppose it so that one could edit e.g. another variant set’s variant within the first variant. So that you could add an opinion that if in the {model=main}
variant then apply this opinion to e.g. {look=main}
?
Either way, the difference in path mapping explains why the edit targets were indeed not equal.
So for my initial use case - what did I want? No matter what I want to set the target to the root layer, and to (non-nested) variant selection. Less flexible, more limited in scope but easier to grasp - and best of all, was my intended use case.
How?
Well, we can use Usd.EditTarget.ForLocalDirectVariant
.
layer = stage.GetRootLayer()
path = prim.GetPath().AppendVariantSelection("model", "main")
edit_target = Usd.EditTarget.ForLocalDirectVariant(layer, path)
As we can see - running that again was my intended edit target and what I expected to be “equal” in the comparison:
edit_target = Usd.EditTarget.ForLocalDirectVariant(layer, path)
mapping = edit_target.GetMapFunction()
print(mapping.sourceToTargetMap)
# {Sdf.Path('/'): Sdf.Path('/'), Sdf.Path('/root{model=main}'): Sdf.Path('/root')}
stage.SetEditTarget(edit_target)
edit_target = Usd.EditTarget.ForLocalDirectVariant(layer, path)
mapping = edit_target.GetMapFunction()
print(mapping.sourceToTargetMap)
# {Sdf.Path('/'): Sdf.Path('/'), Sdf.Path('/root{model=main}'): Sdf.Path('/root')}
And the comparison is equal:
stage.GetEditTarget() == Usd.EditTarget.ForLocalDirectVariant(layer, path)
# True