Maya native usd plugin

any plans to add usd create option in maya, Being able to write out simple usd binary files using the mayaUSDExport could be very handy.

It’s definitely something that’ll come and get added. I’d be happy to implement a draft if I have some time.

To understand your goals/needs:

  1. What version of Maya are you using?
  2. What export flags are important to you? Like how are you using the export feature currently?
  3. Are you also loading them in maya, if so - how are you using it currently?
  4. Any remarks or special things you might need this to support?

At the moment roughly. Exporting manually usd binaries from maya2024 for then to use the tray publisher to get them into ayon.
Then using the pixar api or maya(bifrost or usd layer editor) to collect usd’s into assembly.usda file. defining purpose attributes and reference paths(payload,reference). Again using the tray publisher to get them into ayon db
here is example for animation export, pay attention to the -parentScope flag:

mayaUSDExport -v -shadingMode none -convertMaterialsTo none -eulerFilter on -exportUVs on  -stripNamespaces on -exportComponentTags on -defaultMeshScheme catmullClark -worldspace on -exportInstances on -exportVisibility on -mergeTransformAndShape on -parentScope cat_main_model -staticSingleSample off -frameRange 1001 1250 -frameStride 1 -frameSample 0.0 -exportRoots "cat_main_01:cat_main_modelRender_01:render" -file "/path/seq001_0020_cat_main_01_v001.usd";

and here the camera:

mayaUSDExport -v -shadingMode none -convertMaterialsTo none -eulerFilter on -stripNamespaces on -exportComponentTags on -worldspace on -exportVisibility on -mergeTransformAndShape on -staticSingleSample off -frameRange 1000 1251 -frameStride 1 -frameSample 0.0 -exportRoots "camera_GRP" -file "/job/pipetest/pet3/film/ep101/seq001/seq001_0020/publish/camera/cameraRender/v006/seq001_0020_cameraRender_v006.usd";

For a asset or subAsset the api is then writing a usda publish in this format:

#usda 1.0
(
    defaultPrim = "walls_main_model"
)

def Scope "walls_main_model" (
    kind = "group"
)
{
    def Scope "render" (
        kind = "component"
        prepend payload = @/somepath/walls/walls_main/publish/model/modelRender/v002/walls_main_modelRender_v002.usd@</render>
    )
    {
        uniform token purpose = "render"
    }

    def Scope "proxy" (
        kind = "component"
        prepend references = @/somepath/walls/walls_main/publish/model/modelProxy/v002/walls_main_modelProxy_v002.usd@</proxy>
    )
    {
        uniform token purpose = "proxy"
    }

    def Scope "guide" (
        kind = "component"
        prepend references = @/somepath/walls/walls_main/publish/model/modelGuide/v002/walls_main_modelGuide_v002.usd@</guide>
    )
    {
        uniform token purpose = "guide"
    }
}

multiple subAssets are then collected into top asset with variants if need to be.
Hope this helps :slight_smile:
Thanks
R

1 Like

Is this logic you currently have automated and publicly/readily available to share? Or something you wish to have at the end. It sounds quite familiar to some logic that was in place for Houdini USD in an earlier prototype I’ve produced (which I’m not sure is still available in that state in OpenPype).

Anyway, thanks for the input!


@milan @antirotor are you able to provide some details what part of that request might already be in development with regards to the Asset Resolver? I suspect there’s little overlap?

A code design question regarding this @milan @tokestuartjepsen @iLLiCiT - in Maya we currently have the Multiverse USD support that uses the usd family to extract multiverse content with its multiverse settings, etc.

However, the maya native USD has different settings of course so it’d be a different creator. I prototyped it here, gave it usd family as well but of course now Multiverse USD validators + extractors trigger because they run over usd family.

What’s the idea to support both - should we have a maya-usd family and multiverse-usd family (exact naming to be determined) and then solely make sure the integrated representation gets the usd family for both? That way the publishing can be configured for maya-usd one and multiverse-usd one without conflicts, but still result in a regular usd family output?

Soo let’s open up this can of worms :slight_smile:

I’ll try to answer various parts, but let’s focus on the product type / representations question first.

I have quite a strong belief that we should do our best to work with USD on the representation level as much as possible. That being said USD family should almost act as a catchall with not much (or none at all) validation so it mimics how we work with mayaScene, HDA or blenderScene it’s a backup solution when nothing more specific is iimplemented for a give product type I’m publishing.

