openusd is a Rust implementation of Pixar's Universal Scene Description (USD) format with no C++ dependencies.
This repository contains the following crates:
| Crate | Description | |
|---|---|---|
openusd |
Core USD library — file formats, composition engine, and the composed Stage API. |
|
openusd‑schemas |
Typed views for USD's standard schemas — UsdGeom, UsdShade, UsdSkel, and more. |
For a detailed comparison with the C++ reference implementation and current progress, see the Roadmap.
- File formats — reads and writes
.usda(text),.usdc(binary), and.usdz(archive). - A fully featured composition engine — LIVRPS strength ordering over a per-prim node graph, with list editing, scene-graph instancing, non-destructive relocates, and variable expressions.
- A composed
Stage— lazy cached per-prim composition with typed value resolution, predicate-based traversal, and full prim/property query API over the composed scene. - An authoring API — build scenes through layer- and stage-tier APIs, with typed spec views, composed prim/attribute/relationship handles with chained fluent edits,
EditTargetrouting to a specific layer, in-memory anonymous-root stages, and applied API schema authoring. - Live sync friendly — listen to
Stageedit events and capture each edit as a transferable, replayableDifffor live mirroring across processes. - Domain schema readers (opt-in per family, layered on the composed stage) —
UsdGeom,UsdLux,UsdPhysics,UsdRender,UsdSkel, andUsdShade.
If you encounter a file that can't be read, please open an issue and attach the USD file for investigation.
The AOUSD Core Specification 1.0 has been officially ratified. As part of the specification, sample implementations for compliance testing are provided as Python scripts with JSON baselines. Where JSON baselines are available, the crate parses them and verifies that its output matches.
| Area | Status | Notes |
|---|---|---|
| Text format parsing | ✅ Passes | 10 tests against JSON baselines |
| Binary format parsing | ✅ Passes | 42 tests manually backported from the reference suite's test_binary.py in tests/binary_format.rs |
| Composition | ✅ Passes | tests/composition.rs runs the full vendor suite (138 assets) through both the text and binary parsers, regenerating each pcp.txt dump to validate strength ordering, prim/property stacks, and time offsets |
| Value resolution | ☑️ Partial | 8 tests in tests/value_resolution.rs (defaults, time samples, value clips). Excludes attribute fallbacks and splines |
| Combine chains | ✅ Passes | ListOp::combined_with and ListOp::reduced against JSON baselines |
Warning
These crates are under active development. No API stability is guaranteed until version 1.0.
Make sure you have Rust installed on your system, rustup will do the rest.
Add the crates you need — openusd-schemas is optional, with one feature per
schema family:
[dependencies]
openusd = "0.7"
openusd-schemas = { version = "0.7", features = ["geom", "shade"] }Open a stage, walk its composed prims, and read a resolved attribute value:
use openusd::usd;
let stage = usd::Stage::open("scene.usda")?;
// `DEFAULT` prunes inactive, unloaded, and abstract subtrees.
stage.traverse(usd::PrimPredicate::DEFAULT, |prim_path| {
println!("{prim_path}");
})?;
let sphere = stage.prim("/World/Sphere")?;
println!("type: {:?}", sphere.type_name()?);
// Resolved across every layer, reference, and payload that composes the prim.
let radius = stage.attribute("/World/Sphere.radius")?;
if let Some(r) = radius.get::<f64>()? {
println!("radius = {r}");
}Authoring works the same way round:
use openusd::usd;
let stage = usd::Stage::builder().in_memory("root.usda")?;
stage.define_prim("/World")?.set_type_name("Xform")?;
stage.define_prim("/World/Sphere")?.set_type_name("Sphere")?;
stage.set_default_prim("World")?;
stage.create_attribute("/World/Sphere.radius", "double")?.set(2.5_f64)?;Typed schema views layer on top of that stage — here a mesh's points and the shader driving a material's surface:
use openusd::{gf, usd};
use openusd_schemas::geom::{self, PointBased};
use openusd_schemas::shade;
let stage = usd::Stage::open("scene.usda")?;
// `PointBased` is in scope so `Mesh` inherits its accessors.
if let Some(mesh) = geom::Mesh::get(&stage, "/World/Mesh")? {
if let Some(points) = mesh.points_attr().get::<Vec<gf::Vec3f>>()? {
println!("{} points", points.len());
}
}
// Follow the material's surface terminal to the shader driving it.
if let Some(material) = shade::Material::get(&stage, "/World/Material")? {
if let Some(terminal) = material.compute_surface_source(&[])? {
for source in terminal.sources() {
if let Some(shader) = source.shader() {
println!("surface shader: {:?}", shader.id()?);
}
}
}
}The project targets stable Rust and aims for the latest Rust editions. The MSRV is bumped on an as-needed basis, whenever it makes sense for the project. Please refer to rust-toolchain.toml for the exact version currently used by our CIs.
Licensed under the MIT License.