By Juliana Faux, Andrés Escobar and Santiago Ferreiros

In this blog, we introduce Universal Scene Description (USD), a powerful framework that has become a foundation for 3D content creation and collaboration. We explore how USD enables seamless integration of tools and workflows, revolutionizing industries from film and game production to robotics and AI simulation. By showcasing its role within NVIDIA Omniverse and Isaac Sim, we’ll highlight the transformative potential of USD in building immersive, scalable, and collaborative 3D environments.

Leadtek AI Forum - 5 Things to Know About USD (Universal Scene Description)

Universal Scene Description (USD)

Pipelines capable of producing computer graphics films and games typically generate, store, and transmit large quantities of 3D data, which we call “scene description”. Each of many cooperating applications in the pipeline (modeling, shading, animation, lighting, fx, rendering) typically has its own special form of scene description tailored to the specific needs and workflows of the application, which is neither readable nor editable by any other application. Pixar introduced Universal Scene Description (USD) as the first publicly available software to robustly and scalably interchange and augment arbitrary 3D scenes. 

 

USD organizes information in a structured way using building blocks called Prims. Each Prim can hold data called Attributes and Relationships to other Prims, known as Properties. Relationships define hierarchies or dependencies. All these Prims and their contents are grouped together in a file structure called a Layer. Layers allow different people to simultaneously work on the same asset or scene, by allowing each artist to work in their own file. A Stage is the result of combining different layers.

Simulation of a cluttered warehouse.

 

USD Glossary

Prims

A Prim refers to a fundamental building block or element of a scene within the USD framework. Prim is short for “primitive,” and it represents an individual object or entity within the scene hierarchy.

A USD prim can be thought of as a container that holds various types of data, attributes, and relationships. It represents a specific object or component in a scene, such as a model, camera, light, or even a group of other prims. Prims are organized in a hierarchical structure, forming a scene graph that represents the relationships and transformations between objects in the scene.

Each prim in USD has a unique identifier, known as a path, which identifies its location within the scene graph. The path typically includes the names of all the parent prims leading to the specific prim. For example, a prim’s path might be “/World/Characters/CharacterA,” indicating that it is a child of the “CharacterA” prim, which itself is a child of the “Characters” prim, and so on.

Prims hold various attributes, such as position, rotation, scale, material information, and animation data. These attributes define the properties and characteristics of the objects they represent.

In summary, a USD prim represents an individual object or component within a scene in the Universal Scene Description framework. It serves as a container for data, attributes, and relationships, forming a part of the scene graph. Prims are organized hierarchically, have unique paths, and allow for efficient encapsulation and sharing of data within the OpenUSD ecosystem.

Screenshot from 2022-10-04 20-11-18

Prim types

Prims have a type, which come with default behavior and data. Some of them are:

  • Camera Prim: represents a camera, with properties such as focal length, lens aperture, etc.
  • Light Prim: represents different types of light (e.g. DistantLight, which represents light emitted from a distant source along the Z axis, like the sun).
  • Xform: represents a transformation in the space (translation, rotation and/or scaling).
  • Material Prim: represents superficial properties of objects.

Layer

A Layer is a collection of Prims and their Properties that can be saved to/loaded from disk or memory. As such, it can be considered a “saveable hierarchy”.

Diagram of USD.

Stage

The composed result of opening a layer. All layers interact with one another to produce a “final image”. The layers still exist, they can still be edited, deleted, replaced, etc… but what you see is the result, and that is the Stage in USD.

Example: A Park Scene

  • Prim for a Tree
    • Attributes: This tree Prim has attributes like height (10 feet) and color (green). These values can change over time, such as when the tree grows or during seasonal changes, like turning brown in the fall.
    • Relationships: The tree may have relationships pointing to a ground Prim, indicating where it is planted.
  • Prim for a Bench
    • Attributes: This bench Prim could have attributes such as material (wood) and size (6 feet long).
    • Relationships: It might also link to a location Prim that specifies its exact position in the park.

All these Prims—like the tree and the bench—along with their details, are organized within a Layer. This structure makes it easy to manage and update the scene. By combining different layers, you create a comprehensive representation known as the Stage.

Digital Assets

3D assets are the essential components of a digital twin, representing digital objects with accurate shapes, materials, lighting, physics, and relevant behaviors. These assets can also incorporate real-time data streams from internal or external sources, similar to physical objects equipped with sensors and IoT devices.

In NVIDIA Omniverse, Pixar’s open-source Universal Scene Description (USD) serves as the primary format for asset representation. USD offers a robust scene description framework with an API that supports complex property inheritance, instancing, layering, lazy loading, and a variety of other key features. Additionally, Omniverse allows the creation of different “variants” for each asset, enabling the randomization of an asset’s appearance, position, orientation, and behavior to achieve more realistic scenes.

Diagram of all asset types.

Assets can be imported from Omniverse’s extensive asset libraries or created using external content creation tools and integrated into the Omniverse ecosystem. NVIDIA Omniverse™ provides all the necessary tools to quickly and easily convert assets to and from USD. Moreover, Omniverse offers a comprehensive library of industry-specific USD assets that you and your team can utilize to build your digital twin. For more information about assets and Omniverse support, click here.

 

