USD Structure and Assembly#
At the heart of USD is its composition engine. A virtual world in OpenUSD is represented as a composed stage.
Prims are organized hierarchically. The composition engine allows various composition arcs, such as references, payloads, and variants, to be applied to any prim in any combination, resolving the resulting scene graph in a predictable way. A significant advantage of this system is the ability for stronger opinions in certain layers to non-destructively override scene descriptions from weaker opinions in other layers. For example, changing the material color of a robot within a factory layout scene does not modify the original referenced robot asset file. Aggregate datasets, such as a work cell or a section of a production line, can themselves be aggregated into larger datasets, ultimately forming the complete factory digital twin.
Further reading
Hands On#
Aggregation#
Let’s take the individual pieces that we have set up and aggregate them into a wheel USD file.
Create a new file: File -> New From Stage Template -> Empty.
Select the World prim and in the property panel set its Kind to component.
To be able to see better, change the light mode from Stage Lights to Grey Sky.
From the content browser, drag and drop all the parts onto the World prim.

Save the file to the root of the Wheel directory and name it Wheel.usd.
Let’s move the individual components into place by hand. To move the individual components into place at scale, usually PLM data can be written to csv or json to be parsed and automated via AI, Python or other tools. This will be demonstrated in the workflow iteration cycle automation section.
Select the
/World/Brake_Disk/Disk_Brake_1021
Xform. Before you move it, switch to the Layer panel. Notice that we only have the payloads of the components and nothing else.Now move the Xform forward on the X axis to 14.0. You can do this by using the viewport transform widget and click drag on the red transform handle and the transform op will be created for you in the property panel. You can also click +Add Transforms in the property panel and typing the value in but as of Kit 107.3.1 there is an existing defect with this method.

Notice how we are getting a new group in the Property window containing the Xform and a triangle in the layer panel - this is an opinion that we have introduced by moving the disk break to a position that differs from the original location of the part.
Note
You can RMB -> Delete Delta on the entry with the triangle in the layer panel and the part will go back to its original location.
Do the same with
/World/Caliper/Caliper_8708
- select it in the stage panel and move it forward 14.0 on the X axis.For the
/World/Bolt/Bolt_1113
, move it to ( X=18.0, Y=5.6, Z=0.0 ).
Next, let’s enable an extension to easily fill in the rest of the bolts to show how you can easily extend your workflows with custom tools. You could also easily duplicate and rotate these bolts.

Go to Developer -> Extensions and search for Array Tool. Install it if not installed then enable it. You can also set it to autoload if you want it enabled at all times.
Select the top level Bolt payload prim (
/World/Bolt
), then click Tools -> Array Tool.Set the count to 5, Rotate X to 72, and under options check create copies.
Click Apply (the preview shows the result).

The array tool is a sample extension that demonstrates how you can enhance a workflow with custom tools to speed up iteration time.#
Now that we used an offset pivot for authoring, let’s fix the pivots by going to Window -> Utilities -> Scene Optimizer.
Select all the Bolt payloads.
Click + Add Scene Optimizer Process and add Compute Pivot. The processor will be added to the bottom of the stack if you have processors there already.
Set:
- Apply to to Meshes and Xforms
- Method to Bounding Box Center.
- Prims To Process, click the + Add to limit the compute pivot process to the selected prims and their sub hierarchies.
- Click Execute - Compute Pivot.
Notice how each pivot is now in the center of each respective bolt geometry.

Save the file.
We now have a component file that we can drop into a stage that can aggregate many of these wheels.
Sublayer#
Exploring the concept of sublayers is important for understanding stage transformations in OpenUSD. A stage can be built from multiple layers, including sublayers, each containing specific data or transformations such as geometry, materials, or transforms. When another layer subscribes to a sublayer, it is set up to reference or include that sublayer, so any changes made—such as updates from a new CAD conversion—are automatically reflected wherever the sublayer is used. This approach enables efficient, automated updates throughout your pipeline. While this method offers greater flexibility, it may require additional data management to ensure these data layers remain up to date when your source data changes, for example, through re-conversion from CAD.
In the same Wheel.usd file, go to the Layer panel and click on Create Sublayer.
Name the sublayer file Wheel_Merged.usd and save it to a new folder named “Sublayers” within the same folder where “Wheel.usd” is located.
Say No to the question of transferring root layer contents to a new sublayer. We want to only store transformational data in the sublayer and not all the original content.
Double-click on the Wheel_Merged.usd layer, or right-click on Wheel_Merged.usd and select Set Authoring Layer, to make it the authoring layer.
Go to Scene Optimizer and click + Add Scene Optimizer Process -> Merge Static Meshes. The processor will be added to the bottom of the stack if you have processors there already.
Set the Merge Boundary to Root Prim and click Execute - Merge Static Meshes.
In the Stage panel, double-click on the merged mesh named “merged” and name it Merged_Wheel
Go back to the material library we added earlier and select each GeomSubset under the Merged_Wheel prim and assign the shaders by double clicking them from the material tab. For the Chromium subsets, select all of them before double clicking on the Chromium from the material library. Same thing for Caliper.
We are copying the required materials into the scope of this stage, making them directly accessible within the current USD scene file. This ensures that even after we deactivate the original payloads, the geometry in our scene will retain valid material assignments and maintain its correct appearance.When done, nothing will have changed visually, but you will have a Looks Scope under the world prim with all the materials native to this stage now.
Select all the individual parts and RMB -> deactivate.
Go back to the layer panel and click the save icon to save the layer or RMB on the Authoring Layer and click “save”.
Double-click the root layer to set it back to be the authoring layer.
Go to the layer panel and click the eye ball to mute the Wheel_Merged layer. Inspect the stage view and notice how our original state is back.
Back to the layer panel click the eye to un-mute the layer and notice how a merged mesh is now representing the stage again.
If you remove this layer, the stage is back to its original state, and if you add the sublayer in again, you have a different representation.
This is a powerful concept that allows you to transform data in a non destructive way.
Important to note for this specific example is that if the wheel should change, you would need to re-create the sublayer, because the connection to the original data was severed when we created a new mesh representation by merging the static meshes. Because of the flexible nature of Omniverse, this can be done easily by just running scene optimizer and some Python scripts via CLI when the source data changes.
In most cases, you do not need to recreate a sublayer because it simply introduces new opinions, such as changes to properties or attributes, on existing prims by referencing their unique paths in the stage. As long as these prim paths remain unchanged, the sublayer will continue to apply its opinions correctly. This is why it is important to keep prim paths consistent when updating or iterating on your assets.