The two heaviest combined topic areas on the exam โ mastering these skills separates a production USD developer from a student.
This page covers the two largest combined domain areas of the NCP-OUSD exam: Data Exchange (15%) โ writing custom importers/exporters, data mapping, and interchange scripts โ and Pipeline Development (14%) โ designing studio pipelines, asset management, versioning, USD exporter hooks, build configurations, flattening, and dependency removal. Together they account for roughly 18โ20 of your 60โ70 questions.
Conceptual translation between DCC data models (Maya, Houdini, Blender) and USD prims/properties. Mapping tables document the transformation โ source type, target prim type, value conversions, axis and unit conventions.
Python scripts using Usd, Sdf, and UsdUtils APIs to bring data into or extract data from USD. Sdf-level authoring is preferred for large bulk imports due to 10โ100ร speed advantage.
Intercept and transform data as it passes through a DCC's USD export pipeline. Write custom logic to rename prims, remap materials, add metadata, and validate output โ all registered via plugInfo.json.
Custom ArResolver integrates USD with your studio's asset management system. Version-immutable pipelines create new versions rather than overwriting. Resolvers translate logical identifiers to real file paths.
Deep-dive on every testable concept in Data Exchange and Pipeline Development, with Python and command-line examples.
Before writing any importer/exporter, create a data mapping document that records:
| Source (Maya) | Target USD Type | Notes |
|---|---|---|
| Transform node | UsdGeom.Xform | Axis order, pivot handling |
| Mesh | UsdGeom.Mesh | Face index winding, normals |
| Shader / Material | UsdShade.Shader / Material | Parameter mapping per renderer |
| Instancer | UsdGeom.PointInstancer or native USD instancing | Ambiguous โ document explicitly |
| Camera | UsdGeom.Camera | FOV vs aperture conversion |
stage.SetMetadata("upAxis", "Y")stage.SetMetadata("metersPerUnit", 0.01) for centimeter scenesPattern: read source data โ create Usd.Stage โ define prim hierarchy โ set attributes โ save
Sdf.Layer.CreateNew() for efficient batch authoring โ bypasses change notification overheadSdf.PrimSpec, Sdf.AttributeSpec, Sdf.RelationshipSpec โ faster than Usd-level for large importsUsdUtils.ComplianceChecker for schema compliance; UsdGeom.Imageable for renderable primstimeSamples dict and set via attr.SetMetadata("timeSamples", {...})# Sdf-level batch importer (fast)
from pxr import Sdf, Usd, UsdGeom
layer = Sdf.Layer.CreateNew("/tmp/import.usda")
with Sdf.ChangeBlock():
prim_spec = Sdf.PrimSpec(layer, "MyMesh", Sdf.SpecifierDef, "Mesh")
prim_spec.SetInfo("kind", "component")
# Set a points attribute
attr = Sdf.AttributeSpec(prim_spec, "points", Sdf.ValueTypeNames.Point3fArray)
attr.SetMetadata("timeSamples", {1.0: [(0,0,0),(1,0,0)], 2.0: [(0,1,0),(1,1,0)]})
layer.Save()
print("Import complete:", layer.identifier)
Pattern: traverse Usd.Stage โ convert USD data โ write to target format
stage.Traverse() iterates all prims; prim.GetFilteredChildren(predicate) for filtered traversalUsdGeomPrimvarsAPI(prim).GetPrimvars() to collect all primvarsprim.IsInstance(); get shared data from prim.GetPrototype()attr.GetTimeSamplesInInterval(Gf.Interval(startTime, endTime))stage.Flatten() returns a single-layer Sdf.Layerfrom pxr import Usd, UsdGeom, Gf
stage = Usd.Stage.Open("/path/to/scene.usda")
for prim in stage.Traverse():
if prim.IsA(UsdGeom.Mesh):
mesh = UsdGeom.Mesh(prim)
pts_attr = mesh.GetPointsAttr()
# Export time samples in the shot range
interval = Gf.Interval(stage.GetStartTimeCode(), stage.GetEndTimeCode())
time_samples = pts_attr.GetTimeSamplesInInterval(interval)
print(f"{prim.GetPath()}: {len(time_samples)} time samples")
# Handle instances
if prim.IsInstance():
proto = prim.GetPrototype()
print(f" Instance of prototype: {proto.GetPath()}")
DCC applications (Maya, Houdini) expose a plugin hook that fires during USD export. The hook can:
Registration: Maya USD uses mayaUsdTranslatorExport; Houdini uses ROP USD output driver hooks. Both register via plugInfo.json.
// plugInfo.json โ registers your export hook plugin
{
"Plugins": [{
"Name": "StudioUSDExportHook",
"Type": "python",
"Info": {
"mayaUsdTranslatorExport": {
"exportParentScope": true
}
},
"LibraryPath": ".",
"ResourcePath": "."
}]
}
# studio_export_hook.py โ hook implementation
from pxr import Usd, UsdGeom, Sdf
def post_export_callback(stage, export_options):
"""Fired by Maya USD after each prim is exported."""
for prim in stage.Traverse():
# Enforce naming convention: all prims lowercase
if prim.GetName() != prim.GetName().lower():
stage.GetRootLayer().Rename(
str(prim.GetPath()),
str(prim.GetPath()).lower()
)
# Stamp with studio metadata
prim.SetMetadata("customData", {"studio": "MyStudio", "pipeline": "v2"})
Ar.Resolver to implement studio-specific path resolution"asset:myAsset?v=3" resolved to "/studio/assets/myAsset/v003/asset.usda"ArResolver.Resolve(path) โ returns the filesystem path for the given asset identifierArResolverContext โ pass studio session info (shot, sequence, user) to the resolverfrom pxr import Ar
class StudioResolver(Ar.Resolver):
"""Translates 'asset:NAME?v=N' URIs to real file paths."""
def Resolve(self, path):
if path.startswith("asset:"):
name, _, version_str = path[6:].partition("?v=")
version = int(version_str) if version_str else "latest"
return f"/studio/assets/{name}/v{version:03d}/asset.usda"
return super().Resolve(path)
def CreateDefaultContext(self):
# Provide shot context from environment
import os
return Ar.ResolverContext({"shot": os.environ.get("SHOT", ""), "user": os.environ.get("USER", "")})
/asset/v001/ โ /shot/seq/shot/anim/ โ /shot/seq/shot/lighting/"asset?v=3" (resolver handles it) vs hardcoded pathUsdUtils.FlattenLayerStack or stage.Export() bakes all opinions into one layer; removes proprietary references# Publish a work layer as a new versioned asset
from pxr import Usd, UsdUtils
import shutil, os
work_path = "/studio/work/myAsset/asset.usda"
publish_path = "/studio/assets/myAsset/v004/asset.usda"
# Open work layer and flatten all sublayers
stage = Usd.Stage.Open(work_path)
flat_layer = stage.Flatten(addSourceFileComment=False)
os.makedirs(os.path.dirname(publish_path), exist_ok=True)
flat_layer.Export(publish_path)
print(f"Published to {publish_path}")
usd_config.cmake or setup.cfg controls which plugins are includedstage.Flatten(addSourceFileComment=False) โ one merged layer, no external referencesUsdUtils.StitchLayers โ merge multiple layers into one, preserving time samplesusdzip / usdchecker โ command-line tools for packaging and validation# Merge per-frame USD caches into a single multi-frame layer
from pxr import UsdUtils, Sdf
frame_layers = [Sdf.Layer.FindOrOpen(f"/cache/frame.{f:04d}.usd") for f in range(1001, 1049)]
merged = Sdf.Layer.CreateNew("/deliver/animation_cache.usd")
UsdUtils.StitchLayers(merged, frame_layers)
merged.Save()
print("Stitched", len(frame_layers), "frames into animation_cache.usd")
# Command-line: package scene + all dependencies into .usdz
usdzip --asset /path/to/scene.usda /path/to/output.usdz
# Validate before delivery
usdchecker /path/to/output.usdz
# Inspect merged/flat result
usdcat --flatten /path/to/scene.usda
Six mental shortcuts to anchor the most testable concepts from Data Exchange and Pipeline Development.
Always create a data mapping document before writing an importer or exporter. Identify ambiguities โ instancing strategy, axis convention, unit scale โ before touching Python. Undefined mappings become runtime bugs.
For large imports, use Sdf.PrimSpec / Sdf.AttributeSpec directly โ it bypasses USD's change notification system and is 10โ100ร faster than Usd-level authoring via stage.DefinePrim().
The hook fires during DCC export. Use it to rename, remap, validate, and add metadata โ without modifying the DCC scene itself. Registered via plugInfo.json in your plugin directory.
Custom resolver maps logical identifiers ("asset:prop?v=2") to real file paths. The ArResolverContext carries shot/user session data so the resolver can make context-aware decisions.
stage.Export() or UsdUtils.FlattenLayerStack() produces a single self-contained layer โ remove proprietary paths before handing off to clients or third-party renderers.
Published versions are never edited. Work โ Publish โ New Version. Pipeline tools pin references to specific versions; resolvers handle the path translation. Overwriting published versions corrupts dependent shots.
10 questions on Data Exchange & Pipeline Development. One at a time โ choose your answer to advance.
1. What is the primary purpose of a conceptual data mapping document in a USD pipeline?
2. Which USD API layer is fastest for bulk/batch authoring of large scenes during import?
3. What does a USD Exporter Hook allow a developer to do?
4. Which Python call flattens all layers in a stage into a single merged layer?
5. What does a custom ArResolver enable?
6. Which stage metadata attribute specifies the coordinate system orientation?
7. In a version-immutable pipeline, what happens when an artist needs to update a published asset?
8. Which tool packages a USD scene with all dependencies into a single distributable .usdz file?
9. When exporting time-sampled data at the Sdf level, which method efficiently sets all time samples at once?
10. What does UsdUtils.StitchLayers do?
Click any card to reveal the answer. Test yourself before reading.
Why use Sdf-level authoring for importers?
Sdf.PrimSpec / Sdf.AttributeSpec bypass USD's change notification overhead. For importing thousands of prims, Sdf-level is 10โ100ร faster than creating Usd.Prim objects via stage.DefinePrim().
What is a USD Exporter Hook?
A plugin registered via plugInfo.json that intercepts data during a DCC's USD export. It can rename prims, add metadata, remap paths, and validate output โ without modifying the DCC scene.
ArResolver role in the pipeline
Custom Ar.Resolver subclass that translates logical asset identifiers (studio URNs, version strings) into real file paths. ArResolverContext carries session data (shot, user, environment).
stage.Flatten() vs stage.Export()
Both produce a single merged layer. stage.Flatten() returns an in-memory Sdf.Layer. stage.Export(path) writes the flattened result directly to a file. Use for delivery to remove all external references.
Data mapping document โ what it covers
Source system data types โ USD prim types, property names, value transformations. Covers: axis convention, unit scale, naming rules, instancing strategy, ambiguous mappings. Written before coding begins.
UsdUtils.StitchLayers
Merges multiple Sdf.Layer objects into one, correctly combining time samples from all layers. Used for assembling per-frame USD caches into a single multi-frame layer.
Version immutability in pipelines
Published asset versions are read-only โ never overwritten. New work creates a new version number. References/payloads are pinned to specific versions. Resolvers translate version identifiers to paths.
UsdUtils.ComplianceChecker
Validates a USD stage/layer against USD compliance rules: checks schema correctness, primvar validity, material binding correctness. Use after import to catch authoring errors before publishing.
Targeted guidance for Data Exchange & Pipeline Development โ the heaviest combined section of the NCP-OUSD exam.
This is the heaviest combined section (29%). Data Exchange questions test specific API knowledge โ Sdf vs Usd level, flatten calls, time-sample methods. Pipeline questions are often conceptual โ versioning strategy, resolver role, hook registration. Expect scenario-based questions that describe a pipeline problem and ask which API or design decision solves it.
NVIDIA Learn OpenUSD Module 7 "Developing Data Exchange Pipelines"; USD Pipeline documentation at openusd.org; Ar (Asset Resolution) API docs; plugInfo.json format reference in the USD source. The official NVIDIA certification page links to the OpenUSD Learning Path.
Write a simple OBJ-to-USD importer using Sdf-level authoring; implement a minimal ArResolver subclass that logs every resolve call; try stage.Flatten() on a multi-sublayer scene and inspect the output in a text editor to see all layers merged.
Using Usd-level API for large bulk imports (too slow โ switch to Sdf); forgetting to set metersPerUnit and upAxis in the exported stage; not handling instancing in exporters (traversal stops at the instance boundary โ call prim.GetPrototype() explicitly).
Pipeline Development feeds directly into Customizing USD (6%) โ custom schemas and file format plugins are pipeline extension points. Data Exchange knowledge underpins Debugging (11%) because import/export bugs are the most common pipeline failures on production shows.
Authoritative sources for Data Exchange, Pipeline Development, and NCP-OUSD exam registration.
Official certification overview, exam objectives, and registration link.
NVIDIA's official course module directly covering this exam section โ importers, exporters, hooks, and pipeline design.
Complete reference for Ar.Resolver, ArResolverContext, and the full asset resolution framework.
Documents UsdUtils.FlattenLayerStack, UsdUtils.StitchLayers, UsdUtils.ComplianceChecker, and packaging utilities.
Schedule and purchase your NCP-OUSD exam via Certiverse (NVIDIA's official exam delivery partner). $200 exam fee.