USD Notes

--> -->

Animation

The docs define a value clip as “An individual layer containing time varying data over some interval.”, this seems to mean that a value clip is simple a layer with time samples.

A clip set is a group of value clips that can be partitioned like in a video editor. So you could have 2 value clips; a run cycle and a walk cycle. In the clip set you can start the have the animation start with the run cycle, stop halfway through, switch to the walk cycle, then back to the remaining half of the run cycle. You could then have another clipset that does the opposite.

Each Clip Set has a Clip Manifest layer/file that declares all of the time sampled attributes, not their values for the clips in the clip set. This saves the value resolution algorithm from having to look through every value clip in the clip set to find out which values to take into account.

USD Stitch Clips will generate a Clip Set, where each frame/USD file represents a value clip. This means that the generated file will have a manifest since there is the possibility that the time sampled attributes may change by frame.

The value clip LOP will create a value clip. It takes in a Manifest which can be generated by the usdstitchclips ROP and the clips to use.

Crowds

The way Houdini generates crowds for USD is like so:

Every agent layer becomes its own SkelRoot prim. This means that if you have a default layer of a person, and then a hat layer where they are wearing a hat on top of the default layer. The geometry from the default layer will be written out twice to USD, once in each of the SkelRoot layer definition.

Alt text Alt text

Notice how the SkelAnimation lives outside of the SkelRoot, this allows for the SkelRoot to be instanceable while also having every agent with a custom animation. For example every agent may have the same rig and basic animation but each animation is different because its deformed to a terrain. Having the SkelAnimation outside of the instanceable SkelRoot may seem like it shouldn’t work because it is an instanceable prim, but USD works by inheriting down the namespace/hierarchy of instances. If you look at the image below, the skel:animationSource relationship is stoped on the xform prim, instead of the actual skeleton. The skeleton in the instance will then inherit the relationship from above, this also works for primvars.

Alt text

Storm in usdview is very efficient, around 3gb memory usage for 700 instanced agents. Even when agents were not instanceable memory usage remained around 3gb in usdview. Playback is interactive. Houdini Storm is slightly slower but still usable, and memory usage is around 3gb for the same scene. HoudiniGL is unusable for UsdSkel, 30gb+ memory and too slow to even consider using. When set to uninstanceable, HoudiniGL uses 30gb of memory and playback is still essentially impossible while Houdini Storm uses 3gb.

Karma XPU in usdview and Houdini both consume the same memory around 9gb, which is to be expected.

Visibility Performance

With large scenes the goal is to limit objects in the viewport so you can develop specific elements.

There are 5 ways you can limit prims in the viewport which are population masks, payloads, activations, visibility and muting. Before diving in it is necessary to understand the basics of USD. A Stage is the scene graph tree generated by the composition engine when you open an USD file. The compositon engine composites layers based on a their opinions to create the final stage and exists only during runtime.

Visibility can be accessed via the Prune LOP and the scene graph tree. Visibility turns off prims in the viewport and hydra but they are still loaded in the composition arc meaning that as far as the composition engine is concerned it is still there and can be manipulated which also means that it adds one more layer for the composition engine to process every time. The upside is that it allows for creative flexibility in the viewport and at render time.

Population masks can be accessed via the Configure Stage LOP or through the scene graph tree. Population masks remove all costs from prims that have not been specified, which sounds great but the downside is it acts globally on your scene graph. When you create a population mask the list of prim paths are saved and those are the only prims allowed in your stage, all other prims will be masked out regardless if they are after you create the mask. The population mask method is a show only method meaning you do not have the option to say show all exepct X prims. This mask is applied to a UsdStage meaning it is not something that is saved to disk. Because population masks completely ignore non-specified prims you will need to know your prim paths or have them preset to benefit. A use case could be if you have just saved out a large USD file for lets say an environment and you reference it into a new stage but it is too heavy. What you would do is place a Configure Stage LOP BEFORE the reference LOP and set the prims you want to load, now the reference lop sees the mask and only loads those primitves.

Activiation can be accessed via the Prune LOP or the scene graph tree. When you deactivate a prim USD ignores it completely similar to population masks but does not create a stage wide mask. A deactivation workflow could be you reference in a large scene and place a Prune LOP after the reference and deactivate some prims. Notice how since the Prune is placed after the reference if you click on the Reference LOP the heavy scene file will try to load unlike with population masks.

Payloads can be accessed via the Sublayer LOP and the Configure Stage LOP. Payloads allow you to sublayer a USD file without any payloads loaded but still access the scene graph hierarchy, this means the only cost comes from composing ancestor/parent prims which are not unloaded. The downside of payloads is that it can require a lot of extra setup as when a payload is unloaded all of its children are unloaded which means that if you have an asset with many components, each component needs to be defined as a payload for it to be unloaded specifically. As of now I do not know how to auto authorize geometry as payloads when imported by path attributes as to avoid having to individually importing each component. Because of their flexibility Payloads are ideal if you can set up for them in advance and should always be an adequate amount of optimization.

Muting works on the level of layers only and ignores the layer completely from USD.