Siggraph Presentation

This guide will be officially introduced at Siggraph 2023 - Houdini Hive on Wednesday, 9. of August 2023 at 11:00 AM PST.

API Overview

Before we dive into the nitty gritty details, let's first have a look at how the USD API is structured.

Overall there are two different API "levels":

flowchart TD
    pxr([pxr]) --> highlevel([High Level -> Usd])
    pxr --> lowlevel([Low Level -> PcP/Sdf])

Most tutorials focus primarily on the high level API, as it is a bit more convenient when starting out. The more you work in Usd though, the more you'll start using the lower level API. Therefore this guide will often have examples for both levels.

Tip

We'd actually recommend starting out with the lower level API as soon as you can, as it will force you to write performant code from the start.

Now there are also a few other base modules that supplement these two API levels, we also have contact with them in this guide:

  • Gf: The Graphics Foundations module provides all math related classes and utility functions (E.g matrix and vector data classes)
  • Vt : The Value Types module provides the value types for what USD can store. Among these is also the Vt.Array, which allows us to efficiently map USD arrays (of various data types like int/float/vectors) to numpy arrays for fast data processing.
  • Plug: This module manages USD's plugin framework.
  • Tf: The Tools Foundations module gives us access to profiling, debugging and C++ utilities (Python/Threading). It also houses our type registry (for a variety of USD classes).

For a full overview, visit the excellently written USD Architecture Overview - Official API Docs section.

TL;DR - API Overview In-A-Nutshell

Here is the TL;DR version. Usd is made up of two main APIs:

Individual components of Usd are loaded via a plugin based system, for example Hydra, kinds, file plugins (Vdbs, abc) etc.

Here is a simple comparison:

### High Level ### (Notice how we still use elements of the low level API)
from pxr import Sdf, Usd
stage = Usd.Stage.CreateInMemory()
prim_path = Sdf.Path("/bicycle")
prim = stage.DefinePrim(prim_path, "Xform")
attr = prim.CreateAttribute("tire:size", Sdf.ValueTypeNames.Float)
attr.Set(10)

### Low Level ###
from pxr import Sdf
layer = Sdf.Layer.CreateAnonymous()
prim_path = Sdf.Path("/bicycle")
prim_spec = Sdf.CreatePrimInLayer(layer, prim_path)
prim_spec.specifier = Sdf.SpecifierDef
prim_spec.typeName = "Xform"
attr_spec = Sdf.AttributeSpec(prim_spec, "tire:size", Sdf.ValueTypeNames.Float)
attr_spec.default = 10

What should I use it for?

Tip

You'll be using these two API levels all the time when working with Usd. The high level API is often used with read ops, the low level with write ops or inspecting the underlying caches of the high level API.

Resources

When should I use what?

As a rule of thumb, you use the high level API when:

And the low level API when:

  • Creating/Copying/Moving data of a layer
  • Performance is critical (When is it ever not?)

High Level API

The Usd Core API docs page is a great place to get an overview over the high level API:

Basically everything in the pxr.Usd namespace nicely wraps things in the pxr.Sdf/pxr.Pcp namespace with getters/setters, convenience classes and functions.

Therefore it is a bit more OOP oriented and follows C++ code design patterns.

Important

This level always operates on the composed state of the stage. This means as soon as you are working stages, you'll be using the higher level API. It also takes care of validation data/setting common data, whereas the lower level API often leaves parts up to the user.

Low Level API

Great entry points for the lower level API:

This level always operates individual layers. You won't have access to the stage aka composed view of layers.

Workflows

The typical workflow is to do all read/query operations in the high level API by creating/accessing a stage and then to do all the write operations in the low level API.

In DCCs, the data creation is done by the software, after that it is your job to massage the data to its final form based on what your pipeline needs:

In the daily business, you'll be doing this 90% of the time:

  • Rename/Remove prims
  • Create additional properties/attributes/relationships
  • Add metadata

Sounds simple, right? Ehm right??

Well yes and no. This guide tries to give you good pointers of common pitfalls you might run into.

So let's get started with specifics!