Proposal to revise use of layer metadata in USD

Hi all,
I have a “meta proposal” to update USD object modeling guidelines and seed several other, more specific proposals to follow. It addresses problems people have encountered with how USD encodes important scene “metrics” information (e.g. metersPerUnit, upAxis, …) by proposing a change from layer metadata to prim applied schemas, with rationale.

Here is the PR - feedback preferred in the PR, but OK here, too - thanks!

Thanks Spiff. One question I have is your take on the impact on “internal” references and inherits/specializes. I think it likely has the same risks as sub root references and are commonly used as source scene description with instancing.

Hmmm… I’m not sure I see the same degree of risk for those, since you are (I think?) working “on the same stage”. Sub-root (external, most especially) references are unique (well, for payloads also) in that you’re “piercing the integrity” of a remote asset whose author couldn’t really plan for this kind of use. With internal references and even sub-root inherits, the stuff you are targeting is all on the same stage, so you at least can immediately see what you might be missing. But you’re right you may still wind up missing stuff!

Looking at the proposal strictly from the units perspective, I have to say this might not be the best move. With metadata information, the validation process—specifically, checking for divergent units present on a stage—was very efficient. You could look at all composed layers, check the metadata units, and quickly determine whether there were mismatched units in play. The same applied to adding new references; you could quickly compare a couple of values and be done. This is very important for many workflows that construct stages on the fly, as validation needs to run during the authoring of the stage.
Now, with the proposed change, one would have to traverse the entire stage to determine if there are divergent units. That is very expensive, and I can’t run this at any point during authoring. Note that having validation on a stage does not really help; this has to be validated during authoring.
Additionally, our customers value that we are able to resolve divergent units. While this could still be done with the proposal, the complexity would increase significantly, as different units could appear anywhere in the stage, whereas previously this could be handled with layer-vs-layer information.
Could we, for example, allow this only on the root prims? That could help, I think…

In a tightly structured, well-controlled pipeline, I agree with you that the current, layer-based encoding is fast and facile for detecting and correcting mismatches while adding references during authoring. The big problem, though, is that the result you get is not easily introspectable, nor validatable, and under asset/stage flattening, becomes hopeless. Which, under the small or ideal pipeline, may not be a problem. But in conditions where:

  • You don’t control all the DCC’s that are contributing layers, and therefore can’t guarantee they’ve done everything properly, or
  • The contents of previously referenced assets (which could be individual layers in a layerStack, or an entire asset) change out from underneath you due to a republish

… then the preservation of information and the ease of introspection that the new encoding offers greatly facilitates debugging, validation, and post-correction.

I’d also like to question a few statements?

Even today, you can only assume you don’t need to traverse a stage if you 100% trust the asset you are referencing. And the traversing you’d need to do with the new proposal is far easier than with the old, because the information you need to check is already cached for you at the stage level, and easily accessible, vs. needing to construct a UsdPrimCompositionQuery for every prim (not cheap at all).

I’d like to challenge that until proven otherwise? Especially if you continue making the assumption you are making currently, that each asset you reference is already internally self-consistent. Under those assumptions, then I think (but please correct me if I’m wrong here) your work changes from examining the contents of of the layer metadata of the layer you are adding a reference to :

  • Adding the reference and then examining the UsdTypeInfo of the resulting composed prim to see if there is a UsdLinearMetricsAPI applied
  • For a sub-root reference if no metrics API is applied, then opening the targetted reference masked to the referenced prim (with no child prims) so that you can discover the coordinate system in which the prim is defined by examining its ancestor prims

Unless there is a compelling reason to do the analysis prior to adding the reference, then in the “root reference” case in an authoring workflow, I don’t see any significant added expense. The sub-root reference case is substantially more expensive, but does not scale with the size of the scene, or even with the amount of data/scene being referenced… only with depth of the hierarchy you’re referencing into. I would hazard that with modest number of cores, even that check would be in the hundreds of milliseconds max, commonly. Are there authoring workflows that can’t afford that at reference-adding time?

Just to note again, I believe there should be no difference in how much of the stage you need to process, in either case. But perhaps I don’t understand how you are resolving differing units?

Thanks for the feedback, @aborovicka - keep it coming!

Thanks for the answer @spiff, I realized how late to the party I have arrived, sorry about that.

