# Working with USD Python Libraries

 

USD (Universal Scene Description) is both an open source interchange format for arbitrary 3D scenes, as well as a runtime which provides a rich toolset for reading, writing, editing scenes.

These tutorials will help Python developers new to USD learn how to perform common tasks on the scene graph, as well as learn how to be more proficient in the USD documentation.

These tutorials are not meant to provide an introduction to 3D scene graphs and runtimes in general. Also, some experience with USD is beneficial but not required. If you have never encountered USD before, a good starting resource to get your hands dirty are the [USD Tutorials](https://graphics.pixar.com/usd/docs/USD-Tutorials.html) from Pixar&#39;s USD site.

The tutorials are organized by topic rather than sequential updates to a single goal, so they do not need to be read in any specific order.

- [Opening USD Stages Tutorial](#opening)
- [Prims, Attributes, and Metadata Tutorial](#prims)
- [Hierarchy and Traversal Tutorial](#traversal)

## Opening USD Stages

Working with USD Stages is pretty straight forward, as most times everything is one function call away.

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

    frompxrimportUsd
    
    stage = Usd.Stage.Open(&#39;path\_to\_file.usd&#39;)

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

    frompxrimportUsd
    
    stage = Usd.Stage.CreateNew(&#39;a\_new\_stage.usd&#39;)

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

    frompxrimportUsd
    
    stage = Usd.Stage.Open(&#39;path\_to\_file.usd&#39;)# do something to the stagestage.Save()

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.

    frompxrimportUsd
    
    stage = Usd.Stage.Open(&#39;a\_usda\_file.usda&#39;)# do something to the stagestage.Export(&#39;a\_usdc\_file.usdc&#39;)

  

## 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)`:

    frompxrimportUsd
    
    stage_ref = Usd.Stage.Open(&#39;stage.usda&#39;)
    
    prim = stage_ref.GetPrimAtPath(&#39;/Prim&#39;)print(prim.GetName())# prints &quot;Prim&quot;print(prim.GetPrimPath())# prints &quot;/Prim&quot;

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

    frompxrimportUsd
    
    stage_ref = Usd.Stage.Open(&#39;stage.usda&#39;)
    
    prim = stage_ref.DefinePrim(&#39;/UnTypedPrim&#39;)print(prim.GetName())# prints &quot;UnTypedPrim&quot;

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

    frompxrimportUsd, UsdGeom
    
    stage_ref = Usd.Stage.Open(&#39;stage.usda&#39;)
    
    prim = stage_ref.DefinePrim(&#39;/XformPrim&#39;,&#39;Xform&#39;)# above we have a Usd.Prim, if we want to access all the Xform&#39;s types natively, we need to get an Xform instance of our primxform = UsdGeom.Xform(prim)print(xform.GetPath())# prints &quot;/XformPrim&quot;# 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 instancexform_faster = UsdGeom.Xform.Define(stage_ref, &#39;/AnotherXformPrim&#39;)

To delete a prim from the current edit layer (please refer to the [documentation about RemovePrim](https://graphics.pixar.com/usd/docs/api/class_usd_stage.html#ac605faad8fc2673263775b1eecad2955) for details) you can use `stage_ref.RemovePrim(path)`:

    frompxrimportUsd
    
    stage_ref = Usd.Stage.Open(&#39;stage.usda&#39;)
    prim = stage_ref.DefinePrim(&#39;/UnTypedPrim&#39;)ifstage_ref.RemovePrim(&#39;/UnTypedPrim&#39;):print(&#39;/UnTypedPrim removed&#39;)# if you try to access the prim object, it will still reference path but it is expiredif(prim.IsValid()):print(&#39;{} is valid&#39;.format(prim.GetName()))else:print(&#39;{} is not valid&#39;.format(prim.GetName()))# the above will print &quot;UnTypedPrim is not valid&quot;

### Attributes

Attributes are the workhorse of storing actual data inside a Prim. Attributes are often defined as part of [Schemas](https://graphics.pixar.com/usd/docs/USD-Glossary.html#USDGlossary-Schema) 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&#39;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 &quot;purpose&quot;, and you wouldn&#39;t be able to get any code completion in an IDE that way.

The other way is to use the Xform Schema&#39;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&#39;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&#39;s see the code for getting an Attribute reference and getting its value:

    from pxr import Usd, UsdGeom
    
    stage_ref = Usd.Stage.Open(&#39;stage.usda&#39;)# get a reference to the Xform instance as well as a generic Prim instancexform_ref = UsdGeom.Xform.Define(stage_ref,&#39;/XformPrim&#39;)
    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(&#39;purpose&#39;)print(purpose_from_xform_ref == purpose_from_prim_ref) # prints True# prints the actual attribute&#39;s value, in this case, one of [default, render, proxy, guide], since it is the Xform&#39;s actual Purpose attributeprint(purpose_from_xform_ref.Get())

To create an attribute that isn&#39;t part of a Type&#39;s namespace (or it is, but you want to create the attribute &quot;manually&quot;), 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](https://graphics.pixar.com/usd/docs/api/_usd __page__ datatypes.html) 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](https://graphics.pixar.com/usd/docs/api/_usd __page__ datatypes.html) 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 -\&gt; 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]` |
| 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. | `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)]` |

2. 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):

    frompxrimportSdfprint(dir(Sdf.ValueTypeNames))# output is: [&#39;Asset&#39;, &#39;AssetArray&#39;, &#39;Bool&#39;, &#39;BoolArray&#39;, &#39;Color3d&#39;, &#39;Color3dArray&#39;, &#39;Color3f&#39;, &#39;Color3fArray&#39;, &#39;Color3h&#39;, &#39;Color3hArray&#39;, &#39;Color4d&#39;, &#39;Color4dArray&#39;, &#39;Color4f&#39;, ... 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.

    frompxrimportUsd, UsdGeom
    
    stage_ref = Usd.Stage.Open(&#39;stage.usda&#39;)# get a reference to the Xform instance, this works fine since it is also a Usd.Primxform_ref = UsdGeom.Xform.Define(stage,&#39;/XformPrim&#39;)# create an attribute reference, using an explicit reference to the typeweight_attr = xform_ref.CreateAttribute(&#39;weight&#39;, Sdf.ValueTypeNames.Float)print(weight_attr.Get())# prints empty string for default Float values, not 0!print(weight_attr.Get() ==None)# prints &quot;True&quot;print(weight_attr.Get() ==0)# prints &quot;False&quot;# to set an attribute we use the attribute\_ref.Set(value) functionweight_attr.Set(42.3)print(weight_attr.Get())# prints &quot;42.3&quot;# also, you can chain calls like soprint(xform_ref.GetPrim().GetAttribute(&#39;weight&#39;).Get())# prints &quot;42.3&quot;

  

## 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&#39;s name.

For example `/Car/Wheel/Tire` refers to the `Tire` prim which has parent `Wheel` and grandparent `Car`. `Car`&#39;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()`.

Here is a refresher, we&#39;ll assume `car.usda` has the `/Car/Wheel/Tire` path:

    frompxrimportUsd
    
    stage_ref = Usd.Stage.Open(&#39;car.usda&#39;)
    
    prim_ref = stage_ref.GetPrimAtPath(&#39;/Car&#39;)

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)`:

    frompxrimportUsd
    
    stage_ref = Usd.Stage.Open(&#39;car.usda&#39;)
    
    prim_ref = stage_ref.GetPrimAtPath(&#39;/Car&#39;)
    child_prim_ref = prim_ref.GetChild(&#39;Wheel&#39;)# Prims can be cast as bool, so you can check if the prim exists by comparing its bool() overloadif child_prim_ref:print(&quot;/Car/Wheel exists&quot;)# this will executeprint(child_prim_ref.GetPath())# prints &quot;&quot;/Car/Wheel&quot;

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

    frompxrimportUsd
    
    stage_ref = Usd.Stage.Open(&#39;car.usda&#39;)
    
    prim_ref = stage_ref.GetPrimAtPath(&#39;/Car&#39;)# will return [Usd.Prim(\&lt;/Car/Wheel\&gt;)]children_refs = prim_ref.GetChildren()

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

    frompxrimportUsd
    
    stage_ref = Usd.Stage.Open(&#39;car.usda&#39;)
    
    for prim_ref in stage_ref.Traverse():print(prim_ref.GetPath())

There are more advanced traversal methods described in the [UsdStage](https://graphics.pixar.com/usd/docs/api/class_usd_stage.html#adba675b55f41cc1b305bed414fc4f178) documentation.


