Prim and Property Paths#

What Is a Path?#

In OpenUSD, a path represents the location of a prim or property within a scenegraph. The string representation for a prim path consists of a sequence of prim names separated by forward slashes (/), similar to file paths in a directory structure. The stage pseudo-root, which serves as the starting point for the hierarchy, is represented by a forward slash (/).

For example, the path /World/Geometry/Box represents a prim named Box that is a child of a prim named Geometry, which is a child of the root prim named World.

How Does It Work?#

Paths in OpenUSD are handled through the pxr.Sdf.Path class to encode path data including prims, properties (both attributes and relationships), and variants.

Prims are indicated by a slash separator, which indicates the namespace (e.g. "/geo/box")

Period separators after an identifier is used to introduce a property (ex: "/geo/box.weight")

Variants are indicated by curly brackets, like this: (ex. "/geo/box{size=large}")

They are used to:

  1. Uniquely identify prims and properties. Each prim and property in a scene has a unique path that distinguishes it from other prims and properties.

  2. Navigate the scene hierarchy. Paths allow you to traverse the scene hierarchy via the USD stage and access specific prims.

  3. Specify locations for authoring. When creating or modifying prims, paths are used to specify where the prims should be placed in the hierarchy on the USD stage.

  4. Query and filter prims. Paths can be used to filter and select specific prims based on their location in the hierarchy using Sdf.PathExpression.

Working With Python#

Here are a few Python functions relevant to paths in OpenUSD.

1# Import the Sdf class
2from pxr import Sdf
3
4# Return the path of a Usd.Prim as an Sdf.Path object
5Usd.Prim.GetPath()
6
7# Retrieve a Usd.Prim at the specified path from the Stage
8Usd.Stage.GetPrimAtPath()

Examples#

Example 1: Getting, Validating, and Defining Prims at Path#

Each prim has a path to describe its location in namespace.

For example, we defined a prim hello at path /hello and another prim world at path /hello/world.

We can retrieve prims using their path using GetPrimAtPath(). This will either return a valid or invalid prim. When using GetPrimAtPath() we should always check if the returned prim is valid before using it.

To check if a prim is valid we can use the IsValid() method. Valid means that the prim exists in the stage. Invalid is when the prim does not exist in the stage or when the path is invalid.

 1from pxr import Usd
 2
 3stage: Usd.Stage = Usd.Stage.CreateNew("_assets/paths.usda")
 4stage.DefinePrim("/hello")
 5stage.DefinePrim("/hello/world")
 6
 7# Get the primitive at the path "/hello" from the current stage
 8hello_prim: Usd.Prim = stage.GetPrimAtPath("/hello")
 9
10# Get the primitive at the path "/hello/world" from the current stage
11hello_world_prim: Usd.Prim = stage.GetPrimAtPath("/hello/world")
12
13# Get the primitive at the path "/world" from the current stage
14# Note: This will return an invalid prim because "/world" does not exist, but if changed to "/hello/world" it will return a valid prim
15world_prim: Usd.Prim = stage.GetPrimAtPath("/world")
16
17# Print whether the primitive is valid
18print("Is /hello a valid prim? ", hello_prim.IsValid())
19print("Is /hello/world a valid prim? ", hello_world_prim.IsValid())
20print("Is /world a valid prim? ", world_prim.IsValid())
21
22stage.Save()
Is /hello a valid prim?  True
Is /hello/world a valid prim?  True
Is /world a valid prim?  False
        
    

Example 2: Build and navigate prim paths with Sdf.Path#

Construct prim paths with AppendChild, then validate and navigate them with IsPrimPath and GetParentPath

 1from pxr import Usd, UsdGeom, Sdf
 2
 3stage = Usd.Stage.CreateNew("_assets/paths_build_and_nav.usda")
 4
 5# Build prim paths via Sdf.Path
 6world_path = Sdf.Path("/World")
 7geometry_path = world_path.AppendChild("Geometry")  # /World/Geometry
 8sphere_path = geometry_path.AppendChild("Sphere")  # /World/Geometry/Sphere
 9
