USD Export Example#
The examples/python/usd-export and examples/c/usd-export projects export
a populated hierarchy and runtime-created attributes. They need a build with
population/export support; no pxr Python package is required.
Run Python with uv run main.py from its directory. Outputs use a temporary
directory and are removed when the program exits.
Build C with CMake as described in Getting Started in C, then run
usd-export /tmp/destination.usda. The hierarchy is saved at that path; other
examples add suffixes such as .transforms.usda and .changed.usda.
Runtime Data#
The function receives directory, a temporary output directory. These imports
and writes create /World/Ball at ordinal 1 and make it readable. Subsequent
Python snippets run inside the same context managers:
import math
from pathlib import Path
from tempfile import TemporaryDirectory
import numpy as np
from ovstage import AttributeSemantic, OvstageError, PathDictionary, PopulationDomain, Stage, population
with Stage("example.usd-export.runtime") as stage, PathDictionary(stage) as paths:
with paths.create_path_list_from_strings(["/World/Ball"]) as selected:
with stage.query_from_path_list(selected) as query:
matrix = np.eye(4, dtype=np.float64)[None, :, :]
matrix[0, 3, :3] = [1, 2, 3]
stage.write_attribute(query, "omni:xform", ordinal=1, tensors=matrix,
is_array=False, semantic=AttributeSemantic.MATRIX).wait()
stage.write_attribute(query, "userProperties:temperature", ordinal=1,
tensors=np.array([20], dtype=np.float32), is_array=False).wait()
stage.write_attribute(query, "solver:collisionRadius", ordinal=1,
tensors=np.array([2.5], dtype=np.float64), is_array=False).wait()
# Record the USD type so DEF exports can create a Sphere.
stage.write_attribute(query, "usd-prim-type", ordinal=1,
tensors=np.array([paths.intern_token("Sphere")], dtype=np.uint64),
is_array=False).wait()
stage.advance_write_floor(ordinal=1).wait()
# Run the later snippets inside these same context managers.
createStage() creates the source instance; check() and checkOvx()
stop on errors. waitOp() waits for runtime operations and releases them.
ovstage_instance_t* stage = createStage("example.usd-export.runtime");
auto* dict = getPathDictionary(stage);
const ovx_string_t selected[] = {literal_to_ovx_string("/World/Ball")};
ovx_primpath_list_t paths{};
checkOvx(dict, path_dictionary_create_path_list_from_strings(dict, selected, 1, &paths), "paths");
ovstage_query_handle_t query{};
check(stage, ovstage_query_from_path_list(stage, paths, &query), "query");
const ovx_string_t names[] = {literal_to_ovx_string("omni:xform"),
literal_to_ovx_string("userProperties:temperature"), literal_to_ovx_string("solver:collisionRadius"),
literal_to_ovx_string("usd-prim-type"), literal_to_ovx_string("Sphere")};
ovx_token_t tokens[5]{};
checkOvx(dict, path_dictionary_create_tokens_from_strings(dict, names, 5, tokens), "tokens");
int64_t shape[] = {1};
double matrix[] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 2, 3, 1};
float temperature = 20;
double radius = 2.5;
uint64_t sphereType = tokens[4];
DLTensor tensors[4]{};
void* values[] = {matrix, &temperature, &radius, &sphereType};
const DLDataType types[] = {{kDLFloat, 64, 16}, {kDLFloat, 32, 1},
{kDLFloat, 64, 1}, {kDLUInt, 64, 1}};
// Four fixed-size attributes on one prim. Record the type for later DEF exports.
for (int i = 0; i < 4; ++i)
{
tensors[i].data = values[i];
tensors[i].device = {kDLCPU, 0};
tensors[i].ndim = 1;
tensors[i].shape = shape;
tensors[i].dtype = types[i];
auto write = writeData(&tensors[i], i == 0 ? OVSTAGE_SEMANTIC_MATRIX : OVSTAGE_SEMANTIC_NONE);
waitOp(stage, ovstage_write_attribute(stage, query, {tokens[i], {}}, 1, write,
OVSTAGE_PRIM_MODE_UPSERT), "write");
}
ovstage_write_floor_desc_t watermark{};
watermark.ordinal = 1;
watermark.scope = OVSTAGE_SCOPE_ALL;
waitOp(stage, ovstage_advance_write_floor(stage, &watermark), "advance watermark");
// Keep this source stage, query, and dictionary alive for the remaining examples.
Saving an Overlay#
Export the transform to a new layer, saving and closing it in one call:
# A one-shot export creates, saves, and closes an overlay layer.
report = population.export_to_usd_file(
stage, str(directory / "transforms.usda"), ordinal=1,
attribute_rules=["omni:xform"],
)
print("Transforms exported:", report["transforms_exported"])
# Transforms exported: 1
ovstage_population_export_attribute_rule_t transformRule{};
transformRule.source_attribute_name = literal_to_ovx_string("omni:xform");
ovstage_population_export_desc_t transformDesc{};
check(stage, ovstage_population_export_desc_init_snapshot(&transformDesc, 1), "init export");
transformDesc.attribute_rules = &transformRule;
transformDesc.attribute_rule_count = 1;
const std::string transformFile = prefix + "transforms.usda";
ovstage_population_export_report_t report{};
// One-shot export creates, saves, and closes the overlay layer.
check(stage, ovstage_population_export_to_usd_file(stage,
{transformFile.c_str(), transformFile.size()}, &transformDesc, &report), "export transforms");
std::printf("Transforms exported: %zu\n", report.transforms_exported);
// Transforms exported: 1
For the remaining examples and their contracts, see Exporting ovstage to USD.