Authoring USD with Connect SDK

The Connect SDK seeks to make it easy for clients to author consistent and correct USD data without having to understand all aspects of the OpenUSD API. The goal is not to abstract the authoring process but instead to simplify it by providing convenience functions that cover the common use cases of Connectors.

Valid and Unique Names

OpenUsd has strict requirements on what names are valid for a UsdObject.

Important

An identifier is valid if it follows the C/Python identifier convention; that is, it must be at least one character long, must start with a letter or underscore, and must contain only letters, underscores, and numerals.

Source OpenUsd

Additionally the names of sibling Objects must be unique so that the SdfPath that identifies them is unique within the UsdStage.

Ascii and UTF-8 Support

In many current OpenUSD runtimes valid characters within identifiers are restricted to the minimal ascii characters [A-Za-z0-9_]. The name of a UsdProperty can contain : delimiters for namespaces, however the values within each namespace must be a valid identifier.

Note

In the OpenUSD v24.03 release and beyond, XID identifiers are natively supported, but some reserved characters remain illegal (e.g. /, @).

For many Connectors their native items will not conform to these requirements and the names will need to be made valid in order to be used in USD.

Connect SDK can be used to produce valid UsdObject names for any OpenUSD runtime that we support. This is accomplished via a transcoding process that generates names that can be losslessly decoded. For any legal identifier in a given runtime, this transcoding will produce no changes. For illegal identifiers, the transcoding will produce a human readable name that meets the requirements of the runtime.

Note

This transcoding process has been proposed for inclusion in a future version of OpenUSD. Once a suitable implementation is available, we will adopt it internally to our name validation functions.

While we do not currently provide decoding functions, the omni_transcoding shared library and associated python module do provide this decoding. For the time being, it is recommended to use this library directly to decode any Prim names that have been serialized to a USD layer.

The restrictions on UsdObject names do not apply to the value stored in the “Display Name” metadata field. In order to retain the association with the native name it is recommended that the original name be stored in the Display Name metadata of the Object.

We recommend that connectors set this metadata in cases where the native name of an item could not be used for the associated UsdObject. This could be because the name was invalid, or because it needed to be allocated a suffix to become unique. In either case the original value can be stored as the display name.

Name Collisions

The USD authoring functions within Connect SDK require that the names and paths supplied are valid. While it would be possible for the functions to modify the values to make them valid this can lead to undetected name collisions.

When a name cannot be used due to collision with an other name, the Omniverse convention of adding a numeric suffix is used to generate a unique name.

Prim Naming Functions

Connect SDK provides the UsdPrim Name Algorithms module to generate unique and valid UsdPrim names.

To ensure that a name is valid use getValidPrimName(). This is a lossless encoding algorithm that supports all UTF-8 code set (even control characters). See Transcoding for more details.

When defining multiple prims below a common parent it is important that the names are not only valid, but also unique from one another and existing children. The getValidChildNames() function is provided for this purpose. If there is not an existing parent we provide getValidPrimNames().

Property Naming Functions

Connect SDK provides the UsdProperty Name Algorithms module to generate unique and valid UsdProperty names.

To ensure that a name is valid use getValidPropertyName(). This is a lossless encoding algorithm that supports all UTF-8 code set (even control characters). See Transcoding for more details. The encoding occurs within existing namespaces.

When defining multiple properties for a UsdPrim it is important that the names are not only valid, but also unique from one another. The getValidPropertyNames() function is provided for this purpose.

Prim Display Name

Support for storing a “Display Name” on a Prim is not consistent across all versions of OpenUsd. Connect SDK provides functions in the UsdPrim Display Name Algorithms module to help working with the metadata.

OpenUsd supports UTF-8 encoding for Display Name. You can author UTF-8 binary strings and/or characters directly in a .usda file. For example,

def Cube "cube1" (
    displayName = "\xF0\x9F\x9A\x80"
)

or

def Cube "cube1" (
    displayName = "🚀"
)

Similar to above, you can set the binary strings and/or the characters as the display name via setDisplayName() function.

omni.connect.core.setDisplayName(prim, "🚀")

