Overriding nested references issue / behaviour

Hi,

I ran into an issue in overriding references in USD.
I made a small example of this using the “Parking Lot” language to make it understandable.

I have a car with wheels in a parking lot. The car is made out of references to wheels + translation and the car is a references to the car.usd file. Then i have a ParkingLotOverrides which changes the wheels to a different wheel references for that car.

When I do this, the transform overrides of the wheels (define in car.usd) gets lost / overridden by the reference to the wheel (which sets translation to zero).

I checked how this works in a simpler setup where there is no nesting of references and the transform is taken from the ParkingLot layer in this case. Working as I would expect it. So there seems to be a difference in behaviour for how nested vs not nested references and overrides for it are resolved.

I put both samples of the working and incorrect setup into the zip.

Is this a bug or is this intentional behaviour?
If this is considered a bug, I am happy to make a PR with a fix for.

overriding-nested-references.zip (9.9 KB)

1 Like

Hi @Joachim_Ante , I haven’t had a chance to look at your example yet, but I think your expectations about “overriding” references may be misaligned with the recursive, “encapsulated” nature of USD referencing. Can you have a read of this FAQ entry, and see if it answers your question?

Thanks!

Thanks, It looks like exactly what is described here:

The behavior is indeed unintuitive, and it sounds like it is something that will not be fixed though based on the FAQ.

So in practice that means going down that path the only option is to re-introduce the overrides that “got lost“ again in the same layer that overrides it. Which has it’s own can of worms.

I think the bigger question is then, is there a better pattern / functionality in USD that I am missing? Taking the parking lot example, where we have a car and inside it a wheel. And now we want to replace in a wheel on one of the cars with a different type of wheel geometry.

A variant set would be one option. You define your car asset with all of the wheel variants it could use. The variants can include references to various wheel assets. In your parking lot, you can then swap variants to change out your wheels.

While it seems variants would specifically support that, the fact that you have to create the set of variants upfront instead of being able to “compose them from a higher level composition scene” allowing to create completely new variations and combinations makes them not really a viable option. Or maybe I am missing how to use variations in a way that allows for that?

Basically i want parking lot to be the only thing that knows what my alternative wheel actually is.

There are a lot of ways to skin a cat with USD and it’s often going to come down to your requirements. Some options are more robust solutions in a pipeline environment. What I described is the most idiomatic, but seeing as how you want to introduce the alternative wheel in just that parking lot context, you’ll likely want to go another route.

To answer your last question, you CAN introduce new variants to a variant set later downstream. Attached is an example where I have a variant set with a “default” variant for the default wheel setup and later introduce at “sphere” variant for the alternate. Don’t expect anything fancy looking in the viewport here and I didn’t add any xform values, but overrides should be preserved along the way as you expected with this setup.

You might also solve this without using additional composition arcs. In your parking lot you can override the wheel to deactivate prims or completely override the points and topology of your meshes to change the look.

Given that the reference pattern you tried isn’t an option, I’d recommend trying a few different setups that adhere to your requirements and reach out here if you have any additional questions or would like someone to review your design for any possible pitfalls.
parking_lot.zip (1.2 KB)

I’d second @mati-nvidia 's sug of dynamically adding variants at higher-referencing levels. I haven’t truied this, but you may even be able to add the new variant inside a referenced Wheel_variant_addition.usd (along with the variantSet selection being set to the new variant), so the workflow, at the shot-level, is still “add a reference”. LIke I said, that may not work out, but adding the variant to the variantSet directly (and the variant itself can defnitely just contain a reference to the new wheel variation). Really the only thing you need to set up in the foundational asset is that the wheel is defined inside a variant.

parkinglot.zip (7.9 KB)

Thank you for the help so far. Really appreciate it.

So I setup a sample similar to what Matias described.
Unfortunately the same issue persists. References wipe out the attributes previously introduced. car.usda has translation, and if i change the reference to a different wheel using a variant set in parkinglot.usda. Then all attributes defined in car.usda for the wheel disappear.

Notice in my example, if i set the translation again for the wheel in the parking lot, then everything works.

Do you have any other ideas for how to express this in USD? Or did I set up something incorrectly?

In your example, the Wheel_FL prim inside wheel2.usda has its own authored values for translate, rotateXYZ, and scale.

