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.
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.