For instance model should just have USD representation, but from pipeline perspective still be Model Product. Same for Layout and a bunch of others.

Regarding the validators, we can actually make them more specific. The final product type can be usd, but the multiverse validators should really only trigger on instances that also have multiverse family, so we could be cleaner in that distinction.

resulting data is just USD, validators check how it’s produced in a give context

Edit: just to simplify… technically exactly what you’re proposing. Sorry had to read it again

1 Like

So, say for the “animation” instance it auto-generates a USD output. Currently I believe it also triggers the Multiverse export if the instance has both animation and usd family. But we might want to configure pipelines so that we can produce both Multiverse + Maya native USD exports too.

Code design wise in OpenPype - how should I be changing things to allow choosing of publishing Maya USD exports or Multiverse USD exports.

Yup, the resulting Product Type would be usd

I think I’m asking more about how we should now structure the publish families to be used sensibly - to define which current exporter technique to use to generate the product (and also what settings should show in the publisher?)
Any pointers?

Feel like simply making multiple creators that generate publishing instances with families: ["usd", "usd-maya"] or ["usd", "usd-multiverse"].

That should give differentiation for the rest of the publishing and should also be able to provide any publisher option that are common vs separate

Thanks - and looking at other current existing families that’d likely be usdMaya and usdMultiverse correct?

@iLLiCiT Is there any simple built-in/native system to the new style Creators as to how a Creator could say: I’m usdMultiverse family but also always give publish instances the usd family? It’s quite a similar question to how this recently got tweaked for Pointcaches in Houdini where a pointcache turned to be either bgeo or abc but also remain pointcache family. As in, how should a Creator define the instance as families ["usd", "usdMaya"] so that available settings for the instance also are correctly read for all its families.

No, there is not. Other question is if should be. What is the advantage? Is it required for publish attributes to show? If not then it doesn’t worth it, and there should be a dedicated collector for the creator that adds tha family for publishing.

As far as I know family class atteibute is an one string, however publish instances have families class attributes. So I think we can have something in the middle like adding families attribute in creators

I think it’s similar to the idea of having
default_variant and default_variants in new creators


But, I’m wondering
What if we create create instance with just 'MayaUSD' or 'MultiverseUSD' then a collector will take care of that and appends 'usd' to their families

Downside to that is that the new publisher doesn’t provide any attribute definitions then for plug-ins for usd families. As far as I know it only does so for any families it “pre-collected” for the new publisher as opposed to from the Collector pyblish plugins.

yeah, you are right.

I was a little curious and I dug a little bit in code to learn more.

so, Created Instances only have a single string family value
and, when these are instances are discovered, their family somehow are transformed into a list families ?

why it doesn’t happen in the first place as long as this single value will be saved to a list any way ?

Because I believe family is considered its main family and the others are just additional mix-ins or alike. Hmm, not sure if that’s the best explanation.

Regarding the design choices for the new publisher I think it’s best to take that up with @iLLiCiT @milan. At the initial design proposals I had argued that maybe it’d have been better to have a pre-collect stage similar to this Post-collect. So basically before publishing instead of running all collectors there would just be a very few that e.g. could mix-in important data for the publisher UI to actually show. However, technically that’d have meant that if any attribute was changed on an instance that the pre-collect plug-ins might need to re-trigger to ensure the resulting data remained sync. So there are arguments against it. Having all initial data being solely defined by the one creator might be limiting slightly more, but technically it allows for the same things, keeps things together and can allow for more optimization.

Anyway, I’d prefer that the Creators would then return the instances as, this instance has families ["usdMaya", "usd"] without it writing that actual data onto attributes, since it being those types is 100% defined by the creator itself just for the publishing system - it’s not intended to be a customizable attribute and thus not a storable/writable one.

I think it’s not doable without saving that list to node parameters

as far as I know a create instance is not saved as a class objects however it’s just a set or a rop that marked with some extra parameters and publish plugins try to find all sets and rops that contain extra parameters

I’ve implemented a prototype in this draft PR here: Maya: Implement USD publish and load using native `mayaUsdPlugin` by BigRoy · Pull Request #5573 · ynput/OpenPype · GitHub

I did some magical approach by allowing the creator to define multiple publish families without storing it as node parameters which seemed like the best approach to me. @iLLiCiT @milan design wise it’d be good if you could take a peek to join the discussion on that front.

1 Like

