"Save As" functionality on a live UsdStage?

Hi,

I’m wondering if it’d be possible to save a stage’s root layer as a different file, while taking care of preserving all variants, references, etc. and remapping potential relative paths so that if the new file is in a different folder, the final composed stage stays identical.

I couldn’t find any existing utilities in the source code, and the existing Save/Export functionalities at the UsdStage and SdfLayer level don’t support this (at least from what I could see?) so I’m probably going to try to write such utility myself, but I wanted to know if anyone has any experience with this, before I do.

I was thinking of approaching this like so:

  1. Use SdfLayer::Export to create a copy of the root layer at the new location
  2. Open that exported layer and remap all relative paths
  3. Replace the stage’s root layer by this one?

I’m not even sure if step 3. is technically possible though, so I’m kinda stuck.

Any idea/suggestion?

Hi Damien,
Did you look at flattenLayerStack() ?
It collapses the layers into a single file but keeps all the other arcs intact. The result is an identical stage with fewer files to open, but you lose the ability to mute separate layers.
F

Hi,

Thanks for the suggestion, but I need to keep the structure of the root layer (and the runtime stage) exactly the same, which makes all export and flatten utilities not usable :confused:

It feels like it should be possible to just update the path and format inside the layer, and then call the stage’s Save() method, but Usd’s API don’t expose enough for that to be feasible (to my knowledge) thus my question.

I’m afraid the only solution right now for me will be to create the new layer, transfer content from the current one to the new one using SdfCopySpecs or something like that, then close the stage and reopen the new on.. but that’s kinda bad (takes time, triggers full Hydra resync, causes lots of UI headaches, etc.)

Hi @dcourtois - good to hear from you again! I think there is one narrow path that might work for you (i.e. address #3), here…

You’re correct that there’s no existing utility for doing the exact (and only) transformation you’re trying to do, though SdfLayer::UpdateCompositionAssetDependency() does one half of what you need.

I haven’t decided whether this constitutes an abuse of a mechanism, but the Ar/Sdf combo allows for dynamically changing the location of any loaded layer - we use it when, in Presto, a user decides to edit a source-controlled layer, in which case we check it out of perforce and put a copy in the user’s local space (at a file granularity that ensures we don’t trip over missing anchored references in the new location, I believe).

The way it works is that you must update the stage’s ArResolverContext so that the layer’s existing identifier will resolve to the new location, and once the context has been updated, you’d call rootLayer.Reload(True) , which should result in granular change processing that would recognize nothing has actually changed in the scene. I’m not sure this particular use has ever been tested, so take these statements as “in theory” :slight_smile:

One problematic thing, here, if you’re trying to do this for a generic tool, is that updating the resolverContext requires knowing the format of the Context object, which you may recall is basically held as an opaque object that is specific to the resolver that resolves the path. So your application logic must be able to reason about all the installed resolvers in the session. Providing a means to “update an asset’s location” in a resolver-agnostic manner would be an architectural change that would put a new responsibility on resolver-writers, and would need to be carefully considered.