3D assets

3D assets are the essential components of a digital twin, representing digital objects with accurate shapes, materials, lighting, physics, and relevant behaviors. These assets can also incorporate real-time data streams from internal or external sources, similar to physical objects equipped with sensors and IoT devices.

In NVIDIA Omniverse, Pixar’s open-source Universal Scene Description (USD) serves as the primary format for asset representation. USD offers a robust scene description framework with an API that supports complex property inheritance, instancing, layering, lazy loading, and a variety of other key features. Additionally, Omniverse allows the creation of different “variants” for each asset, enabling the randomization of an asset’s appearance, position, orientation, and behavior to achieve more realistic scenes.

Instructions for viewing NVIDIA assets.

Assets can be imported from Omniverse’s extensive asset libraries or created using external content creation tools and integrated into the Omniverse ecosystem. NVIDIA Omniverse™ provides all the necessary tools to quickly and easily convert assets to and from USD. Moreover, Omniverse offers a comprehensive library of industry-specific USD assets that you and your team can utilize to build your digital twin. For more information about assets and Omniverse support, click here.

 

Introduction to USD in Python

Before reading this section, is it strongly recommended to first read Exploring NVIDIA Omniverse and Isaac Sim

 

pxr and omni.usd

In Python, you can work with USD using the usd-core package, which is imported as pxr (Pixar). Additionally, Omniverse builds on this by providing its own version called omni.usd, specifically designed for development within the Omniverse environment.

While pxr and omni.usd are interchangeable, omni.usd is tailored for Omniverse. It serves to load and initialize pxr and Omniverse USD Resolver that supports opening USD from Omniverse/HTTP urls. You will likely need to use both pxr and omni.usd, depending on your specific goals and requirements.

Code examples

Move a prim

The following code snippets demonstrate how to load an existing stage, retrieve a primitive (prim), and move it. Since there are multiple methods to achieve this, examples are provided using both pxr and omni.usd. Additionally, there is a note on how to use omni.usd in headless mode.

Using pxr
from pxr import Usd, Gf

# Open stage
stage = Usd.Stage.Open('./path/test.usd')

# Get the prim in prim_path
prim_path = "/World/My_prim"
my_prim = stage.GetPrimAtPath(prim_path)

if not my_prim.IsValid():
    print(f"The prim at '{prim_path}' does not exist.")
else:
    print(f"The prim at '{prim_path}' exist.")

# Get its position as a GfVec3d
prim_pos = my_prim.GetAttribute("xformOp:translate").Get(0)

# # Define new position
step = Gf.Vec3d(1, 1, 1)
new_pos = prim_pos + step

# # Set its position to the new position
success = my_prim.GetAttribute("xformOp:translate").Set(new_pos, 0)

Notice that when reading/writing the position of my_prim, we are getting the Attribute “translate” of a xformOp under my_prim. “.Get(0)” and “.Set(0)” refer to the fact that an XForm may contain several “translate” operations, and we are getting/setting only the first one. 

Using omni.usd

The following code assumes the stage was previously opened in Omniverse. 

import omni.usd
from pxr import Gf, UsdGeom

# Get default context
context = omni.usd.get_context()

# Open current stage
stage = context.get_stage()

# List all prims to confirm structure
for prim in stage.Traverse():
    print(prim.GetPath())

# Get the prim in prim_path
prim_path = "/World/My_prim"
my_prim = stage.GetPrimAtPath(prim_path)

if my_prim.IsValid():
    print("The prim is valid and it was found")
else:
    print("The prim is not valid or not exist in the scene.")

# Get its position as a GfVec3d
prim_pos = my_prim.GetAttribute("xformOp:translate").Get(0)

# # Define new position
step = Gf.Vec3d(0.5, 0.5, 0.5)
new_pos = prim_pos + step

# # Set its position to the new position
success = my_prim.GetAttribute("xformOp:translate").Set(new_pos, 0)

omni.usd also has a set_prop_val function that could be used for this purpose.

Using omni.usd in headless mode

If the stage wasn’t previously loaded (for example, when working in headless mode), it is necessary to first launch the Omniverse Toolkit using a helper class called SimulationApp.

from omni.isaac.kit import SimulationApp
from omni.isaac.core.utils.stage import open_stage

# Launch Omniverse Toolkit - choosing to run headless
simulation_app = SimulationApp({"headless": True})

# Load stage
stage_path = "C:\Users\ov-user\test.usd"
open_stage(stage_path)

# Get prim in prim path
from omni.isaac.core.utils import prims
prim_path = "World/my_prim"
my_prim = prims.get_prim_at_path(prim_path)

# Do something
# ...

# Close SimulationApp
simulation_app.close()

 

For similar blogs please visit Marvik Blogs.

Shape
Get in touch with one of our specialists. Let's discover how can we help you.
Training, developing and delivering machine learning models into production
Document