Here’s a video of some more quick prototyping showing:

  • Publishing of model with shaders to USD which can be rendered as USD data with Arnold
  • Loading the USD file into Maya
  • Referencing the USD file into a USD stage
  • Managing the loaded USD data
  • Creating a Point Instancer in the USD data in Maya and using that instancing the loaded USD data.

As shared on Discord


The code used in this demo is in this commit available in this branch.

3 Likes

Some more prototyping:

Maya USD export models as variants into a usd asset

Houdini load the Maya USD asset export, set up a layout, animation and lighting publish for a shot context

Also shared on Discord

Note how the “USD Contribution” workflow behaves the same between Houdini and Maya - the contributions are written via the USD API.

Where’s Blender?

I’ve also set up a USD Exporter for Blender, but unfortunately Blender is still using the old publisher and thus won’t have access to attributes in the publisher UI. However, Blender has the same USD library available so once Blender is over to the new publisher this should automatically also work for Blender.

Gimme!

All the stuff demo’ed here is in this branch - I’ll be doing some more prototyping this week and hope to open a draft PR later this week. But if there’s already feedback, definitely provide some - it’s very welcome!

Unittests

The branch also implements some unittests for the usdlib used for the contribution management - which e.g. in that branch is here

1 Like

I like where this is going, a few quick thoughts:

  1. Should department just mostly come from whatever Task was launched? Still good to have the option to override it but I wonder if we should just have the equivalent tasks that are defined on the project.
  2. Are you writing the usd assembly files (the ones that are pretty light and mostly references to other usd heavier data) in ascii format instead of binary so it’s easier to look, edit and debug?
  3. Are USD “Variants” confusing with Ayon/OP “variants”?
  4. Initialize as “asset” is confusing with OP’s “Asset”. I guess this in Ayon won’t be as confusing as the equivalent is “Folder”?
  5. Similar to other Houdini publish discussions I find the publish workflow there a bit cumbersome. The backbone can stay the same but an Ayon Cacher SOP (in this case LOP!) node here would help to visualize more clearly at what parts you are exporting/publishing your model. That SOP node could contain a ROP network where you have the USD ROP nodes but at least you have the exporter/publisher at the same place where you are authoring your data and not referenced somewhere else kind of even hidden if you don’t know how the system works.
  6. How do you envision using this to author different LODs for the assets?

Yes, I feel like in the majority of cases the department layer equals the task - there might be edge cases however where you might be breaking up animation into separate tasks but still want to contribute to the same layer. I think in practice it’ll be something we will most figure out as we use it in production.


Yes, these are currently written as ASCII format but with .usd as recommended in the ASWF: Guidelines for Structuring USD Assets:

Using the “.usd” extension is highly recommended for the “asset.usd”, to avoid having to re-author reference paths when the asset layer is switched between ascii and binary. It may also be useful to carry that to individual layers as well.


In some cases they are almost interchangable - like how I’m using model variants to also turn into USD variants. Whether they are problematic/conflicting terminology down the line I’m not sure - I think it’s fine as is.


The label in the publisher could also read "Initialize as: “USD Asset Structure” if that would make it clearer. But yes, the asset structure does not necessarily mean OpenPype/AYON asset/folder - it’s a USD concept here.


Agreed. The contribution system is just designed to work on a USD export (.usd) file so if we swap it over to another ROP, another HDA or whatever, as long as it generates the base USD file to contribute it should be able to work fine with most of the logic already here. So I’d say it’s a separate problem but definitely one we should solve - I’d really love for the ROPs to not necessarily having to be in /out as well.


Good question! Admittedly, I have no idea - it totally depends on what actual USD asset structure makes sense from a USD perspective. My first thought might be that they could be variants of their own or that the variants are included as a subvariant so that one could switch:

model: main
    lod: LOD0    [from e.g. LOD0, LOD1, LOD2 that exist for 'main' variant]

model: damaged
    lod: LOD1    [from e.g. LOD0, LOD1 that exist for 'damaged' variant]

Currently the contribution system I set up does not inheritly allow building the nested variants however - any contribution you make (e.g. your modelMain contribution) could in itself have variants, etc. This would mean in practice that when publish main you’d need to include all the LODs in the published data, etc.

Again, I think this is something we should figure out a bit more as we go to get grasp on it from a production perspective. (We rarely use LODs on our end so I’m also not too familiar with how they should work from an artist’s perspective.)

1 Like