Skip to content

How to group animation data (joints, transforms, custom attributes) into a single predictable USD structure without custom primwriters? #4677

Description

@serelium

Context

We're exporting animation files from Maya scenes that can contain multiple animated entities. We are using Maya 2023 and Maya 2025 with their respective maya-usd versions. Each entity is a character or prop rig in Maya, and for each one the animation data can include:

  • Joint animation on a skeleton
  • Displacement, which can be either a separate skeleton or an animated transform
  • Actor references, which can be either joints inside the displacement skeleton or animated transforms
  • Other animated transforms that are part of the animation but unrelated to displacement or actor references
  • Custom animated attributes on various nodes
Image

Maya outliner showing one entity with its skeleton, displacement node, and animated transforms highlighted

The Maya scene used for the examples in this thread is attached: maya-usd-export-example.ma (examples.zip)

When exported to USD via maya-usd, each of these becomes:

  • Joint animation via SkelAnimation
  • Displacement as either a Skeleton with its own SkelAnimation, or a time-sampled Xform
  • Actor references as either joints inside the displacement Skeleton, or time-sampled Xform prims
  • Other time-sampled Xform prims
  • Custom time-sampled attributes on various prims
Image

Raw maya-usd export for one entity before any chasers run. The animation data is split across multiple disconnected prims with no grouping.

Full USD file (raw maya-usd output, no chasers): maya-usd-export-example.usda (examples.zip)

All of these animation channels scattered across the USD are actually a single animation file in our game engine, compounding potentially many animation channels into one unit. That animation file is identified by a unique engine ID.

Image

A single animation file in our engine, showing its unique engine ID and all its animation tracks.

The framed tracks are not joints from the main skeleton. They are the additional transforms and joints (displacement, actor references, extra props) described above, which must be exported as part of the same animation file. The remaining tracks are the standard skeleton joints. The animation file in the engine therefore groups channels that come from different sources in the Maya scene into a single unit.

We currently use selection sets as a workaround to represent this grouping in Maya, where each set holds all the Maya nodes whose animation belongs to the same file. The USD structure produced on export must transport that engine ID so the engine can make the connection between the USD data and the animation file it belongs to.

Eventually we will also want to transfer several animation files in a single export, meaning one USD file would carry multiple animations for multiple entities at once (this would map to what Maya calls clips, or what the Time Editor calls Compositions under a Take). The grouping and ID tagging must work at that scale. We have started exploring USD value clips as a way to compose multiple animations of a single Take into one structure, but we have not settled on an approach yet.

Our longer term goal is to be able to represent and transport a full cinematic workspace in USD. The image below shows what that workspace looks like in our engine: multiple characters each with their own animation and facial animation tracks, composed together across shots into a single Take. This is the structure we ultimately want to be able to round-trip through USD, and it is the reason Takes and multi-animation composition are important to us.

Image

A cinematic workspace in our engine. Multiple characters each have their own animation and facial animation tracks composed across shots into a single Take. This is the structure we ultimately want to represent and transport in USD.

What we want is to author animation scenes using Maya-native concepts as much as possible and have that authoring round-trip cleanly through USD, rather than relying on a workaround to reconstruct the grouping on export.


Current approach and its problems

We use export chasers to reorganize the data after maya-usd writes it. The goal is to consolidate everything belonging to the same entity under a single identifiable structure in USD. In practice this is fragile:

  • The number of SkelAnimation prims maya-usd produces depends on what was selected for export and what skeletons are present in the scene. For a character we get two (displacement + main skeleton), for a prop we may get none.
  • Displacement and actor references can be represented either as joints inside a SkelAnimation or as time-sampled transforms on Xform prims, depending on how the Maya scene is set up. The chaser has to detect which representation was used and handle each combination.
  • Beyond displacement and actor references, arbitrary Xform prims anywhere in the entity hierarchy can carry time-sampled transforms that are meaningful animation data. These have no structural marker distinguishing them from non-animated transforms.
  • Animated transforms and custom attributes are scattered across the prim hierarchy with no natural grouping.
  • The selection set membership is lost entirely after export, so the USD has no record of which prims belonged to the same animation.
  • Chasers have to handle each case differently, leading to growing edge case logic that multiplies with every new combination.
Image

The same entity after our export chasers run. The data is reorganized into a single SkelAnimation structure, but this requires significant post-processing logic.

Full USD file (after our chasers run): custom-export-example.usda (examples.zip)


Additional structural constraint

Beyond the grouping problem, maya-usd exports the animated entity as a full SkelRoot + Skeleton + SkelAnimation hierarchy even when we only want to transport the animation data. For our use case the skeleton definition (bind transforms, rest transforms, joint topology) lives in the asset file, so the animation file should only contain the time-sampled values. We have no way to tell maya-usd to suppress the SkelRoot and Skeleton prims and emit only the SkelAnimation.

The same constraint applies on import. Maya-usd appears to require the full SkelRoot -> Skeleton -> SkelAnimation chain to be present before it will process any animation data. A USD file containing only SkelAnimation prims, or SkelAnimation prims under a lighter structure, is silently ignored. This means we cannot produce a lean animation-only file and round-trip it through maya-usd without reconstructing the full skeleton hierarchy on both ends, which defeats the purpose of separating asset and animation files.


What we want

Authoring

We want to author animation scenes in Maya using native Maya concepts as much as possible. We looked at the Time Editor as a natural candidate since it is Maya's built-in tool for organizing and managing animation clips. However in its current state it does not give us what we need for two reasons: it operates at the clip level and does not let us declare which animated nodes belong to a given animation unit in a way that survives export to USD, and it is not designed for constant iteration. Once an animation source has been produced it cannot be modified in place and must instead be deleted and recreated, which makes it impractical for an animation authoring workflow. On top of that, maya-usd does not natively handle Time Editor data during export. Clips and animation sources are ignored entirely, so even if we used the Time Editor as our authoring tool the animation would not make it into the USD file.

Is there a mechanism in maya-usd, either at the export context level, via metadata, or through composition (applied API schemas, over prims, custom layers), that would let us declare a grouping anchor for animation data produced by the native export pipeline without taking ownership of writing the animation data itself?

Is there a recommended pattern in the maya-usd ecosystem for grouping heterogeneous animation data (joints, transforms, custom attributes) from a multi-entity Maya scene into per-entity structures in USD?


Import

A broader issue we want to raise is how the USD importer handles existing Maya nodes. Right now maya-usd always creates new Maya nodes on import. What we would like instead is a way to inject our own resolution logic so that incoming USD prims are matched against nodes that already exist in the scene rather than always creating new ones.

This is feasible for us because our USD files carry unique object IDs as custom metadata on each prim, and those same IDs are stored as custom attributes on the corresponding Maya nodes. On a subsequent import we have everything we need to match a USD prim to its existing Maya node. Is there a hook or an interface in the import pipeline that would allow this kind of custom resolution behavior?


The files (.ma and .usda) used as examples:
examples.zip

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions