Stage Traversal#
What is Stage Traversal?#
Stage traversal is the process of traversing the scenegraph of a stage with the purpose of querying or editing the scene data. We can traverse the scenegraph by iterating through child prims, accessing parent prims, and traversing the hierarchy to find specific prims of interest.
How Does It Work?#
Traversing stages works via the Usd.PrimRange
iterator. Other methods like Usd.Stage.Traverse
return a Usd.PrimRange
iterator. The difference is that Usd.PrimRange
takes a starting prim as an argument and Usd.Stage.Traverse
starts it’s traversal from the stage’s pseudo-root.
Traversals operate by walking prim by prim in depth-first order. You can use predicates and Usd.PrimRange.PruneChildren
to optimize your traversals if you know you don’t need to visit certain branches.
There are two traversal modes:
Default: Iterate over child prims
PreAndPostVisit: Iterate over the hierarchy and visit each prim twice, once when first encountering it, and then again when “exiting” the child hierarchy.
There are also predicates which can be used for pre-filtering the result:
Usd.PrimIsActive
If the active metadata is
True
Analogous to
Usd.Prim.IsActive()
Usd.PrimIsLoaded
If the (ancestor) payload is loaded
Analogous to
Usd.Prim.IsLoaded()
Usd.PrimIsModel
If the kind is a sub kind of
Kind.Tokens.model
Analogous to
Usd.Prim.IsModel()
Usd.PrimIsGroup
If the kind is
Kind.Tokens.group
Analogous to
Usd.Prim.IsGroup()
Usd.PrimIsAbstract
If the prim specifier is
Sdf.SpecifierClass
Analogous to
Usd.Prim.IsAbstract()
Usd.PrimIsDefined
If the prim specifier is
Sdf.SpecifierDef
Analogous to
Usd.Prim.IsDefined()
Working With Python#
1# This yields all active, loaded, defined, non-abstract prims on this stage depth-first
2Usd.Stage.Traverse()
3
4# Traverse all prims in the stage
5Usd.Stage.TraverseAll()
6
7# Predicates are combined used bitwise operators
8predicate = Usd.PrimIsActive & Usd.PrimIsLoaded
9
10# Traverse starting from the given prim and based on the predicate for filtering the traversal
11Usd.PrimRange(prim, predicate=predicate)
12
13# You must use iter() to invoke iterator methods like Usd.PrimRange.PruneChildren()
14it = iter(Usd.PrimRange.Stage(stage))
15for prim in it:
16 if prim.GetName() == "Environment":
17 prim_range.PruneChildren() # Skip all children of "Environment"
Examples#
For reference, this the USDA for the stage that we will be using in the following examples:
Example 1: Traversing Through the Stage#
To traverse through the stage, we can use the Traverse()
method. This traversal will yield prims that are active, loaded, defined, non-abstract on the stage in depth-first order.
1# Import the Usd module from the pxr package
2from pxr import Usd
3
4# Open the USD stage from the specified file
5stage: Usd.Stage = Usd.Stage.Open("_assets/stage_traversal.usda")
6
7# Traverse and print the paths for the visited prims
8for prim in stage.Traverse():
9 # Print the path of each prim
10 print(prim.GetPath())
/World
/World/Box
/World/Box/Geometry
/World/Box/Geometry/Cube
/World/Box/Materials
/World/Box/Materials/BoxMat
/World/Environment
/World/Environment/SkyLight
Note how the prims were printed in depth-first order. All of the descendants of /World/Box
appear before /World/Environment
and its descendants.
Example 2: Traversing USD Content for Specific Prim Types#
For this practical example, we will traverse the stage to operate on specific prims based on their types.
We can filter based on the type of the prim. For example, we can check if the prim is of type scope
or xform
. To do this we pass the prim into the constructor method for the prim type we are interested in. For example,UsdGeom.Scope(prim)
is equivalent to UsdGeom.Scope.Get(prim.GetStage(), prim.GetPath())
for a valid prim. If the prim’s type does not match, it will return an invalid prim.
1# Import necessary modules from the pxr package
2from pxr import Usd, UsdGeom
3
4# Open the USD stage from the specified file
5stage: Usd.Stage = Usd.Stage.Open("_assets/stage_traversal.usda")
6
7scope_count = 0
8xform_count = 0
9# Traverse through each prim in the stage
10for prim in stage.Traverse():
11 # Check if the prim is of type Scope
12 if UsdGeom.Scope(prim):
13 scope_count += 1
14 print("Scope Type: ", prim.GetName())
15 # Check if the prim is of type Xform
16 elif UsdGeom.Xform(prim):
17 xform_count +=1
18 print("Xform Type: ", prim.GetName())
19
20print("Number of Scope prims: ", scope_count)
21print("Number of Xform prims: ", xform_count)
Xform Type: World
Xform Type: Box
Scope Type: Geometry
Scope Type: Materials
Scope Type: Environment
Number of Scope prims: 3
Number of Xform prims: 2
Example 3: Traversing Through the Children of a Prim#
Using Traverse()
can be a powerful tool, but for large stages, more efficient and targeted methods should be considered. A way to be more efficient and targeted is to traverse through the children of a prim.
If you need to work within a specific scope or hierarchy in the stage, you can perform a traversal starting from a particular prim. Let’s take a look at how we can traverse through the children of the default prim.
1# Import the `Usd` module from the `pxr` package:
2from pxr import Usd
3
4# Open the USD stage from the specified file:
5stage: Usd.Stage = Usd.Stage.Open("_assets/stage_traversal.usda")
6
7# Get the default prim of the stage (/World in this case):
8default_prim: Usd.Prim = stage.GetDefaultPrim()
9
10# Iterate through all children of the default prim
11for child in default_prim.GetAllChildren():
12 # Print the path of each child prim
13 print(child.GetPath())
/World/Box
/World/Environment
Example 4: Traversing Using Usd.PrimRange#
Traverse()
will return a UsdPrimRange
object. UsdPrimRange
exposes pre- and post- prim visitations allowing for a more involved traversals. It can also be used to perform actions such as pruning subtrees.
Let’s see an example of UsdPrimRange
in use.
1# Import the Usd module from the pxr package
2from pxr import Usd
3
4# Open the USD stage from the specified file
5stage: Usd.Stage = Usd.Stage.Open("_assets/stage_traversal.usda")
6
7prim_range = Usd.PrimRange(stage.GetPrimAtPath("/World/Box"))
8for prim in prim_range:
9 print(prim.GetPath())
/World/Box
/World/Box/Geometry
/World/Box/Geometry/Cube
/World/Box/Materials
/World/Box/Materials/BoxMat
Note how only “/World/Box” and its descendants are printed.
There are other ways to use UsdPrimRange
such as passing in predicates
, you can find more information in the Using Usd.PrimRange in Python section of UsdPrimRange
.
Key Takeaways#
Traversal is how we navigate the scenegraph and query scene data. Traversal can be made more efficient by limiting the number of prims it visits.