Skip to main content

openusd_schemas/
lib.rs

1//! Typed views for USD's standard schemas, over a composed
2//! [`Stage`](openusd::usd::Stage).
3//!
4//! Ask a `Mesh` for its points, a `Camera` for its focal length, a `Material`
5//! for the shader on its surface output, a `Skeleton` for its joints and
6//! skinning weights — as Rust types, rather than by attribute name and hand
7//! decoding. Every view authors as well as reads.
8//!
9//! Each sub-module is feature-gated so callers only compile what
10//! they need:
11//!
12//! | Feature | Module | Status |
13//! |---------|--------|--------|
14//! | `geom`    | `geom`    | `UsdGeom` reader (cross-cutting Imageable / Boundable today; full surface incoming). |
15//! | `physics` | `physics` | `UsdPhysics` reader (8 prim types, 7 single-apply APIs, multi-apply `LimitAPI` / `DriveAPI`). |
16//! | `skel`    | `skel`    | `UsdSkel` trait-views (SkelRoot / Skeleton as geom `Boundable`, SkelAnimation / BlendShape typed, SkelBindingAPI single-apply) + skinning toolkit (Topology, AnimMapper, SkeletonResolver, SkinningResolver, pure-math LBS); builds on the `geom` trait chain. |
17//! | `lux`     | `lux`     | `UsdLux` trait-views (8 concrete light prims + LightFilter + LightAPI / ShapingAPI / ShadowAPI / LightListAPI); builds on the `geom` trait chain. |
18//! | `shade`   | `shade`   | `UsdShade` trait-views (Shader / NodeGraph / Material via the `Connectable` interface, MaterialBindingAPI, UsdPreviewSurface reader). |
19//! | `render`  | `render`  | `UsdRender` trait-views (RenderSettings / Product via the `RenderSettingsBase` interface, Var / Pass / DenoisePass) + the computed render spec. |
20//! | `ui`      | `ui`      | `UsdUI` trait-views (typed `Backdrop` + single-apply `SceneGraphPrimAPI` / `NodeGraphNodeAPI`). |
21//! | `vol`     | `vol`     | `UsdVol` trait-views (`Volume` + `OpenVDBAsset` / `Field3DAsset`); builds on the `geom` trait chain. |
22//! | `media`   | `media`   | `UsdMedia` trait-views (`SpatialAudio` + `AssetPreviewsAPI`); builds on the `geom` trait chain. |
23//! | `proc`    | `proc`    | `UsdProc` trait-view (`GenerativeProcedural`, a `geom::Boundable`); builds on the `geom` trait chain. |
24//!
25//! These views read and author opinions; the property fallbacks a schema
26//! declares come from [`openusd::usd::SchemaRegistry`].
27
28use openusd::sdf;
29
30// The macros below generate paths into the core crate. Reaching it through
31// `$crate::openusd` keeps them bound to this crate's dependency rather than
32// to whatever `openusd` names at the expansion site.
33pub(crate) use ::openusd;
34
35#[cfg(any(
36    feature = "geom",
37    feature = "lux",
38    feature = "media",
39    feature = "physics",
40    feature = "proc",
41    feature = "render",
42    feature = "shade",
43    feature = "skel",
44    feature = "ui",
45    feature = "vol"
46))]
47mod common;
48
49/// Any failure a schema view can report: a schema-domain failure of its own,
50/// or a core failure ([`Core`](Self::Core)) from the composed queries and
51/// authoring calls the view is built on.
52///
53/// The schemas module is layered on the core the way a separate crate would
54/// be, so the core's [`Error`](openusd::Error) knows nothing of this type; this
55/// enum wraps the core error instead.
56#[derive(Debug, thiserror::Error)]
57#[non_exhaustive]
58pub enum SchemaError {
59    /// A core failure underneath the schema view.
60    #[error(transparent)]
61    Core(#[from] openusd::Error),
62
63    /// An xformOp names no kind this schema knows, so it has no value type
64    /// and would contribute nothing to the transform stack.
65    #[error("`{op}` is not an xformOp kind")]
66    UnknownXformOp {
67        /// The kind the op token named, with its `xformOp:` prefix and any
68        /// `:suffix` removed.
69        op: String,
70    },
71
72    /// An xformOp's matrix is singular, so the transform stack cannot be
73    /// inverted through it.
74    #[error("xformOp `{op}` matrix is singular and cannot be inverted")]
75    SingularTransform {
76        /// The offending op's attribute name.
77        op: String,
78    },
79
80    /// `!resetXformStack!` appears past the front of `xformOpOrder`, where it
81    /// no longer means anything.
82    #[error("xformOpOrder on `{prim}`: `!resetXformStack!` is only valid at index 0, found at index {index}")]
83    InvalidOpOrder {
84        /// The prim whose order is malformed.
85        prim: sdf::Path,
86        /// Where the reset token was found.
87        index: usize,
88    },
89
90    /// A shading connection chain exceeds the resolver's depth bound,
91    /// indicating a cycle or a pathologically deep graph.
92    #[error("connection chain at {attribute} is deeper than {max} hops")]
93    ConnectionDepthExceeded {
94        /// The attribute whose resolution hit the bound.
95        attribute: sdf::Path,
96        /// The bound that was hit.
97        max: usize,
98    },
99
100    /// A volume field relationship needs a non-empty field name.
101    #[error("Volume field name must not be empty")]
102    EmptyFieldName,
103
104    /// A render context that is neither the universal context nor a
105    /// namespaced identifier.
106    #[error("invalid render context {context:?}")]
107    InvalidRenderContext {
108        /// The rejected context string.
109        context: String,
110    },
111}
112
113/// Stage-tier authoring failures route through [`SchemaError::Core`], so a
114/// schema authoring helper propagates them with one `?`.
115impl From<openusd::usd::StageAuthoringError> for SchemaError {
116    fn from(error: openusd::usd::StageAuthoringError) -> Self {
117        Self::Core(error.into())
118    }
119}
120
121/// Composed-query failures route through [`SchemaError::Core`] likewise.
122impl From<openusd::pcp::QueryError> for SchemaError {
123    fn from(error: openusd::pcp::QueryError) -> Self {
124        Self::Core(error.into())
125    }
126}
127
128/// Path-parse failures route through [`SchemaError::Core`] likewise.
129impl From<sdf::PathParseError> for SchemaError {
130    fn from(error: sdf::PathParseError) -> Self {
131        Self::Core(error.into())
132    }
133}
134
135/// Cast failures route through [`SchemaError::Core`] likewise.
136impl From<sdf::CastError> for SchemaError {
137    fn from(error: sdf::CastError) -> Self {
138        Self::Core(error.into())
139    }
140}
141
142/// A value that does not fit an attribute's declared type surfaces as the
143/// authoring error it is.
144impl From<sdf::ValueTypeError> for SchemaError {
145    fn from(error: sdf::ValueTypeError) -> Self {
146        Self::Core(openusd::usd::StageAuthoringError::from(error).into())
147    }
148}
149
150#[cfg(feature = "geom")]
151pub mod geom;
152#[cfg(feature = "lux")]
153pub mod lux;
154#[cfg(feature = "media")]
155pub mod media;
156#[cfg(feature = "physics")]
157pub mod physics;
158#[cfg(feature = "proc")]
159pub mod proc;
160#[cfg(feature = "render")]
161pub mod render;
162#[cfg(feature = "shade")]
163pub mod shade;
164#[cfg(feature = "skel")]
165pub mod skel;
166#[cfg(feature = "ui")]
167pub mod ui;
168#[cfg(feature = "vol")]
169pub mod vol;