USD Authoring with the OpenUSD Exchange SDK
When to apply
Apply when a task imports usdex.core / usdex.rtx / usdex.test in Python, or includes <usdex/core/...> / <usdex/rtx/...> / <usdex/test/...> in C++, or authors / converts / exports / validates OpenUSD data of any kind (Usd.Stage, Sdf.Layer, UsdPrim, UsdGeomMesh, UsdGeomXformable, UsdGeomCamera, UsdLuxLight, UsdShadeMaterial, UsdPhysics*, .usd* files). Stop when the task moves to non-USD work.
The audience is Physical AI converter / pipeline authors: robotics, simulation, synthetic data, digital twins, reusable asset libraries.
Non-negotiables
These rules apply to every snippet you write and every API you call. Do not relax them with "this example is illustrative" or "this is just for teaching" reasoning.
Use the SDK helpers; do not call raw OpenUSD where a helper exists
| Domain |
Use this |
Not this |
| Stage creation |
usdex.core.createStage |
Usd.Stage.CreateNew, Usd.Stage.CreateInMemory plus manual metadata |
| Stage configuration |
usdex.core.configureStage |
UsdGeomSetStageUpAxis + UsdGeomSetStageMetersPerUnit + manual creator write |
| Stage save |
usdex.core.saveStage |
stage.Save() / stage.GetRootLayer().Save() |
| Single-layer save / export |
usdex.core.saveLayer / usdex.core.exportLayer |
layer.Save() / layer.Export() |
| Transforms |
usdex.core.setLocalTransform (or pass transform to defineXform / defineCamera) |
UsdGeomXformCommonAPI, AddTranslateOp / AddRotateOp / AddScaleOp / AddTransformOp |
| Names (prims) |
usdex.core.NameCache.getPrimName(s) or getValidPrimName(s) / getValidChildName(s) |
string literals, Tf.MakeValidIdentifier, TfMakeValidIdentifier |
| Names (properties) |
getValidPropertyName(s) or NameCache.getPropertyName(s) |
string literals for property names |
| References |
usdex.core.defineReference |
prim.GetReferences().AddReference(...) |
| Payloads |
usdex.core.definePayload |
prim.GetPayloads().AddPayload(...) |
| Scopes |
usdex.core.defineScope |
UsdGeomScope.Define |
| Xforms / meshes / curves / points / gprims / cameras / lights / materials / physics joints / physics materials |
the matching usdex.core.define* helper |
Usd<Schema>.Define plus attribute writes |
| OpenPBR (MaterialX) + Preview Surface materials |
usdex.core.definePbrMaterial / defineGlassPbrMaterial |
canonical MaterialX shader graphs |
| RTX MDL materials |
usdex.rtx.definePbrMaterial / defineGlassMaterial |
hand-rolled MDL shader graphs |
| Primvars (normals, UVs, widths, displayColor, displayOpacity, ids, custom) |
wrap in usdex.core.PrimvarData or typed aliases Vec3fPrimvarData / Vec2fPrimvarData / FloatPrimvarData / Int64PrimvarData / IntPrimvarData / TokenPrimvarData / StringPrimvarData |
direct CreatePrimvar + raw VtArray writes |
| Constant primvars holding one scalar value |
usdex.core.createConstantPrimvar(prim, name, value, [valueTypeName]), or setConstantPrimvar to write another time sample |
a one-element typed alias with constant interpolation |
Custom primvars no define* helper covers |
<alias>.createPrimvar(prim, name, [valueTypeName]) |
prim.CreatePrimvar(...) + Set(...) |
| Values on schema-declared attributes |
usdex.core.setEffectiveAttributeValue |
prim.GetAttribute(name).Set(value), or a generated Create<Name>Attr(value) / Get<Name>Attr().Set(value) accessor, for every value including schema fallbacks |
Both primvar creation calls take an optional valueTypeName, which must be an array type. It carries a role only for Vec3f data, which authors float3[] unless told to author color3f[], normal3f[], or point3f[] — so pass it there, and leave it defaulted elsewhere. Every other alias accepts just its own array type, and a scalar spelling is rejected: createConstantPrimvar(prim, "myInt", 42, Sdf.ValueTypeNames.Int) authors nothing, it needs IntArray.
Raw schema is allowed (and required) only for APIs without a helper — e.g. UsdPhysicsRigidBodyAPI.Apply, UsdPhysicsCollisionAPI.Apply, UsdPhysics.Scene.Define, UsdLux.DistantLight.Define — and only after the prim has been defined via a helper, where one applies. That exemption covers defining the prim and applying the schema, not writing its values: author those with setEffectiveAttributeValue rather than the schema's generated Create<Name>Attr / Get<Name>Attr().Set accessors, so schema fallbacks stay unauthored. The generated accessors are the right tool only for what setEffectiveAttributeValue cannot express — time samples, connections, and metadata. See references/attributes.md.
Names
Every prim name you author — including names you "own" (asset names, scope names, default-prim names, throwaway example names) — flows through the name pipeline. Never pass a string literal to a usdex.core.define* / usdex.rtx.define* / defineScope / createMaterial name= argument. Never pass a string literal to defaultPrimName=. Use a variable populated from NameCache.getPrimName(parent, source.name), getValidChildName(parent, source.name), or getValidPrimName(asset.name).
For property names, the same rule applies via getValidPropertyName(s) or NameCache.getPropertyName(s). The pipeline is for names you derive from source data, so names a schema already declares (physics:mass, primvars:displayColor) are passed through as literals.
Authoring metadata
Every call to createStage / configureStage / saveStage / saveLayer / exportLayer must take an authoringMetadata value, and that value must be a variable (e.g. AUTHORING_METADATA), not a string literal. The variable should describe the host application and version (for example, "My Converter 2026.1, usdex_ver: <ver>").
Validation
If usdex.test is available, regression tests should subclass usdex.test.TestCase and call self.assertIsValidUsd(stage) on every produced stage. Diagnostic-checking tests use usdex.test.ScopedDiagnosticChecker. Outside of tests, run USD Validation on output. See references/diagnostics-and-testing.md.
Canonical authoring flow (prose, not code)
The flow below applies whether you are writing one stage or an asset library. The reference files expand each step.
- Activate the diagnostics delegate so SDK status messages stop printing to stdout. See
references/diagnostics-and-testing.md.
- Allocate a single
NameCache for the whole conversion. Use it for every prim and property name you author. See references/names.md.
- Define a module-level
AUTHORING_METADATA string from the host application's identity and version. Pass it to every stage / layer call.
- Create the stage with
usdex.core.createStage, supplying defaultPrimName=getValidPrimName(asset.name), upAxis, linearUnits (and massUnits if physics is involved), and authoringMetadata=AUTHORING_METADATA. See references/stages-and-layers.md.
- For placeable assets (the typical converter output), define the default prim as
Xform via usdex.core.defineXform — never leave it as the Scope fallback that createStage creates. Classify reusable assets with configureComponentHierarchy / configureAssemblyHierarchy (or rely on addAssetInterface for the multi-layer flow). See references/asset-structure.md.
- Author content under the default prim using
usdex.core.define* / usdex.rtx.define* helpers. For each prim:
- Allocate the name through the cache.
- Call the matching
define* helper, passing typed data and any PrimvarData.
- Apply API schemas (e.g.
UsdPhysicsRigidBodyAPI.Apply) only after the prim is defined.
- Set the local transform via
usdex.core.setLocalTransform or by passing a transform to the define* helper.
- For mesh normals use the source-provided
Vec3fPrimvarData when available, or compute it when the source data lacks normals. Asset Validator's NormalsExistChecker rejects non-subdiv meshes that have no primvars:normals authored. When computing, use usdex.core.computeMeshNormals unless a higher fidelity mesh operation library is being used as well.
- For multi-layer asset structure (Atomic Component, Library + Content + Interface layers), use
createAssetPayload / addAssetLibrary / addAssetContent / addAssetInterface. See references/asset-structure.md.
- For materials, prefer
usdex.core.definePbrMaterial — it drives an OpenPBR shader for the mtlx render context and a Preview Surface for the universal context from one Material Interface. Use definePreviewMaterial when only the universal context is wanted, and usdex.rtx.definePbrMaterial / defineGlassMaterial when targeting the RTX Renderer specifically. Bind with bindMaterial / bindMaterialSubsets. See references/materials.md.
- For physics, define visual / collision geometry first, then apply
UsdPhysicsRigidBodyAPI / UsdPhysicsCollisionAPI, define UsdPhysics.Scene (raw schema), and use definePhysicsFixedJoint / definePhysicsRevoluteJoint / definePhysicsPrismaticJoint / definePhysicsSphericalJoint for joints. See references/physics.md.
- Save with
usdex.core.saveStage(stage, AUTHORING_METADATA). For single-layer flows, use saveLayer / exportLayer instead. See references/stages-and-layers.md.
- Validate the result with
usd_validation_nvidia.ValidationEngine or usdex.test.TestCase.assertIsValidUsd. See references/diagnostics-and-testing.md.
Reference index
Load only the files needed for the current task; this SKILL.md already contains the rules that apply to every domain.
| File |
Read when the task involves |
references/stages-and-layers.md |
Creating, configuring, saving, or exporting stages / layers; choosing USDA vs USDC; layer authoring metadata; Usd → Sdf API moves in USD 25.11. |
references/names.md |
Any prim or property name; NameCache; displayName metadata; transcoding; the USDEX_ENABLE_TRANSCODING env setting. |
references/geometry.md |
Meshes, curves, points, basic gprims (sphere/cube/cone/cylinder/capsule/plane), subsets, primvars, normals computation. |
references/attributes.md |
Authoring values on schema-declared attributes, sparse layers, codeless schemas. |
references/materials.md |
OpenPBR (MaterialX), UsdPreviewSurface, and RTX MDL materials, textures, material interfaces, bindings, color space, primvar shaders. |
references/asset-structure.md |
Atomic Component assets, Library / Content / Interface layers, defineReference / definePayload, scopes, kinds. |
references/physics.md |
UsdPhysics scenes, rigid bodies, colliders, joints, physics materials, friction / restitution / density. |
references/lights.md |
UsdLuxDomeLight, UsdLuxRectLight, generic UsdLuxLightAPI attributes, the inputs: rename, dome pole axis. |
references/cameras.md |
UsdGeomCamera via GfCamera. |
references/diagnostics-and-testing.md |
Diagnostics delegate, TF_DEBUG, usdex.test.TestCase, ScopedDiagnosticChecker, USD Validation. |
External references
1---2name: usd-authoring3description: Author USD content via OpenUSD Exchange helpers (usdex.core, usdex.rtx, usdex.test). Use when writing or converting USD; do NOT use for install tasks.4license: Apache-2.05---6<!-- SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -->7<!-- SPDX-License-Identifier: Apache-2.0 -->89# USD Authoring with the OpenUSD Exchange SDK1011## When to apply1213Apply when a task imports `usdex.core` / `usdex.rtx` / `usdex.test` in Python, or includes `<usdex/core/...>` / `<usdex/rtx/...>` / `<usdex/test/...>` in C++, or authors / converts / exports / validates OpenUSD data of any kind (`Usd.Stage`, `Sdf.Layer`, `UsdPrim`, `UsdGeomMesh`, `UsdGeomXformable`, `UsdGeomCamera`, `UsdLuxLight`, `UsdShadeMaterial`, `UsdPhysics*`, `.usd*` files). Stop when the task moves to non-USD work.1415The audience is Physical AI converter / pipeline authors: robotics, simulation, synthetic data, digital twins, reusable asset libraries.1617## Non-negotiables1819These rules apply to every snippet you write and every API you call. Do not relax them with "this example is illustrative" or "this is just for teaching" reasoning.2021### Use the SDK helpers; do not call raw OpenUSD where a helper exists2223| Domain | Use this | Not this |24| --- | --- | --- |25| Stage creation | `usdex.core.createStage` | `Usd.Stage.CreateNew`, `Usd.Stage.CreateInMemory` plus manual metadata |26| Stage configuration | `usdex.core.configureStage` | `UsdGeomSetStageUpAxis` + `UsdGeomSetStageMetersPerUnit` + manual `creator` write |27| Stage save | `usdex.core.saveStage` | `stage.Save()` / `stage.GetRootLayer().Save()` |28| Single-layer save / export | `usdex.core.saveLayer` / `usdex.core.exportLayer` | `layer.Save()` / `layer.Export()` |29| Transforms | `usdex.core.setLocalTransform` (or pass `transform` to `defineXform` / `defineCamera`) | `UsdGeomXformCommonAPI`, `AddTranslateOp` / `AddRotateOp` / `AddScaleOp` / `AddTransformOp` |30| Names (prims) | `usdex.core.NameCache.getPrimName(s)` or `getValidPrimName(s)` / `getValidChildName(s)` | string literals, `Tf.MakeValidIdentifier`, `TfMakeValidIdentifier` |31| Names (properties) | `getValidPropertyName(s)` or `NameCache.getPropertyName(s)` | string literals for property names |32| References | `usdex.core.defineReference` | `prim.GetReferences().AddReference(...)` |33| Payloads | `usdex.core.definePayload` | `prim.GetPayloads().AddPayload(...)` |34| Scopes | `usdex.core.defineScope` | `UsdGeomScope.Define` |35| Xforms / meshes / curves / points / gprims / cameras / lights / materials / physics joints / physics materials | the matching `usdex.core.define*` helper | `Usd<Schema>.Define` plus attribute writes |36| OpenPBR (MaterialX) + Preview Surface materials | `usdex.core.definePbrMaterial` / `defineGlassPbrMaterial` | canonical MaterialX shader graphs |37| RTX MDL materials | `usdex.rtx.definePbrMaterial` / `defineGlassMaterial` | hand-rolled MDL shader graphs |38| Primvars (normals, UVs, widths, displayColor, displayOpacity, ids, custom) | wrap in `usdex.core.PrimvarData` or typed aliases `Vec3fPrimvarData` / `Vec2fPrimvarData` / `FloatPrimvarData` / `Int64PrimvarData` / `IntPrimvarData` / `TokenPrimvarData` / `StringPrimvarData` | direct `CreatePrimvar` + raw `VtArray` writes |39| Constant primvars holding one scalar value | `usdex.core.createConstantPrimvar(prim, name, value, [valueTypeName])`, or `setConstantPrimvar` to write another time sample | a one-element typed alias with `constant` interpolation |40| Custom primvars no `define*` helper covers | `<alias>.createPrimvar(prim, name, [valueTypeName])` | `prim.CreatePrimvar(...)` + `Set(...)` |41| Values on schema-declared attributes | `usdex.core.setEffectiveAttributeValue` | `prim.GetAttribute(name).Set(value)`, or a generated `Create<Name>Attr(value)` / `Get<Name>Attr().Set(value)` accessor, for every value including schema fallbacks |4243Both primvar creation calls take an optional `valueTypeName`, which must be an array type. It carries a role only for `Vec3f` data, which authors `float3[]` unless told to author `color3f[]`, `normal3f[]`, or `point3f[]` — so pass it there, and leave it defaulted elsewhere. Every other alias accepts just its own array type, and a scalar spelling is rejected: `createConstantPrimvar(prim, "myInt", 42, Sdf.ValueTypeNames.Int)` authors nothing, it needs `IntArray`.4445Raw schema is allowed (and required) only for APIs without a helper — e.g. `UsdPhysicsRigidBodyAPI.Apply`, `UsdPhysicsCollisionAPI.Apply`, `UsdPhysics.Scene.Define`, `UsdLux.DistantLight.Define` — and only **after** the prim has been defined via a helper, where one applies. That exemption covers defining the prim and applying the schema, not writing its values: author those with `setEffectiveAttributeValue` rather than the schema's generated `Create<Name>Attr` / `Get<Name>Attr().Set` accessors, so schema fallbacks stay unauthored. The generated accessors are the right tool only for what `setEffectiveAttributeValue` cannot express — time samples, connections, and metadata. See `references/attributes.md`.4647### Names4849Every prim name you author — including names you "own" (asset names, scope names, default-prim names, throwaway example names) — flows through the name pipeline. Never pass a string literal to a `usdex.core.define*` / `usdex.rtx.define*` / `defineScope` / `createMaterial` `name=` argument. Never pass a string literal to `defaultPrimName=`. Use a variable populated from `NameCache.getPrimName(parent, source.name)`, `getValidChildName(parent, source.name)`, or `getValidPrimName(asset.name)`.5051For property names, the same rule applies via `getValidPropertyName(s)` or `NameCache.getPropertyName(s)`. The pipeline is for names you derive from source data, so names a schema already declares (`physics:mass`, `primvars:displayColor`) are passed through as literals.5253### Authoring metadata5455Every call to `createStage` / `configureStage` / `saveStage` / `saveLayer` / `exportLayer` must take an `authoringMetadata` value, and that value must be a variable (e.g. `AUTHORING_METADATA`), not a string literal. The variable should describe the host application and version (for example, `"My Converter 2026.1, usdex_ver: <ver>"`).5657### Validation5859If `usdex.test` is available, regression tests should subclass `usdex.test.TestCase` and call `self.assertIsValidUsd(stage)` on every produced stage. Diagnostic-checking tests use `usdex.test.ScopedDiagnosticChecker`. Outside of tests, run [USD Validation](../../../docs/devtools.md#asset-validator) on output. See `references/diagnostics-and-testing.md`.6061## Canonical authoring flow (prose, not code)6263The flow below applies whether you are writing one stage or an asset library. The reference files expand each step.64651. Activate the diagnostics delegate so SDK status messages stop printing to stdout. See `references/diagnostics-and-testing.md`.662. Allocate a single `NameCache` for the whole conversion. Use it for every prim and property name you author. See `references/names.md`.673. Define a module-level `AUTHORING_METADATA` string from the host application's identity and version. Pass it to every stage / layer call.684. Create the stage with `usdex.core.createStage`, supplying `defaultPrimName=getValidPrimName(asset.name)`, `upAxis`, `linearUnits` (and `massUnits` if physics is involved), and `authoringMetadata=AUTHORING_METADATA`. See `references/stages-and-layers.md`.695. For placeable assets (the typical converter output), define the default prim as `Xform` via `usdex.core.defineXform` — never leave it as the `Scope` fallback that `createStage` creates. Classify reusable assets with `configureComponentHierarchy` / `configureAssemblyHierarchy` (or rely on `addAssetInterface` for the multi-layer flow). See `references/asset-structure.md`.706. Author content under the default prim using `usdex.core.define*` / `usdex.rtx.define*` helpers. For each prim:71 - Allocate the name through the cache.72 - Call the matching `define*` helper, passing typed data and any `PrimvarData`.73 - Apply API schemas (e.g. `UsdPhysicsRigidBodyAPI.Apply`) only after the prim is defined.74 - Set the local transform via `usdex.core.setLocalTransform` or by passing a transform to the `define*` helper.75 - For mesh normals use the source-provided `Vec3fPrimvarData` when available, or compute it when the source data lacks normals. Asset Validator's `NormalsExistChecker` rejects non-subdiv meshes that have no `primvars:normals` authored. When computing, use `usdex.core.computeMeshNormals` unless a higher fidelity mesh operation library is being used as well.767. For multi-layer asset structure (Atomic Component, Library + Content + Interface layers), use `createAssetPayload` / `addAssetLibrary` / `addAssetContent` / `addAssetInterface`. See `references/asset-structure.md`.778. For materials, prefer `usdex.core.definePbrMaterial` — it drives an OpenPBR shader for the `mtlx` render context and a Preview Surface for the universal context from one Material Interface. Use `definePreviewMaterial` when only the universal context is wanted, and `usdex.rtx.definePbrMaterial` / `defineGlassMaterial` when targeting the RTX Renderer specifically. Bind with `bindMaterial` / `bindMaterialSubsets`. See `references/materials.md`.789. For physics, define visual / collision geometry first, then apply `UsdPhysicsRigidBodyAPI` / `UsdPhysicsCollisionAPI`, define `UsdPhysics.Scene` (raw schema), and use `definePhysicsFixedJoint` / `definePhysicsRevoluteJoint` / `definePhysicsPrismaticJoint` / `definePhysicsSphericalJoint` for joints. See `references/physics.md`.7910. Save with `usdex.core.saveStage(stage, AUTHORING_METADATA)`. For single-layer flows, use `saveLayer` / `exportLayer` instead. See `references/stages-and-layers.md`.8011. Validate the result with `usd_validation_nvidia.ValidationEngine` or `usdex.test.TestCase.assertIsValidUsd`. See `references/diagnostics-and-testing.md`.8182## Reference index8384Load only the files needed for the current task; this `SKILL.md` already contains the rules that apply to every domain.8586| File | Read when the task involves |87| --- | --- |88| `references/stages-and-layers.md` | Creating, configuring, saving, or exporting stages / layers; choosing USDA vs USDC; layer authoring metadata; `Usd` → `Sdf` API moves in USD 25.11. |89| `references/names.md` | Any prim or property name; `NameCache`; `displayName` metadata; transcoding; the `USDEX_ENABLE_TRANSCODING` env setting. |90| `references/geometry.md` | Meshes, curves, points, basic gprims (sphere/cube/cone/cylinder/capsule/plane), subsets, primvars, normals computation. |91| `references/attributes.md` | Authoring values on schema-declared attributes, sparse layers, codeless schemas. |92| `references/materials.md` | OpenPBR (MaterialX), UsdPreviewSurface, and RTX MDL materials, textures, material interfaces, bindings, color space, primvar shaders. |93| `references/asset-structure.md` | Atomic Component assets, Library / Content / Interface layers, `defineReference` / `definePayload`, scopes, kinds. |94| `references/physics.md` | UsdPhysics scenes, rigid bodies, colliders, joints, physics materials, friction / restitution / density. |95| `references/lights.md` | `UsdLuxDomeLight`, `UsdLuxRectLight`, generic `UsdLuxLightAPI` attributes, the `inputs:` rename, dome pole axis. |96| `references/cameras.md` | `UsdGeomCamera` via `GfCamera`. |97| `references/diagnostics-and-testing.md` | Diagnostics delegate, `TF_DEBUG`, `usdex.test.TestCase`, `ScopedDiagnosticChecker`, USD Validation. |9899## External references100101- [Authoring USD Data](../../../docs/authoring-usd.md) — the SDK's own authoring narrative.102- [OpenUSD Exchange Samples](https://github.com/NVIDIA-Omniverse/usd-exchange-samples) — full end-to-end converters in matched C++ and Python.103- [Principles of Scalable Asset Structure](https://docs.omniverse.nvidia.com/usd/latest/learn-openusd/independent/asset-structure-principles.html.md) — background for the Asset Structure module.