You don’t control all the DCC’s that are contributing layers, and therefore can’t guarantee they’ve done everything properly

Yes, this is very true, but how does the proposal help with that? That API can be omitted like the metadata part, am I missing something?

Even today, you can only assume you don’t need to traverse a stage if you 100% trust the asset you are referencing. 
And the traversing you’d need to do with the new proposal is far easier than with the old,
because the information you need to check is already cached for you at the stage level, 
and easily accessible, vs. needing to construct a UsdPrimCompositionQuery for every prim (not cheap at all).

This is true, however the sort of again the advantage is that with the current layer metadata information I can:

  1. Have validation that each layer does have the metadata part, easy to check, easy to require and document. There is one fixed place where this information is.
  2. The UsdPrimCompositionQuery is expensive yes, however I dont require it to run in most cases because if units match, I dont have to construct the queries. Because as a pre-step I can easily get all participant layers in the stage and just check the units, no need to run the expensive queries if I dont have to. However the new approach I have to always traverse the whole stage, there is no early exit option for me.
I’d like to challenge that until proven otherwise? Especially if you continue making the assumption you are making currently,
that each asset you reference is already internally self-consistent. Under those assumptions, then I think 
(but please correct me if I’m wrong here) your work changes from examining the contents of of the layer metadata of the layer you are adding a reference to :

Adding the reference and then examining the UsdTypeInfo of the resulting composed prim to see if there is a UsdLinearMetricsAPI applied
For a sub-root reference if no metrics API is applied, then opening the targetted reference masked to the referenced prim (with no child prims) so that you can discover the coordinate system in which the prim is defined by examining its ancestor prims
Unless there is a compelling reason to do the analysis prior to adding the reference, then in the “root reference” case in an authoring workflow, I don’t see any significant added expense. The sub-root reference case is substantially more expensive, but does not scale with the size of the scene, or even with the amount of data/scene being referenced… only with depth of the hierarchy you’re referencing into. I would hazard that with modest number of cores, even that check would be in the hundreds of milliseconds max, commonly. Are there authoring workflows that can’t afford that at reference-adding time?

The traversal cost is something that is bothering me yes, the traversal itself is usually fast however querying applied API schema is not from what I have seen so far. Maybe I do something wrong, but on a larger hierarchy this is expensive and can add seconds easily.

Just to note again, I believe there should be no difference in how much of the stage you need to process, in either case. But perhaps I don’t understand how you are resolving differing units?

I think there is a huge difference, if I get a stage and have to check if there are divergent units on a given stage.
Let me try to write up what I do for units now and make an exercise how would that change.

Lets assume an easier case where there is already existing stage that has all consistent units and we try to add a reference to a new layer.
Currently this is what I do (very simplified):

  1. I get stage root layer metadata, I get the reference layer metadata, if the units match done
  2. If units dont match we run the metrics assembler to resolve the divergences
  3. I do traverse the hierarchy and run the UsdPrimCompositionQuery to find the two divergent layers on that prim
  4. Based on the units difference corrections are applied

Now with this new pattern:

  1. I need to traverse the added layer to find the applied metrics API if there is anywhere some divergent API, this means I can never early exist, always the whole layer has to be traversed.
  2. If units dont match run the metrics assembler
  3. So instead of running the composition query I could indeed get the API applied and compare against the parent applied API. This sounds ok I guess if we can trust the API values as those can be authored and mutated by various layer, but I guess thats fine.

Now the benefit here would be, that I can mutate the metrics attributes on the right layers to indicate that the metrics now matches across the whole stage, thats interesting.

So I guess my main issue would remain, that if we allow this metrics API to be on non-root prims, the validation part becomes non-trivial and possibly expensive.

Ales

Thanks so much for the added info, @aborovicka - that “quick check for any differences in units anywhere on the stage” is a concern I was missing. So, there are several aspects of the new proposal that haven’t been worked out yet (like if we require every layer to declare its units/upAxis as we do today with the layer metadata), but we do expect to require that (composed) root prims do declare these things via the API schema. So under the same assumption that the layers you are referencing are already self-consistent, you should not need to traverse the referenced layer or its composed stage.

Whether we would require that every root prim on every layer declare units is an unanswered question, and whether different root prims in the same layer can declare different units/upAxis is another open question.

1 Like