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 ships sample implementations for compliance testing, as Python scripts with JSON baselines. Where a baseline exists these crates parse it and check their own output against it, and the vendored suites run on every CI build: text and binary parsing, composition, value resolution, and list-op combine chains.
Refer to the compliance table for what is currently covered.
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, PointBasedSchema};
use openusd_schemas::shade;
// The registry is what makes a prim a `Mesh` and what resolves the fallbacks
// its schema declares; without it the typed constructors answer `None`.
let stage = usd::Stage::builder()
.schema_registry(openusd_schemas::schema_registry())
.open("scene.usda")?;
// `PointBasedSchema` 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.