
Table of Contents:
Benefits of USD for Collaboration
Scalability and Performance
Installing USD on Your Machine
Setting up USD from source
Pre-built binaries for different OS
USD Files (USDA, USD, USDC, USDZ)
USD Layers
Using USD and Python
Creating a Cube
Understanding Layers and Composition in USD
How USD Layers Work
Layer Muting and Layering Examples
References and Overrides in USD
Referencing Complex Assets
Overriding Properties and Attributes
Layering in USD
Inheritance in USD
Variants in USD
References in USD
Payloads in USD
Sub-Layers in USD
Introduction to USD Primitives (Cube, Sphere, Capsule)
Adding Custom Geometries
Working with USD in Different DCCs
USD in Maya
USD in Houdini
USD in Katana
Introduction to TimeSamples and Animations in USD
TimeSamples vs Keyframes
Animating Transforms in USD
Creating a Simple Scene with Animated Objects
Adding Custom Shaders and Materials
Introduction to Hydra
Setting up a Hydra Render Scene
Advanced USD: Introduction to USD Skel
Understanding Skeletons and Rigs in USD
Example: Building a Simple Rig
Optimizing USD for Large-Scale Productions
Caching and Layer Streaming
Memory Optimization Techniques
USD for Collaborative and Cloud-Based Workflows
USD in a Pipeline
USD in the Cloud
1. What is USD (Universal Scene Description)?
Universal Scene Description, or USD, is a file format and framework developed by Pixar Animation Studios to handle complex 3D graphics, scene hierarchies, and asset management. USD is more than just a file format—it's a flexible, extensible framework that allows artists, technical directors, and developers to manage massive assets, collaborate on scene data, and move between different digital content creation (DCC) tools seamlessly.
Pixar designed USD to handle:
Asset creation: Models, rigs, textures, shaders, and environments.
Scene composition: Assembly of complex assets with transformations, attributes, and animation.
Collaboration: Multiple teams working on the same assets or scenes using layers and composition.
USD represents scenes in a universal way, allowing interoperability across multiple DCCs like Maya, Houdini, and Katana.
2. The History and Origin of USD
Pixar originally developed USD as a means to handle the complex environments and high-detail assets required for their films. As their films evolved in terms of complexity and scale, so did the demand for a robust framework that could handle this ever-increasing challenge.
USD was open-sourced in 2016, enabling the entire 3D industry to leverage this technology for production pipelines, facilitating a universal standard for 3D scene description and data exchange.
3. Core Concepts of USD
To understand USD, it's essential to grasp the following core concepts:
Layering: USD uses a non-destructive workflow. Multiple artists or processes can work on the same scene, each adding to a different layer. These layers are then composed into the final scene, respecting the hierarchy of edits.
Composition: Composition refers to how USD assembles layers and scene data. This can involve various types of operations like referencing, overriding, or using variants to manage different versions of an asset.
References and Overrides: With references, you can pull in external files and layers into your scene. Overrides allow you to modify referenced assets without altering the original source.
Variants: Variants are powerful tools in USD that allow you to define different versions of a model (like different LODs or texture maps) and switch between them.
4. Why Use USD?
USD's most significant strength lies in its ability to scale from individual asset development to the assembly of vast, highly detailed scenes in production environments.
Benefits of USD:
Interoperability: USD files can be imported and exported across multiple DCCs, allowing seamless integration into pipelines that involve Maya, Houdini, Katana, Blender, and others.
Collaboration: Different teams can work on various parts of the same project without conflict. For example, animators can work on animation layers while shading artists work on material layers without overwriting each other’s work.
Non-destructive Editing: USD allows for multiple artists to collaborate on the same asset or scene through layering, where each layer can contain separate edits.
Efficient Scene Composition: USD's layering and composition make it highly efficient for large scenes with many assets. USD only loads the necessary assets into memory, which helps avoid performance bottlenecks.
5. Installing USD on Your Machine
Setting Up USD from Source
USD is available on GitHub, where you can clone and build the source files for your system. Follow these steps to get started:
Clone the repository:
git clone https://github.com/PixarAnimationStudios/USD
cd USD
Install dependencies: USD requires some external libraries, such as OpenEXR, TBB, Boost, and OpenImageIO. You can install these via package managers like apt for Linux, brew for macOS, or download them manually for Windows.
Build the USD framework: Run the following command to build USD:
python build_scripts/build_usd.py /path/to/install/USD
Environment Setup: Once the build is complete, set up your environment by configuring the PATHÂ and PYTHONPATHÂ variables:
export PATH=/path/to/install/USD/bin:$PATH
export PYTHONPATH=/path/to/install/USD/lib/python:$PYTHONPATH
6. The USD File Structure