or

omni.connect.core.setDisplayName(prim, b"\xF0\x9F\x9A\x80")

OpenUsd only supports UTF-8 encoding. If you have UTF-16 encoding bytes, you can decode it before setting the display name.

utf16_bytes = b'\xD8\x3D\xDE\x80'  # utf-16 for 🚀
unicode_code_point = utf16_bytes.decode('utf-16-be')
utf8_bytes = unicode_code_point.encode('utf-8')  # encode with utf-8
omni.connect.core.setDisplayName(prim, utf8_bytes)

Defining Prims

OpenUsd provides Schema classes for authoring typed Prims, however in order to author a complete and correct Prim it is often necessary to call multiple functions. It is common for some of these functions to be over looked, or have mismatched data supplied. The Connect SDK provides “define” functions to address this problem.

The role of the “define” functions is to ensure that a complete Prim definition is authored via a single function call, with validation being performed on the data supplied. All opinions that contribute to the Prims definition will be explicitly authored in a single Layer. If any of the supplied data is invalid then the Prim will not be authored. This up front validation avoids partial authoring of Prims.

Examples are:

  • defineXform()

  • definePolyMesh()

  • defineLinearBasisCurves()

  • defineCubicBasisCurves()

  • definePointCloud()

  • defineOmniPbrMaterial()

Defining Primvars

All UsdGeomPointBased prims can optionally have geometric surface varying variables called UsdGeomPrimvars (primitive variables or simply “primvars”) which interpolate across a primitive’s topology, can override shader inputs. In addition, any UsdPrim can have constant primvars, which are inherited down prim hierarchy to provide a convenient set-once-affect-many workflow within a hierarchy.

UsdGeomPrimvars are often used when authoring UsdGeomPointBased prims (e.g meshes, curves, and point clouds) to describe surface varying properties such as normals, widths, displayColor, and displayOpacity. They can also be used to describe completely bespoke user properties that can affect how a prim is rendered, or to drive a surface deformation.

However, UsdGeomPrimvar data can be quite intricate to use, especially with respect to indexed vs non-indexed primvars, element size, the complexities of VtArray detach (copy-on-write) semantics, and the ambiguity of “native” attributes vs primvar attributes (e.g. mesh normals).

We provide a templated read-only PrimvarData class to encapsulate all this data as a single object without risk of detaching (copying) arrays, and to provide simpler entry points to avoid common mistakes with respect to UsdGeomPrimvar data handling.

All of our USD authoring “define” functions for UsdGeomPointBased prims accept optional PrimvarData to define e.g normals, display colors, etc.

The PrimvarData class also supports reading from and authoring to any existing UsdGeomPrimvar, which may have been created via OpenUSD’s UsdGeomPrimvarsAPI.

Working with Transformation

The UsdGeomXformable schema supports a rich set of transform operations from which a resulting matrix can be computed. The flexibility of this system adds necessary complexity to the code required for Connectors authoring and retrieving transform information. Connect SDK provides the UsdPrim Xformable Algorithms module to help with this.

This module provides API for authoring and retrieving transformation using a standard suite of transform formats.

The goal of the API is to decouple the Connectors preferred transform format from the format in which the transform is stored on the UsdPrim. It achieves this by providing functions that will internally convert between formats as needed, and modify the storage format when required.

Getting Transforms

The getLocalTransform functions will retrieve the local transform of a UsdPrim in the format requested. If the existing UsdGeomXformOps can be mapped to the requested format then the components will be populated with the values authored. If there is no clear mapping then a local transform matrix will be computed and the components extracted from that.

Setting Transforms

The setLocalTransform functions will set the values of existing UsdGeomXformOps on a UsdPrim to achieve the transform supplied. If the given format can be mapped to the existing UsdGeomXformOps or have mappable values extracted, then the values of those will be set. If the given format (or the value it holds) cannot be mapped to the existing UsdGeomXformOps then new operations will be authored that can. If no UsdGeomXformOps exist then new ones matching the format will be authored. When a value is set at a given time all existing time samples will be maintained, even in cases where the operations were changed.