Debugging variant selection composition

Hello,

I’m trying to debug why the variant selection of an asset in one of our production scenes isn’t composing quite as we would expect. What we’re seeing is that when using AddVariant on one of our variant sets, another variant set is actually switching it’s variant selection. I suspect this has to do with the fact that our variant sets are nested and we’re hitting a strange subtlety with composition, but I can’t figure out how it’s happening. I wish I could share a scene, but I haven’t been able to reproduce with a simpler non-production case yet. For context, we have a variant set foo (which has a few variants A, B, C) which is currently set to variant B. Inside variant foo, we have a nested variant set bar which has a few variants (X, Y). We make a VariantEditContext for foo, and add variant Z to variant set bar. When this happens foo somehow switches to have A selected. (Note: that I’ve simplified this a bit since foo is actually nested within another variant set above it).

What I’ve tried so far is looping over the prim specs in the PrimStack and finding out which ones are setting a variant selection for variant set foo. What’s odd is the strongest spec is setting the variant selection for variant set foo to B, so shouldn’t that mean that B should be the composed selection?
The other thing I’ve tried is to examine the variant selections in the PcpPrimIndex. What I get seems a bit strange:

>> primIndex = prim.GetPrimIndex()
>> primIndex.ComposeAuthoredVariantSelections()
{}
>> primIndex.GetSelectionAppliedForVariantSet('foo')
'A'
>> expandedPrimIndex = prim.ComputeExpandedPrimIndex()
>> expandedPrimIndex.ComposeAuthoredVariantSelections()
{'foo': 'B'
 'bar': 'Y'}
>> expandedPrimIndex.GetSelectionAppliedForVariantSet('foo')
'A'

>> prim.GetVariantSet('foo').GetVariantNames()
['A', 'B']

What could I be missing here? I feel like potentially the strongest spec with the B variant selection isn’t being applied. Is there something else I can try to debug the variant selection composition in more detail to figure out how the A is getting applied?

Thanks,
Cameron

Hi @cbillingham ,
If you can get us an example that violates your expectations we can get you a hopefully somewhat more satisfying explanation, but here’s what I can tell you for now…

“Discovery of variant selections during prim indexing” is what I’d call an opaque corner of USD’s composition algorithm. Here’s why: when Pcp is done computing the PrimIndex for any given prim, you have access to a lovely, fully inspectable node-graph of all the composition arcs that were followed, as well as the linearized (in strength order) “unrolling” of that graph into a sequence of “sites” to consult for opinions. That allows us to provide pretty comprehensive debugging tools for figuring out how metadata and property data gets “value resolved”, including Prim/PropertyStacks, the “Composition Tab” in usdview, and the ability to dump a dot graph of the node graph.

But variant selections must be evaluated before we can fully compute the PrimIndex… or rather, interwoven with computing it. Which arcs, and the order in which we traverse them, to find the selection for each variantSet is not always the same as the order of sites in the final PrimIndex, and nested variants (and I think sequential variantSets, as well) are the canonical example of where the ordering may differ… which variantSet do you “resolve” first, because which selection you make for that one can affect the arcs that get consulted to evaluate subsequent variant selections.

That’s the depth of my understanding, and unfortunately I don’t have any advice to offer at this point as to what to do about it, beyond making your variant selections “above” the definitions of the variantSets themselves in the composition graph, realizing that that may run entirely against your asset/pipeline needs.

I found something similar, UsdVariantSets::GetAllVariantSelections (which uses the prim index) can give a different result than getting all variant selections… So maybe that method should be renamed, to make it clearer that a difference exists?

I have a huge scene that reproduces this, but it is under NDA. It still happens when I remove all geometry from that scene, so maybe I am allowed to give it as such. It also shows many performance bottlenecks with variants, references in variants, and nested variants (the latter is a known issue on github)