USD Files
USD supports multiple file formats:
USDA: ASCII format, human-readable and easy to edit manually.
USD: Binary format, optimized for performance in production.
USDC: Binary, more compact than USD, ideal for large datasets.
USDZ: Archive format that packages all assets like textures, shaders, and animations into a single file. Ideal for AR and iOS devices.
7. Creating a Simple USD Scene
Let’s create a basic USD scene using Python.
Example: Creating a Simple Cube
Here’s a minimal Python example that demonstrates how to create a simple USD scene with a cube.
from pxr import Usd, UsdGeom
# Create a new USD stage
stage = Usd.Stage.CreateNew("simple_scene.usda")
# Define the root of the scene
UsdGeom.Xform.Define(stage, "/World")
# Create a Cube primitive in the scene
UsdGeom.Cube.Define(stage, "/World/Cube")
# Save the stage
stage.GetRootLayer().Save()
8. Understanding Layers and Composition in USD
USD supports a layered approach to scene construction. Layers are combined and composed into the final scene, allowing for non-destructive editing and collaboration.

How USD Layers Work
Layers in USD are like layers in Photoshop; they stack on top of each other, with higher layers overriding lower ones when necessary. Each layer can contain different assets, animations, or modifications.
Example: Layering in USD
Let’s add more layers to our simple cube scene.
from pxr import Usd, UsdGeom
# Create the base layer
base_stage = Usd.Stage.CreateNew("base_layer.usda")
UsdGeom.Xform.Define(base_stage, "/World")
UsdGeom.Cube.Define(base_stage, "/World/Cube")
base_stage.GetRootLayer().Save()
# Create an override layer
override_stage = Usd.Stage.CreateNew("override_layer.usda")
UsdGeom.Xform.Define(override_stage, "/World")
override_cube = UsdGeom.Cube.Define(override_stage, "/World/Cube")
override_cube.AddTranslateOp().Set((2, 2, 2))
override_stage.GetRootLayer().Save()
# Create a composed stage
composed_stage = Usd.Stage.CreateNew("composed_scene.usda")
composed_stage.GetRootLayer().subLayerPaths.append("base_layer.usda")
composed_stage.GetRootLayer().subLayerPaths.append("override_layer.usda")
composed_stage.GetRootLayer().Save()
In this example, two layers are created: a base layer that defines the cube and an override layer that moves it to a new position. Both layers are then composed into a final scene.
9. References and Overrides in USD
USD references allow you to reuse existing assets while still giving you the ability to modify and override them in different contexts.
Example: Referencing an External Asset
from pxr import Usd
# Create a new stage
stage = Usd.Stage.CreateNew("reference_scene.usda")
# Reference an external asset
stage.DefinePrim("/World/Asset").GetReferences().AddReference("path/to/external_asset.usd")
# Save the stage
stage.GetRootLayer().Save()
This example demonstrates how to reference an external USD asset into your scene without duplicating the file. Any changes made to the external asset will automatically be reflected in your scene.
10. Understanding LIVRPS (Layering, Inheritance, Variants, References, Payloads, and Sub-Layers)