10looks_path = world_path.AppendChild("Looks")  # /World/Looks
11material_path = looks_path.AppendChild("Material")  # /World/Looks/Material
12
13# Define prims at those paths
14stage.DefinePrim(world_path)
15stage.DefinePrim(geometry_path)
16UsdGeom.Sphere.Define(stage, sphere_path)
17stage.DefinePrim(looks_path)
18stage.DefinePrim(material_path)
19
20# Path checks and basic navigation
21print("sphere_path IsPrimPath:", sphere_path.IsPrimPath())
22print("sphere_path parent:",    sphere_path.GetParentPath())
23print("Geometry prim valid:",   stage.GetPrimAtPath(geometry_path).IsValid())
24print("\nmaterial_path IsPrimPath:", material_path.IsPrimPath())
25print("material_path parent:",    material_path.GetParentPath())
26print("Looks prim valid:",   stage.GetPrimAtPath(looks_path).IsValid())
27
28stage.Save()
sphere_path IsPrimPath: True
sphere_path parent: /World/Geometry
Geometry prim valid: True

material_path IsPrimPath: True
material_path parent: /World/Looks
Looks prim valid: True
        
    

Example 3: Author an attribute and a relationship from property paths#

A property path identifies a property location but does not create anything by itself. You use AppendProperty to build the path, then author the spec with CreateAttribute or CreateRelationship

 1from pxr import Usd, UsdGeom, Sdf
 2
 3stage = Usd.Stage.CreateNew("_assets/paths_property_authoring.usda")
 4
 5# A prim to work with
 6sphere = UsdGeom.Sphere.Define(stage, "/World/Geom/Sphere")
 7
 8# Create a property path for the attribute /World/Geom/Sphere.userProperties:tag
 9attr_property_path = sphere.GetPath().AppendProperty("userProperties:tag")
10
11# Working with the property path for the attribute
12owner_prim = stage.GetPrimAtPath(attr_property_path.GetPrimPath())
13attr_name = stage.GetPropertyAtPath(attr_property_path).GetPath().name  # "userProperties:tag"
14print(f"Attribute property '{attr_name}' has been defined on {owner_prim.GetPath()} after AppendProperty: {owner_prim.GetAttribute(attr_name).IsDefined()}")
15
16# Define the attribute on the owner prim
17attr = owner_prim.CreateAttribute(attr_name, Sdf.ValueTypeNames.String)
18print(f"\nAttribute property '{attr_name}' has been defined on {owner_prim.GetPath()} after CreateAttribute: {owner_prim.GetAttribute(attr_name).IsDefined()}")
19
20attr.Set("surveyed")
21print(f"Attribute value after Set: {stage.GetAttributeAtPath(attr_property_path).Get()}")
22
23# Create a relationship from a property path
24marker = UsdGeom.Xform.Define(stage, "/World/Markers/MarkerA")
25# Create a property path for the relationship
26rel_property_path = sphere.GetPath().AppendProperty("my:ref")  # /World/Geom/Sphere.my:ref
27
28# Working with the property path for the relationship
29owner_prim = stage.GetPrimAtPath(rel_property_path.GetPrimPath())
30rel_name = stage.GetPropertyAtPath(rel_property_path).GetPath().name  # "my:ref"
31print(f"\nRelationship property '{rel_name}' has been defined on {owner_prim.GetPath()} after AppendProperty: {owner_prim.GetRelationship(rel_name).IsDefined()}")
32
33# Define the relationship on the owner prim
34rel = owner_prim.CreateRelationship(rel_name)
35print(f"\nRelationship property '{rel_name}' has been defined on {owner_prim.GetPath()} after CreateRelationship: {owner_prim.GetRelationship(rel_name).IsDefined()}")
36
37rel.AddTarget(marker.GetPath())
38print(f"Relationship targets after AddTarget: {[str(p) for p in stage.GetRelationshipAtPath(rel_property_path).GetTargets()]}")
39
40stage.Save()
Attribute property 'userProperties:tag' has been defined on /World/Geom/Sphere after AppendProperty: False

Attribute property 'userProperties:tag' has been defined on /World/Geom/Sphere after CreateAttribute: True
Attribute value after Set: surveyed

Relationship property 'my:ref' has been defined on /World/Geom/Sphere after AppendProperty: False

Relationship property 'my:ref' has been defined on /World/Geom/Sphere after CreateRelationship: True
Relationship targets after AddTarget: ['/World/Markers/MarkerA']
        
    

Key Takeaways#

Using Sdf.Path objects in OpenUSD provides a way to uniquely identify and locate objects (prims) within our scene hierarchy. We will use paths for authoring, querying, and navigating USD data effectively.