USD

Opening USD Stages

Working with USD Stages is straightforward, as most times everything is one function call away.

To load a USD file as a USD Stage you use Usd.Stage.Open(path):

Note that this does not load the scene into Kit! (see omni.usd docs for this)

from pxr import Usd
from omni.kit.usd_docs import single_prim_usda

stage = Usd.Stage.Open(single_prim_usda)
print (f"opened stage {stage}")

To create a new Stage use Usd.Stage.CreateNew(path);

from pxr import Usd

stage = Usd.Stage.CreateNew('a_new_stage.usd')
print (f"created stage {stage}")

To save a loaded Stage use Usd.Stage.Save(path)

from pxr import Usd
from omni.kit.usd_docs import single_prim_usda

stage = Usd.Stage.Open(single_prim_usda)

# do something to the stage
stage.Save()
print (f"saved stage {stage}")

To export a stage to a new file, you can use Usd.Stage.Export(). This function allows you to transition between serialization formats (usda or usdc) as well, based on the file extension provided.

from pxr import Usd
from omni.kit.usd_docs import single_prim_usda

stage = Usd.Stage.Open(single_prim_usda)
# do something to the stage
stage.Export('a_usdc_file.usdc')
print (f"exported stage {stage}")

Prims, Attributes and Metadata

Prims

Working with Prims is a more complicated since Prims are extremely powerful objects in USD. Prims are referenced by their path in the stage, which is a string in the form of /Prim/ChildPrim. / is a special prim known as the root prim in a stage.

To get a reference to a prim at a path use stage_ref.GetPrimAtPath(path):

from pxr import Usd
from omni.kit.usd_docs import single_prim_usda

stage_ref = Usd.Stage.Open(single_prim_usda)

prim = stage_ref.GetPrimAtPath('/hello')
print(prim.GetName()) # prints "hello"
print(prim.GetPrimPath()) # prints "/hello"

To define a new prim use stage_ref.DefinePrim(path):

from pxr import Usd
from omni.kit.usd_docs import single_prim_usda

stage_ref = Usd.Stage.Open(single_prim_usda)

prim = stage_ref.DefinePrim('/UnTypedPrim')
print(prim.GetName()) # prints "UnTypedPrim"

To define a new prim with a type use stage_ref.DefinePrim(path, type_name) or you can use your Type’s SomeType.Define(stage_ref, path) method:

from pxr import Usd, UsdGeom
from omni.kit.usd_docs import single_prim_usda

stage_ref = Usd.Stage.Open(single_prim_usda)

prim = stage_ref.DefinePrim('/XformPrim', 'Xform')
# above we have a Usd.Prim, if we want to access all the Xform's types natively, we need to get an Xform instance of our prim
xform = UsdGeom.Xform(prim)

print(xform.GetPath()) # prints "/XformPrim"

# it is often better to use the Define() method of your type right away, since it returns your typed instance rather than a Usd.Prim instance

xform_faster = UsdGeom.Xform.Define(stage_ref, '/AnotherXformPrim')

To delete a prim from the current edit layer (please refer to the documentation about RemovePrim for details) you can use stage_ref.RemovePrim(path):

from pxr import Usd
from omni.kit.usd_docs import single_prim_usda

stage_ref = Usd.Stage.Open(single_prim_usda)
prim = stage_ref.DefinePrim('/UnTypedPrim')

if stage_ref.RemovePrim('/UnTypedPrim'):
    print('/UnTypedPrim removed')

# if you try to access the prim object, it will still reference path but it is expired
if (prim.IsValid()):
    print('{} is valid'.format(prim.GetName()))
else:
    print('{} is not valid'.format(prim.GetName()))

# the above will print "UnTypedPrim is not valid"

Attributes

Attributes are the workhorse of storing actual data inside a Prim. Attributes are often defined as part of Schemas to make it easier to access context-relevant data from within an instance of that Type.

For example, Xform typed Prims have an attribute called Purpose which is used to specify the purpose of an imageable prim. It contains one of the following values: [default, render, proxy, guide]

Now, you could get this attribute’s value in two ways. One, as a generic prim_ref.GetAttribute(name) call, but you would have to know that the exact name of the attribute you want is “purpose”, and you wouldn’t be able to get any code completion in an IDE that way.

The other way is to use the Xform Schema’s exposed function for getting the purpose, which is xform_ref.GetPurposeAttr(), which returns the same object, but will be typed in an IDE and does not depend on the underlying string name of the attribute.

Most often after you get an Attribute object, you will want to get the attribute’s actual value or set it. That can be done with attribute_ref.Get() to retrieve the value, and attribute_ref.Set(value) to set the value.

Note! attribute_ref.Set(value) requires passing the correct type of value as well, refer to table in Working with USD Types below to see how to construct the appropriate type.

Let’s see the code for getting an Attribute reference and getting its value:

from pxr import Usd, UsdGeom
from omni.kit.usd_docs import single_prim_usda

stage_ref = Usd.Stage.Open(single_prim_usda)

# get a reference to the Xform instance as well as a generic Prim instance
xform_ref = UsdGeom.Xform.Define(stage_ref, '/XformPrim')
prim_ref = xform_ref.GetPrim()

# Get an attribute reference (not its value!)
purpose_from_xform_ref = xform_ref.GetPurposeAttr()
purpose_from_prim_ref = prim_ref.GetAttribute('purpose')

print(purpose_from_xform_ref == purpose_from_prim_ref) # prints True

# prints the actual attribute's value, in this case, one of [default, render, proxy, guide], since it is the Xform's actual Purpose attribute
print(purpose_from_xform_ref.Get())

To create an attribute that isn’t part of a Type’s namespace (or it is, but you want to create the attribute “manually”), you must pass the attribute name and its type to prim_ref.CreateAttribute(name, type).

Otherwise, most Types expose a Set -style command, for example xform_ref.SetPurposeAttr(value).

The name of an Attribute is a string. The type system for Attributes (and USD in general) is explained below.

Working with USD Types

The USD API Documentation has a list of USD Basic Data Types that are used for Attribute types. Type Name are provided by the Sdf.ValueTypeNames module, which is a useful resource for reference.

In order to actually pass a valid value for the type for the CreateAttribute(name, type) function, it needs to be a reference to a Sdf.ValueTypeNames.TypeName object. There are three ways of getting these:

  1. The current values and how to construct an object that will function as that value are in a table here for convenience, please refer to the USD Basic Data Types page for an explanation on explicit definitions. [] denotes a list of types. The left column of this list was generated with the method from 1) above.

Note: Gf.Vec3d/f/h instances below can be constructed with just a (float, float, float) tuple (and Vec2d/f/h , Vec4d/f/h as well), but the explicit declaration is passed below for completeness.

Attribute Type Constructor Table

Type Name

Python Constructor

Asset

string

AssetArray

[string]

Bool

bool

BoolArray

[bool]

Color3d

Gf.Vec3d(float, float, float)

Color3dArray

[Gf.Vec3d(float, float, float)]

Color3f

Gf.Vec3f(float, float, float)

Color3fArray

[Gf.Vec3f(float, float, float)]

Color3h

Gf.Vec3h(float, float, float)

Color3hArray

[Gf.Vec3h(float, float, float)]

Color4d

Gf.Vec4d(float, float, float, float)

Color4dArray

[Gf.Vec4d(float, float, float, float)]

Color4f

Gf.Vec4f(float, float, float, float)

Color4fArray

[Gf.Vec4f(float, float, float, float)]

Color4h

Gf.Vec4h(float, float, float, float)

Color4hArray

[Gf.Vec4h(float, float, float, float)]

Double

float

Double2

(float, float)

Double2Array

[(float, float)]

Double3

(float, float, float)

Double3Array

[(float, float, float)]

Double4

(float, float, float, float)

Double4Array

[(float, float, float, float)]

DoubleArray

[float]

DoubleArray

[float]

DoubleArray

[float]

Float

float

Float2

(float, float)

Float2Array

[(float, float)]

Float3

(float, float, float)

Float3Array

[(float, float, float)]

Float4

(float, float, float, float)

Float4Array

[(float, float, float, float)]

FloatArray

[float]

Frame4d

float, float, float, float, float, float, float, float, float, float, float, float, float, float, float, float

Frame4dArray

[Gf.Matrix4d(float, float, float, float, float, float, float, float, float, float, float, float, float, float, float, float)]

Half

float

Half2

(float, float)

Half2Array

[(float, float)]

Half3

(float, float, float)

Half3Array

[(float, float, float)]

Half4

(float, float, float, float)

Half4Array

[(float, float, float, float)]

HalfArray

[float]

Int

int

Int2

(int, int)

Int2Array

[(int, int)]

Int3

(int, int, int)

Int3Array

[(int, int, int)]

Int4

(int, int, int, int)

Int4Array

[(int, int, int, int)]

Int64

long or int in Python3

Int64Array

[long] or [int] in Python3

IntArray

[int]

Matrix2d

float, float, float, float

Matrix2dArray

[Gf.Matrix2d(float, float, float, float)]

Matrix3d

float, float, float, float, float, float, float, float, float

Matrix3dArray

[Gf.Matrix3d(float, float, float, float, float, float, float, float, float)]

Matrix4d

float, float, float, float, float, float, float, float, float, float, float, float, float, float, float, float

Matrix4dArray

[Gf.Matrix4d(float, float, float, float, float, float, float, float, float, float, float, float, float, float, float, float)]

Normal3d

Gf.Vec3d(float, float, float)

Normal3dArray

[Gf.Vec3d(float, float, float)]

Normal3f

Gf.Vec3f(float, float, float)

Normal3fArray

[Gf.Vec3f(float, float, float)]

Normal3h

Gf.Vec3h(float, float, float)

Normal3hArray

[Gf.Vec3h(float, float, float)]

Point3d

Gf.Vec3d(float, float, float)

Point3dArray

[Gf.Vec3d(float, float, float)]

Point3f

Gf.Vec3f(float, float, float)

Point3fArray

[Gf.Vec3f(float, float, float)]

Point3h

Gf.Vec3h(float, float, float)

Point3hArray

[Gf.Vec3h(float, float, float)]

Quatd

Gf.Quatd(float, Gf.Vec3d(float, float, float))

QuatdArray

[Gf.Quatd(float, Gf.Vec3d(float, float, float))]

Quatf

Gf.Quatf(float, Gf.Vec3f(float, float, float))

QuatfArray

[Gf.Quatf(float, Gf.Vec3f(float, float, float))]

Quath

Gf.Quath(float, Gf.Vec3h(float, float, float))

QuathArray

[Gf.Quath(float, Gf.Vec3h(float, float, float))]

String

str

StringArray

[str]

TexCoord2d

Gf.Vec2d(float, float)

TexCoord2dArray

[Gf.Vec2d(float, float)]

TexCoord2f

Gf.Vec2f(float, float)

TexCoord2fArray

[Gf.Vec2f(float, float)]

TexCoord2h

Gf.Vec2h(float, float)

TexCoord2hArray

[Gf.Vec2h(float, float)]

TexCoord3d

Gf.Vec3d(float, float, float)

TexCoord3dArray

[Gf.Vec3d(float, float, float)]

TexCoord3f

Gf.Vec3f(float, float, float)

TexCoord3fArray

[Gf.Vec3f(float, float, float)]

TexCoord3h

Gf.Vec3h(float, float, float)

TexCoord3hArray

[Gf.Vec3h(float, float, float)]

Token

str

TokenArray

string

UChar

ord(char) where char is a single letter string

UInt

int

UInt64

long or int in Python3

UIntArray

[int]

Vector3d

Gf.Vec3d(float, float, float)

Vector3dArray

[Gf.Vec3d(float, float, float)]

Vector3f

Gf.Vec3f(float, float, float)

Vector3fArray

[Gf.Vec3f(float, float, float)]

Vector3h

Gf.Vec3h(float, float, float)

Vector3hArray

[Gf.Vec3h(float, float, float)]

  1. Use Sdf.ValueTypeNames.Find(string) to get the reference from a string (valid inputs are the left column in the table above)