USD’s composition model allows you to manage complex scenes and assets through a non-destructive workflow. Central to this are concepts like Layering, Inheritance, Variants, References, Payloads, and Sub-Layers—collectively abbreviated as LIVRPS. Understanding these concepts is crucial for leveraging USD in real-world production environments where multiple artists and processes work on the same assets or scenes.
Let’s break down each component of LIVRPS and explore how they interact to manage complex data.
Layering in USD
Layers in USD represent discrete files that hold scene data. A USD scene is often built up from multiple layers that stack on top of each other. Each layer can define geometry, transforms, shaders, and other properties. When these layers are composed together, they form the final scene.
Layers work similarly to layers in Photoshop, where the top layer can override values from lower layers. This allows for non-destructive edits since each artist or department can work on their own layer without modifying the base data.
Example: Layering in USD
Let’s say we have a simple scene with a cube. We create two layers:
The base layer defines the cube.
The override layer moves the cube to a different position.
from pxr import Usd, UsdGeom
# Create the base layer
base_stage = Usd.Stage.CreateNew("base_layer.usda")
UsdGeom.Xform.Define(base_stage, "/World")
UsdGeom.Cube.Define(base_stage, "/World/Cube")
base_stage.GetRootLayer().Save()
# Create the override layer
override_stage = Usd.Stage.CreateNew("override_layer.usda")
UsdGeom.Xform.Define(override_stage, "/World")
cube = UsdGeom.Cube.Get(override_stage, "/World/Cube")
cube.AddTranslateOp().Set(value=(10, 0, 0))
override_stage.GetRootLayer().Save()
# Create a composed stage that references both layers
composed_stage = Usd.Stage.CreateNew("composed_scene.usda")
composed_stage.GetRootLayer().subLayerPaths.append("base_layer.usda")
composed_stage.GetRootLayer().subLayerPaths.append("override_layer.usda")
composed_stage.GetRootLayer().Save()
In this example:
The base layer defines the cube.
The override layer modifies the cube’s position.
When we combine these layers in the composed stage, the cube appears at the new location (10, 0, 0).
Inheritance in USD
Inheritance in USD allows prims (primitives, which are objects or components in the scene) to inherit attributes and behaviors from other prims. This can reduce redundancy and make scene management more efficient by allowing a hierarchy of objects to share common properties.
USD provides class inheritance, which allows you to define shared properties in a class and have multiple prims inherit from that class.
Example: Inheritance in USD
from pxr import Usd, UsdGeom
# Create a new stage
stage = Usd.Stage.CreateNew("inheritance.usda")
# Define a class for shared properties
base_class = UsdGeom.Xform.Define(stage, "/Class/Base")
cube_class = UsdGeom.Cube.Define(stage, "/Class/Base/Cube")
cube_class.AddTranslateOp().Set(value=(0, 0, 0)) # Default position
# Create an instance that inherits from the base class
cube_instance = UsdGeom.Cube.Define(stage, "/World/InheritedCube")
cube_instance.GetPrim().GetInherits().AddInherit("/Class/Base/Cube")
# Override the position for the inherited cube
cube_instance.AddTranslateOp().Set(value=(5, 5, 5))
# Save the stage
stage.GetRootLayer().Save()
In this example:
We create a base class that defines a cube.
The cube in /World/InheritedCube inherits from the base class but overrides its position.
Variants in USD
Variants allow you to define multiple versions of a prim (for example, a model with different levels of detail or different textures). You can switch between these versions without duplicating the geometry or other data, making it ideal for managing variations in complex scenes.
Example: Using Variants in USD
from pxr import Usd, UsdGeom
# Create a new stage
stage = Usd.Stage.CreateNew("variants.usda")
# Create a cube
cube = UsdGeom.Cube.Define(stage, "/World/Cube")
# Add a variant set
variantSet = cube.GetPrim().GetVariantSets().AddVariantSet('modelVariant')
variantSet.AddVariant('lowRes')
variantSet.AddVariant('highRes')
# Set the low-res variant and modify the size
variantSet.SetVariantSelection('lowRes')
with variantSet.GetVariantEditContext('lowRes'):
cube.GetPrim().GetAttribute('size').Set(1)
# Set the high-res variant and modify the size
variantSet.SetVariantSelection('highRes')
with variantSet.GetVariantEditContext('highRes'):
cube.GetPrim().GetAttribute('size').Set(5)
# Save the stage
stage.GetRootLayer().Save()
Here, we define two variants (lowRes and highRes) for the same cube, each with a different size. You can switch between these variants depending on the context.
References in USD
References allow you to include external USD assets in your scene. This enables scene composition where different teams can work on separate assets, and you can reference their work without duplicating data.
A reference brings the entire hierarchy of another USD file into your scene, including geometry, transformations, and any other data defined in the referenced file.
Example: Referencing External USD Files
from pxr import Usd
# Create a new stage
stage = Usd.Stage.CreateNew("referencing.usda")
# Reference an external USD file
reference_prim = stage.DefinePrim("/World/Asset")
reference_prim.GetReferences().AddReference("path/to/external_asset.usda")
# Save the stage
stage.GetRootLayer().Save()
This example demonstrates how to reference an external USD file into your scene. The external_asset.usda file could contain a complex model that you want to bring into your current scene. Any updates to the external asset will automatically reflect in your scene without needing to re-import or copy the data.
Payloads in USD
Payloads work similarly to references, but with one key difference: they are deferred by default. This means that the referenced data is not loaded into memory unless explicitly requested. Payloads are useful when dealing with very large scenes or assets that might not be needed immediately.
Example: Using Payloads in USD
from pxr import Usd
# Create a new stage
stage = Usd.Stage.CreateNew("payloads.usda")
# Define a prim with a payload
payload_prim = stage.DefinePrim("/World/HeavyAsset")
payload_prim.GetPayloads().AddPayload("path/to/heavy_asset.usda")
# Save the stage
stage.GetRootLayer().Save()
In this case, the USD file heavy_asset.usda will only be loaded into memory when necessary, making the workflow more efficient when working with large datasets.
Sub-Layers in USD
Sub-layers are a way to layer multiple USD files on top of each other. Each sub-layer contributes data to the final composed scene, and the order of the sub-layers determines how they override each other.
Example: Using Sub-Layers in USD
from pxr import Usd
# Create a new stage
stage = Usd.Stage.CreateNew("sub_layers.usda")
# Add sub-layers
stage.GetRootLayer().subLayerPaths.append("base_layer.usda")
stage.GetRootLayer().subLayerPaths.append("override_layer.usda")
# Save the stage
stage.GetRootLayer().Save()
In this example, the base layer contains the initial data, while the override layer modifies or adds to that data. The order of the sub-layers is important because higher layers can override values from lower layers.
Putting It All Together: LIVRPS in Action
Let’s combine all the components of LIVRPS into a single example to illustrate how layering, inheritance, variants, references, payloads, and sub-layers work together.
Comprehensive Example: LIVRPS in USD
from pxr import Usd, UsdGeom, UsdShade
# Create a new stage
stage = Usd.Stage.CreateNew("livrps_example.usda")
# 1. Layering: Add a base and override layer
base_stage = Usd.Stage.CreateNew("base_layer.usda")
UsdGeom.Cube.Define(base_stage, "/World/Cube")
base_stage.GetRootLayer().Save()
override_stage = Usd.Stage.CreateNew("override_layer.usda")
cube = UsdGeom.Cube.Get(override_stage, "/World/Cube")
cube.AddTranslateOp().Set(value=(10, 10, 0))
override_stage.GetRootLayer().Save()
# Add sub-layers
stage.GetRootLayer().subLayerPaths.append("base_layer.usda")
stage.GetRootLayer().subLayerPaths.append("override_layer.usda")
# 2. Inheritance: Create a class with shared properties
UsdGeom.Xform.Define(stage, "/Class/Base")
inherited_cube = UsdGeom.Cube.Define(stage, "/World/InheritedCube")
inherited_cube.GetPrim().GetInherits().AddInherit("/Class/Base")
# 3. Variants: Add two variants for the inherited cube
variant_set = inherited_cube.GetPrim().GetVariantSets().AddVariantSet('res')
variant_set.AddVariant('lowRes')
variant_set.AddVariant('highRes')
variant_set.SetVariantSelection('lowRes')
with variant_set.GetVariantEditContext('lowRes'):
inherited_cube.GetPrim().GetAttribute('size').Set(1)
variant_set.SetVariantSelection('highRes')
with variant_set.GetVariantEditContext('highRes'):
inherited_cube.GetPrim().GetAttribute('size').Set(5)
# 4. References: Reference an external USD file
reference_prim = stage.DefinePrim("/World/ExternalAsset")
reference_prim.GetReferences().AddReference("external_asset.usda")
# 5. Payloads: Add a deferred asset using a payload
payload_prim = stage.DefinePrim("/World/DeferredAsset")
payload_prim.GetPayloads().AddPayload("heavy_asset.usda")
# Save the final composed stage
stage.GetRootLayer().Save()
Explanation:
Layering: We create a base layer and an override layer, with the override layer modifying the position of the cube.
Inheritance: The cube in /World/InheritedCube inherits from the class /Class/Base, allowing shared properties.
Variants: We define two variants (lowRes and highRes) for the inherited cube, each with a different size.
References: We reference an external asset using the AddReference()Â method.
Payloads: We defer loading a large asset by using a payload.
This comprehensive example demonstrates how all the components of LIVRPS can be used in a real-world USD pipeline, offering scalability, flexibility, and efficiency when working on complex scenes.
11. USD Primitives and Geometries
USD provides a wide range of built-in geometry types, or "primitives," that allow you to represent the most common shapes you would need in a scene. These include standard shapes like cubes, spheres, cones, cylinders, and capsules. USD also allows you to define custom geometries for more advanced shapes, giving you the flexibility to create almost anything.
Introduction to USD Primitives
Let's explore the most commonly used USD primitives:
UsdGeom.Cube: Represents a cube.
UsdGeom.Sphere: Represents a sphere.
UsdGeom.Cone: Represents a cone.
UsdGeom.Cylinder: Represents a cylinder.
UsdGeom.Capsule: Represents a capsule.
Example: Creating Multiple Primitives in USD
from pxr import Usd, UsdGeom
# Create a new USD stage
stage = Usd.Stage.CreateNew("primitives_scene.usda")
# Create a Xform group to hold our primitives
UsdGeom.Xform.Define(stage, "/World")
# Create a Cube
UsdGeom.Cube.Define(stage, "/World/Cube")
# Create a Sphere
UsdGeom.Sphere.Define(stage, "/World/Sphere")
# Create a Cone
UsdGeom.Cone.Define(stage, "/World/Cone")
# Create a Cylinder
UsdGeom.Cylinder.Define(stage, "/World/Cylinder")
# Create a Capsule
UsdGeom.Capsule.Define(stage, "/World/Capsule")
# Save the stage
stage.GetRootLayer().Save()
In this example, we're creating a USD scene that contains five different geometric primitives: a cube, a sphere, a cone, a cylinder, and a capsule. Each primitive is created under the /World Xform group.
Adding Transformations to Primitives
Once you have created a primitive, you will often want to modify its position, rotation, or scale in the scene. This is done by applying transformations, such as translations (moving the object), rotations, or scaling (resizing the object).
from pxr import Usd, UsdGeom
# Create a new USD stage
stage = Usd.Stage.CreateNew("transformed_primitives_scene.usda")
# Create a Xform group to hold our primitives
world = UsdGeom.Xform.Define(stage, "/World")
# Create a Cube
cube = UsdGeom.Cube.Define(stage, "/World/Cube")
# Apply a translation to the cube
xformOp = cube.AddTranslateOp()
xformOp.Set((1, 1, 1))
# Apply a rotation to the cube
rotateOp = cube.AddRotateXYZOp()
rotateOp.Set((45, 0, 0))
# Apply scaling to the cube
scaleOp = cube.AddScaleOp()
scaleOp.Set((2, 2, 2))
# Save the stage
stage.GetRootLayer().Save()
In this example, we are applying three different transformations to a cube:
Translation: Moves the cube to position (1, 1, 1)Â in the world space.
Rotation: Rotates the cube 45 degrees around the X-axis.
Scaling: Scales the cube by a factor of 2Â in each axis, making it twice as large as its original size.
These transformations can be combined and manipulated to build complex scenes with dynamic and interactive elements.
12. Working with USD in Different DCCs
USD is designed to be interoperable between multiple DCC (Digital Content Creation) tools. Pixar developed it to allow seamless integration between software platforms such as Maya, Houdini, and Katana, allowing artists and technical directors to move assets between software packages without the need for conversion.
USD in Maya
Maya integrates USD with the Maya USD plug-in, allowing users to import and export USD files, create new assets using USD, and use USD for scene assembly and composition.
Importing USD Files in Maya
You can import USD files directly into Maya using the USD Import options:
Open Maya.
Go to the File menu and select Import.
Choose USDÂ as the file type.
Browse to the location of your USD file and select it for import.
Once imported, the USD scene will appear in the Maya viewport, and you can manipulate it as if it were a native Maya scene.
Exporting USD Files from Maya
To export a Maya scene to USD:
Open the scene in Maya.
Go to File -> Export All (or Export Selection if you want to export only part of the scene).
In the export options, choose USD Export.
Configure any export settings (such as exporting in .usda, .usd, .usdc, or .usdz formats).
Click Export to generate the USD file.
Python Example: Exporting a Scene from Maya Using Script Editor
You can also export a USD file from Maya using Python in the Script Editor.
import maya.cmds as cmds
# Select the objects to export
cmds.select("pCube1", "pSphere1")
# Export to USD
cmds.file("C:/path/to/your/usd_file.usda", force=True, options=";", type="USD Export", exportSelected=True)
This script will export the selected objects (pCube1Â and pSphere1) as a USD file.
USD in Houdini
Houdini has deep integration with USD, allowing you to build and manipulate USD stages directly within Houdini’s node-based interface. The LOP (Lighting Operators) context is where USD workflows are primarily handled in Houdini, offering an interactive environment to compose, light, and render USD-based scenes.
Creating USD Primitives in Houdini
In Houdini, USD primitives can be created using the Sop Create LOP node.
Create a new LOPÂ network in Houdini.
Add a Sop Create node and dive inside.
Create geometry (such as a cube or sphere) using Houdini’s standard SOP nodes.
This geometry will be automatically converted to USD and displayed in the Stage viewport.
Exporting USD from Houdini
To export your USD scene from Houdini:
Add a USD ROPÂ node to your LOPÂ network.
Configure the output path for your USD file.
Click Render to Disk to generate the USD file.
USD in Katana
Katana integrates USD into its workflow for scene composition, lighting, and rendering. Katana's USD nodes allow you to manage scene assembly using USD layers and composition.
Example: Importing a USD File in Katana
In Katana:
Create a UsdIn node.
Point the file parameter of the UsdIn node to your USD file.
The USD scene will now be available for lighting and rendering inside Katana.
13. Introduction to TimeSamples and Animations in USD
USD provides a powerful framework for handling animation through two primary mechanisms: TimeSamples and Keyframes. TimeSamples allow for precise control over how data evolves over time, making it ideal for dealing with complex, continuous animations.
TimeSamples vs. Keyframes
Keyframes: Discrete points in time where a specific value (such as position or rotation) is specified. Keyframes work well for traditional keyframe-based animation.
TimeSamples: These are more granular than keyframes and allow USD to store values at specific time intervals. This is useful for motion blur, caching simulations, or ensuring smooth transitions.
Example: Animating a Cube with TimeSamples
from pxr import Usd, UsdGeom
# Create a new stage
stage = Usd.Stage.CreateNew("animated_cube.usda")
# Define the cube geometry
cube = UsdGeom.Cube.Define(stage, "/World/Cube")
# Set initial time samples for position (X, Y, Z)
cube.AddTranslateOp().Set(value=(0, 0, 0), time=0)
cube.AddTranslateOp().Set(value=(5, 5, 5), time=24)
# Save the stage
stage.GetRootLayer().Save()
In this example, we create a cube and apply a TranslateOp transformation to move the cube from (0, 0, 0) at time 0 to (5, 5, 5) at time 24. This creates a smooth transition between these two positions.
Keyframes for Rotation
USD can also handle keyframe animation using rotation values.
# Add rotation keyframes for the cube
cube.AddRotateXYZOp().Set(value=(0, 0, 0), time=0)
cube.AddRotateXYZOp().Set(value=(90, 0, 0), time=24)
This snippet rotates the cube 90 degrees around the X-axis over the course of the animation.
Animation Caching in USD
One of the most useful features of USD is its ability to cache complex animations. This allows for efficient playback in DCCs without needing to calculate the animation every time it’s loaded.
14. Building a Real-World Example
Now that you’re familiar with basic USD concepts, let’s build a more complex scene that involves creating multiple animated objects, applying shaders, and exporting the scene for rendering.
Scene Overview
In this scene, we’ll:
Create three different objects (a cube, a sphere, and a cylinder).
Animate the objects over time.
Apply materials and shaders to each object.
Export the scene for rendering.
Example: Building the Scene
from pxr import Usd, UsdGeom, UsdShade
# Create a new USD stage
stage = Usd.Stage.CreateNew("real_world_scene.usda")
# Create a cube
cube = UsdGeom.Cube.Define(stage, "/World/Cube")
cube.AddTranslateOp().Set(value=(0, 0, 0), time=0)
cube.AddTranslateOp().Set(value=(5, 0, 0), time=24)
# Create a sphere
sphere = UsdGeom.Sphere.Define(stage, "/World/Sphere")
sphere.AddTranslateOp().Set(value=(0, 5, 0), time=0)
sphere.AddTranslateOp().Set(value=(0, 10, 0), time=24)
# Create a cylinder
cylinder = UsdGeom.Cylinder.Define(stage, "/World/Cylinder")
cylinder.AddTranslateOp().Set(value=(-5, 0, 0), time=0)
cylinder.AddTranslateOp().Set(value=(-10, 0, 0), time=24)
# Save the stage
stage.GetRootLayer().Save()
This example creates a scene with three objects—a cube, a sphere, and a cylinder—that move along different axes over time. Each object is animated with TimeSamples, giving them smooth movements over the course of 24 frames.
15. USD Shading and Hydra
USD also provides a robust framework for assigning materials and shaders to objects. Hydra, a part of USD, is a high-performance rendering engine that works with USD data to visualize scenes in real-time.
Introduction to Hydra
Hydra is designed for interactive real-time rendering of USD scenes. It uses a scene graph to manage geometry, lights, and materials, rendering them in an efficient way that supports parallel computation and can display complex scenes in real-time.
Applying Shaders in USD
Materials in USD are defined using the UsdShade API, which allows you to apply different shaders to your objects.
from pxr import Usd, UsdShade
# Create a material for the cube
material = UsdShade.Material.Define(stage, "/World/Materials/CubeMaterial")
# Create a shader for the material
shader = UsdShade.Shader.Define(stage, "/World/Materials/CubeMaterial/Shader")
shader.CreateIdAttr("UsdPreviewSurface")
# Assign the shader to the material
material.CreateSurfaceOutput().ConnectToSource(shader.ConnectableAPI(), "outputs:surface")
# Bind the material to the cube
UsdShade.MaterialBindingAPI(cube).Bind(material)
This example creates a new material for the cube and applies a basic UsdPreviewSurface shader, which is part of USD's preview shader system for Hydra. The material is then bound to the cube geometry.
Visualizing the Scene with Hydra
You can visualize the scene using Hydra's built-in real-time renderer, such as Storm or Arnold, in software like Maya, Houdini, or the standalone USD viewer.
16. Advanced USD: Introduction to USD Skel

