Prims#

Welcome to this lesson on OpenUSD prims. In this lesson, we will:

  • Identify the role of prims, including what a prim is and its role within a OpenUSD stage.

What is a Prim?#

Primitives, or prims for short, are the building blocks of any OpenUSD scene, making understanding them essential for anyone working with 3D content creation and manipulation in the OpenUSD ecosystem.

A prim is the core component within the USD framework. Think of a prim as a container that holds various types of data, attributes, and relationships which define an object or entity within a scene. A prim can be a type of visual or non-visual entity, such as a mesh, a material, or a light or an xform. Prims are organized in a hierarchical structure, creating a scenegraph that represents the relationships and transformations between objects in the scene.

Each prim has a unique identifier known as a path, which helps in locating it within the scene graph. For example, a prim’s path might be /World/BuildingA/Geometry/building_geo, indicating that it is a child of the Geometry prim, which itself is a child of the BuildingA prim, and so on.

How Does It Work?#

Prims can have various types of attributes associated with them, such as position, rotation, scale, material information, animation data, and more. These properties define the attributes and relationships of the objects they represent.

A key feature of USD prims is their ability to encapsulate data, allowing them to be shared, referenced, and instanced across different scenes and files. This promotes efficient data management, modularity, and collaborative workflows. Typical use cases include defining models, cameras, lights, or even groups of other prims. The ability to efficiently manage and manipulate these prims non-destructively is what makes USD so powerful in various industries where complex scenes are the norm.

Working With Python#

In Python, working with prims involves several methods using the USD Python API:

 1# Generic USD API command. Used to define a new prim on a stage at a specified path, and optionally the type of prim.
 2stage.DefinePrim(path, prim_type)
 3
 4# Specific to UsdGeom schema. Used to define a new prim on a USD stage at a specified path of type Xform. 
 5UsdGeom.Xform.Define(stage, path)
 6	
 7# Retrieves the children of a prim. Useful for navigating through the scenegraph.
 8prim.GetChildren()
 9	
10# Returns the type of the prim, helping identify what kind of data the prim contains.
11prim.GetTypeName()
12
13# Returns all properties of the prim.
14prim.GetProperties()

Examples#

Example 1: Defining a Prim#

A prim is the primary container object in USD. It can contain other prims and properties holding data.

To create a generic prim on the stage we use DefinePrim(). By default, the prim will be typeless meaning that it’s just an empty container. By introducing a prim type, we can begin to dictate what kind of data the prim contains depending on if it is a prim to represent a cube, a light, a mesh, etc.

 1# Import the `Usd` module from the `pxr` package:
 2from pxr import Usd
 3
 4# Create a new USD stage with root layer named "prims.usda":
 5stage: Usd.Stage = Usd.Stage.CreateNew("_assets/prims.usda")
 6
 7# Define a new primitive at the path "/hello" on the current stage:
 8stage.DefinePrim("/hello")
 9
10# Define a new primitive at the path "/world" on the current stage with the prim type, Sphere.
11stage.DefinePrim("/world", "Sphere")
12
13stage.Save()
Loading your model...
_assets/prims.usda
        
    

Note in the USDA output that the prim with the name “hello” does not have a type, but the prim named “world” has the type, Sphere.

Example 2: Defining a Sphere Prim#

While the DefinePrim() API provides a generic way to create any type of prim. Many prim types have specific API to create and interact with them.

 1from pxr import Usd, UsdGeom
 2
 3file_path = "_assets/sphere_prim.usda"
 4stage: Usd.Stage = Usd.Stage.CreateNew(file_path)
 5
 6# Define a prim of type `Sphere` at path `/hello`:
 7sphere: UsdGeom.Sphere = UsdGeom.Sphere.Define(stage, "/hello")
 8sphere.CreateRadiusAttr().Set(2)
 9
10# Save the stage:
11stage.Save()
Loading your model...
_assets/sphere_prim.usda
        
    

In this example, we used the UsdGeom.Sphere class to create a Sphere type prim and set some data about that sphere. We set there sphere’s radius to 5. Using the UsdGeom.Sphere class provides a more transparent interface for the Sphere prim type.

Example 3: Creating a Prim Hierarchy#

Prims can contain other prims to create a namespace hierarchy.

 1from pxr import Usd, UsdGeom
 2
 3file_path = "_assets/prim_hierarchy.usda"
 4stage: Usd.Stage = Usd.Stage.CreateNew(file_path)
 5
 6# Define a Scope prim in stage at `/Geometry`
 7geom_scope: UsdGeom.Scope = UsdGeom.Scope.Define(stage, "/Geometry")
 8# Define an Xform prim in the stage as a child of /Geometry called GroupTransform
 9xform: UsdGeom.Xform = UsdGeom.Xform.Define(stage, geom_scope.GetPath().AppendPath("GroupTransform"))
10# Define a Cube in the stage as a child of /Geometry/GroupTransform, called Box
11cube: UsdGeom.Cube = UsdGeom.Cube.Define(stage, xform.GetPath().AppendPath("Box"))
12
13stage.Save()
Loading your model...
_assets/prim_hierarchy.usda
        
    

The prim hierarchy that we have created is:

  • Geometry

    • GroupTransform

      • Cube

By nesting prims in this way, a hierarchical scenegraph begins to take shape. In this example, “Geometry” is the root prim. We are also defining three different types of prims here: Scope, Xform, and Cube. We will look at these prim types more closely in other lessons, but for a brief description:

  • Xform: Defines a transform (translate, rotation, scale)

  • Scope: Is a simple container that does not hold transform data

  • Cube: Defines a primitive rectilinear cube

Example 4: Does the Prim Exist?#

When working with large amounts of data it is key to make sure that a prim exists before trying to override it. We can get the child of a prim using GetChild(). If it was unable to find the child, it will return an invalid UsdPrim. An invalid prim will evaluate as False when treated as a boolean. You can use Usd.Object.IsValid() to check if the prim is valid or exists.

 1from pxr import Usd
 2
 3file_path = "_assets/prim_hierarchy.usda"
 4stage: Usd.Stage = Usd.Stage.Open(file_path)
 5
 6prim: Usd.Prim = stage.GetPrimAtPath("/Geometry")
 7child_prim: Usd.Prim
 8if child_prim := prim.GetChild("Box"):
 9    print("Child prim exists")
10else:
11    print("Child prim DOES NOT exist")
Child prim DOES NOT exist

Here is the USDA output of _assets/prim_hierarchy.usda to verify.

        
    

Box is not a child of Geometry. If we change Box to GroupTransform then it will print out “Child prim exists”. That is because GetChild() only returns the direct child of the prim, not nested children.

 1from pxr import Usd
 2
 3file_path = "_assets/prim_hierarchy.usda"
 4stage: Usd.Stage = Usd.Stage.Open(file_path)
 5
 6prim: Usd.Prim = stage.GetPrimAtPath("/Geometry")
 7child_prim: Usd.Prim
 8if child_prim := prim.GetChild("GroupTransform"):
 9    print("Child prim exists")
10else:
11    print("Child prim DOES NOT exist")
Child prim exists

Here is the USDA output of _assets/prim_hierarchy.usda to verify.

        
    

Key Takeaways#

In this lesson, we covered what a prim is in the context of OpenUSD, its characteristics, and its role in building and managing 3D scenes. We also looked at how prims facilitate data encapsulation and sharing, which are critical for complex 3D project workflows. Understanding prims is foundational as we start working with OpenUSD.