3.Look up the exact value for TypeName in the Sdf.ValueTypeNames module ( Sdf.ValueTypeNames.Color3h for example is valid):

from pxr import Sdf

print(dir(Sdf.ValueTypeNames))

# output is: ['Asset', 'AssetArray', 'Bool', 'BoolArray', 'Color3d', 'Color3dArray', 'Color3f', 'Color3fArray', 'Color3h' 'Color3hArray', 'Color4d', 'Color4dArray', 'Color4f', ... snipped ]

Coming back to Working with Attributes.

You can call the prim_ref.CreateAttribute(name, type) function to create the attribute, and we can use the information above to select a valid type. It returns a reference to the attribute created, which we can set with attribute_ref.Set(value) , and again we can construct a valid value by looking up the constructor above.

from pxr import Usd, UsdGeom, Sdf
from omni.kit.usd_docs import single_prim_usda

stage_ref = Usd.Stage.Open(single_prim_usda)

# get a reference to the Xform instance, this works fine since it is also a Usd.Prim
xform_ref = UsdGeom.Xform.Define(stage_ref, '/XformPrim')

# create an attribute reference, using an explicit reference to the type
weight_attr = xform_ref.GetPrim().CreateAttribute('weight', Sdf.ValueTypeNames.Float)

print(weight_attr.Get()) # prints empty string for default Float values, not 0!

print(weight_attr.Get() == None) # prints "True"
print(weight_attr.Get() == 0) # prints "False"

# to set an attribute we use the attribute_ref.Set(value) function
weight_attr.Set(42.3)

print(weight_attr.Get()) # prints "42.3"

# also, you can chain calls like so
print(xform_ref.GetPrim().GetAttribute('weight').Get()) # prints "42.3"

Hierarchy and Traversal

USD Stages are organized in a hierarchy of Prims: there is a special root prim at / and it may have N-number of direct Prim descendants, each of which can have their own tree of Prim descendants.

The path to a Prim is described by a string which starts with the root prim / and contains the Prim name separated by the path separator / until the last component is the desired Prim’s name.

For example /Car/Wheel/Tire refers to the Tire prim which has parent Wheel and grandparent Car. Car’s parent is the special root prim /.

In the Tutorial section on Stages there is information on how to retrieve a Prim at a given path using stage_ref.GetPrimAtPath().

from pxr import Usd
from omni.kit.usd_docs import car_usda

stage_ref = Usd.Stage.Open(car_usda)

prim_ref = stage_ref.GetPrimAtPath('/Car')
print (f"car prim {prim_ref}")

Now, if you want to get a specific child of a Prim, and you know the name, you can use prim_ref.GetChild(child_name):

from pxr import Usd
from omni.kit.usd_docs import car_usda

stage_ref = Usd.Stage.Open(car_usda)

prim_ref = stage_ref.GetPrimAtPath('/Car')
child_prim_ref = prim_ref.GetChild('Wheel')

# Prims can be cast as bool, so you can check if the prim exists by comparing its bool() overload
if child_prim_ref:
    print("/Car/Wheel exists") # this will execute

print(child_prim_ref.GetPath()) # prints ""/Car/Wheel"

If you want to get all the children of a Prim, you can use prim_ref.GetChildren() which returns a list of prim references:

from pxr import Usd
from omni.kit.usd_docs import car_usda

stage_ref = Usd.Stage.Open(car_usda)

prim_ref = stage_ref.GetPrimAtPath('/Car')
print (f"prim_ref {prim_ref}")

# will return [Usd.Prim(</Car/Wheel>)]
children_refs = prim_ref.GetChildren()
print (f"children_refs {children_refs}")

If you want to traverse the entire stage, the stage_ref.Traverse() function is perfect for that, it returns an iterator:

from pxr import Usd
from omni.kit.usd_docs import car_usda

stage_ref = Usd.Stage.Open(car_usda)

for prim_ref in stage_ref.Traverse():
    print(prim_ref.GetPath())

There are more advanced traversal methods described in the UsdStage documentation.