USD Skel is Pixar's skeletal animation framework that supports rigging and character animation in USD. It allows for the definition of skeletal joints, skinning, and animation clips, making it possible to animate characters directly in USD.
Understanding Skeletons in USD
USD Skel defines characters using two main components:
Skeleton: The hierarchy of joints that define the character's rig.
Skinning: The process of binding the character’s geometry to the skeleton.
Example: Creating a Simple Rig
from pxr import Usd, UsdSkel
# Create a new stage
stage = Usd.Stage.CreateNew("simple_skeleton.usda")
# Define a skeleton
skeleton = UsdSkel.Skeleton.Define(stage, "/World/Character/Skeleton")
# Create joints for the skeleton
joints = ["Root", "Spine", "Head"]
skeleton.CreateJointsAttr(joints)
# Set joint transforms (in local space)
skeleton.CreateBindTransformsAttr([((0, 0, 0), (0, 0, 0)), ((0, 1, 0), (0, 0, 0)), ((0, 2, 0), (0, 0, 0))])
# Save the stage
stage.GetRootLayer().Save()
This example creates a simple skeleton with three joints (Root, Spine, and Head). Each joint has a local transform that determines its position relative to its parent joint.
Animating a Rigged Character
USD Skel allows you to animate a rigged character by applying skinning and animation clips to the skeleton, deforming the character’s geometry over time.
17. Optimizing USD for Large-Scale Productions
When working with large-scale productions involving many assets, USD offers several strategies for optimizing performance.
Caching and Layer Streaming
USD supports efficient scene loading by using layer streaming, which only loads the necessary assets into memory at any given time. This is crucial for handling scenes with hundreds or thousands of assets.
Memory Optimization Techniques
To reduce memory consumption:
Use usdzip to compress USD files: USDZ files package multiple assets into a single file with compression, reducing disk and memory usage.
Layer Muting: Temporarily disable layers that aren't necessary for the current task to reduce memory usage.
Instanceable References: Use instances for duplicated objects (such as trees or rocks in a scene), which USD can optimize to avoid loading the same data multiple times.
18. USD for Collaborative and Cloud-Based Workflows
USD's robust scene description system is built for collaboration, allowing multiple artists or technical directors to work on the same scene simultaneously without overwriting each other's work.
USD in a Pipeline
In a typical USD pipeline:
Modelers create and export assets in USD format.
Animators reference those assets and animate them using USD’s animation framework.
Lighting and Shading Artists apply shaders and materials in USD, assembling everything into the final shot.
USD in the Cloud
Many studios are now adopting cloud-based workflows where USD files are stored on cloud services like AWS or Google Cloud. This enables multiple teams from different locations to work together in real-time, sharing assets and scene data without having to pass large files back and forth.
Conclusion
Universal Scene Description (USD) is a revolutionary tool for managing 3D scenes in animation, VFX, and beyond. From simple primitives and animation to complex skeletal rigs and collaborative workflows, USD offers unparalleled flexibility, performance, and interoperability across various digital content creation tools.
This guide has introduced you to the core concepts of USD, providing practical examples and insights into how you can use USD in your production pipeline. Whether you're building small assets or massive environments, USD gives you the tools to scale your work, collaborate with teams, and bring your creative vision to life.