When you bring that prim into parkinglot.usda through your new variant, the transform values from wheel2.usda end up stronger than the ones defined in car.usda. If you remove those transform opinions from wheel2.usda, the transforms from car.usda should take effect as you expect.

Thanks Ant. Great find.

Very interesting, so if i remove the translation from the wheels. Then both using references directly as well as using the variant set approach works as expected. (Wheel ends up in the right place defined by car.usda)

Is this a common practice for creating reusable assets? To very intentionally not have any attributes in the root prim of reusable asset (wheel in this particular example)

Knowing all this, there is a certain logic to the override behaviour but it is very confusing.

Even though references now seem to work, I’d still caution against using “raw” references for this workflow, because all of the references will always still be contributing. THis could cause problems if, e.g., the wheel referenced in the base asset has not just a tire prim and rim and hubcap prims, but also a bunch of individually modeled bolt prims. Now if, at shot level, you decide to “replace” the wheel with a simpler one that just has a tire, rim, and hubcap, the bolts from the asset-level reference will still be present in your Stage!

If, however, both references are added inside different variants of the same variantSet, then the replacement will be complete and clean.

Ant might have a broader perspective than I, but generally, we don’t do much “dynamic swapping”, instead making sure our assets are published with the needed variations in a modelingVariant variantSet. I can say that generally, we consider the root prim of an asset to be its “model interface”, so it does contain a bunch of metadata and attributes (e.g. some constant primvars to be inherited down into the asset) that provide information about the asset, setups like texture cards, etc. We do try to zero out the transform at the root such that the asset is in a good default position at the origin when referenced, but I don’t recall whether that translates to enforcing that no transform is authored.

Like Spiff mentioned, building the available wheels (as variants) into the car would be the most common approach. Mostly for tracking reasons, so that to know (and view) the available wheels for a car it’s not necessary to know about all the available parking lots.

That said, building aspects of a model that may need to be removed down the road into a variant definitely has value. I’ve occasionally seen pipelines author tons of prim deactivates in the hopes of achieving the same (while not fully understanding the model and thus missing things). A formal variant set built into the model to support the removal requirements would have been more robust and better communicated the overall intent.

The override behavior is documented here btw. There’s other good explanations out there if you search for LIVERPS (formally LIVRPS).

Hi, Tech Artist from Joachim’s team here.

I’m not sure variants are the best fit for game development in this context — or maybe I’m just not fully aware of their flexibility yet. I’m still learning the full possibilities in USD, and there certainly seem to be many ways to skin a cat. :slightly_smiling_face:
So I’ll outline some of my use cases and concerns:

For the scenario discussed, I’d prefer a more type-strong solution. For example, sockets like the wheels on a car should be linked to compatible parts through a type/tag system, rather than predefined variant sets. I think it’s more elegant if both the runtime (what you might call the “shot context” in games) and the authoring environment share the same dependency-resolution logic. That feels necessary for live-service games, where many unique content states can coexist across different SKUs with different ownership rights.

In film USD, the shot context selects variants and payloads.
In games, the equivalent is the “current game state” (DLC entitlement, region, platform, player progression, etc.).

Ideally, we should be able to preview these states locally in the editor.
For example: set a config like “DLC1+2 enabled, base game, region EU” → the editor resolves exactly what the runtime would: which assets load, which wheels are allowed, which overrides apply, and so on.

My intuition is that this shouldn’t rely on managing large variant graphs for every possible combination. USD variants often require variantSets like modelVariant = wheelA | wheelB | wheelC, skinVariant = ... etc. In a live-service game with near-infinite combinatorics, that seems difficult to scale and maintain.

Instead, I’d like authors to be able to contribute a new wheel with the correct tag/type, and have the system automatically discover it as compatible with the socket — without anyone needing to go back and register it in a central authoritative list. This also feels important for asset libraries shared across multiple projects, proceduralism and potential user-generated content.

I’m not sure if it’ll fit your needs better, but it might be worth taking a look at dynamic file formats which would offer some of the flexibility you’re looking for. A custom file format would be free to consult some external system in order to obtain a list of all known/discovered wheel assets for example, and only add wheel variants for those that match certain criteria at runtime (tags, entitlements etc).