feat(stage): add Stage::up_axis() -> Option<UpAxis>#42
feat(stage): add Stage::up_axis() -> Option<UpAxis>#42
Conversation
Adds a typed accessor for the root layer's upAxis metadata:
pub fn up_axis(&self) -> Option<UpAxis>
where UpAxis is a small Y/Z enum. USD defines only "Y" and "Z"
as valid values; any other authored string is treated as None so
that callers can continue inspecting the rest of the stage without
erroring on malformed data.
Changes:
- Add FieldKey::UpAxis ("upAxis") to sdf::schema.
- Add pub enum UpAxis { Y, Z } to stage.rs.
- Add Stage::up_axis() accessor.
Tests added:
- up_axis_y: Y-up fixture returns Some(UpAxis::Y).
- up_axis_z: Z-up fixture returns Some(UpAxis::Z).
- up_axis_absent_returns_none: fixture without upAxis returns None.
Fixtures added:
- fixtures/up_axis_y.usda
- fixtures/up_axis_z.usda
- fixtures/up_axis_absent.usda
There was a problem hiding this comment.
Pull request overview
Adds a typed accessor on Stage to read the composed stage up-axis convention from authored upAxis metadata, plus fixtures and tests to validate Y/Z and missing metadata behavior.
Changes:
- Introduces
UpAxisenum andStage::up_axis() -> Option<UpAxis>accessor. - Registers
FieldKey::UpAxis("upAxis") in the Sdf schema field key list. - Adds minimal
.usdafixtures and tests for Y-up, Z-up, and absentupAxis.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/stage.rs | Adds UpAxis enum, Stage::up_axis() implementation, and unit tests. |
| src/sdf/schema.rs | Adds FieldKey::UpAxis and maps it to "upAxis". |
| fixtures/up_axis_y.usda | Fixture with upAxis = "Y" metadata. |
| fixtures/up_axis_z.usda | Fixture with upAxis = "Z" metadata. |
| fixtures/up_axis_absent.usda | Fixture without upAxis metadata. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| /// Returns the `upAxis` metadata from the root layer, if set. | ||
| /// | ||
| /// USD defines two valid values: `"Y"` and `"Z"`. Any other authored | ||
| /// value (malformed data) is treated as `None` rather than an error so | ||
| /// that callers can continue inspecting the rest of the stage. |
There was a problem hiding this comment.
The docstring says this returns upAxis metadata "from the root layer", but the implementation uses self.field(...) which resolves the strongest opinion across the entire layer stack (it may come from a sublayer if the strongest/root layer doesn’t author it). Consider clarifying the wording (e.g., “from the pseudo-root (composed across layers)” or “from the root layer stack”) to match actual behavior.
| /// } | ||
| /// ``` | ||
| pub fn up_axis(&self) -> Option<UpAxis> { | ||
| let raw = self.field::<String>(&Path::abs_root(), FieldKey::UpAxis).ok()??; |
There was a problem hiding this comment.
ok()?? works here but is a bit hard to read at a glance (it’s relying on Option-? twice to drop both Err and None). Consider rewriting this in a more explicit/idiomatic way (e.g. using .ok().flatten()? or a small match) to improve maintainability.
| let raw = self.field::<String>(&Path::abs_root(), FieldKey::UpAxis).ok()??; | |
| let raw = self | |
| .field::<String>(&Path::abs_root(), FieldKey::UpAxis) | |
| .ok() | |
| .flatten()?; |
| match raw.as_str() { | ||
| "Y" => Some(UpAxis::Y), | ||
| "Z" => Some(UpAxis::Z), | ||
| _ => None, | ||
| } |
There was a problem hiding this comment.
The function’s behavior for malformed authored values (anything other than "Y"/"Z" => None) is part of the stated contract, but there isn’t a test covering that case. Adding a small fixture (e.g. upAxis = "X") and a corresponding test would help prevent regressions.
|
Hi @mxpv, Apologies — this PR (and the other four in this batch: #41 #42 #43 #44 #45) was opened by an AI agent on my behalf without enough human review of upstream etiquette. I should have filed an issue first to discuss before dropping a stack of code on you. Sorry for the noise. For context: I'm building yw-look, a Windows quick-look style asset inspector for CG workflows, and I need a few small accessors on top of If the API and approach look reasonable to you, I'd be grateful if you could merge them. If not — totally fine to close, I'd just maintain them on my fork instead. Happy to revise based on any feedback. Thanks for the great crate! |
|
Thanks for PR! I believe This crate doesn't have a geometry module yet, but it's on the roadmap. In the meantime, you can access upAxis via the generic field API: let up_axis: Option<String> = stage.field("/", "upAxis")?;I'd prefer to defer the typed UpAxis enum and FieldKey until the geometry module lands, so it ends up in the right place architecturally. Going to close this one for now. |
Summary
Adds a typed accessor for the root layer's
upAxismetadata, which is the first piece of scene-convention metadata most downstream renderers / viewers need:where
UpAxisis a smallY/Zenum. USD defines only"Y"and"Z"as valid values; any other authored string is treated asNoneso callers can continue inspecting the rest of the stage without erroring on malformed data.Changes
src/sdf/schema.rs: addFieldKey::UpAxis("upAxis").src/stage.rs: addpub enum UpAxis { Y, Z }andStage::up_axis().fixtures/up_axis_y.usda,fixtures/up_axis_z.usda,fixtures/up_axis_absent.usda: minimal fixtures.stage::tests:up_axis_y: Y-up fixture returnsSome(UpAxis::Y)up_axis_z: Z-up fixture returnsSome(UpAxis::Z)up_axis_absent_returns_none: no-metadata fixture returnsNoneRationale
The common alternative is to expose
upAxisas a raw string via the existingfield::<String>API, but:A companion PR for
Stage::meters_per_unit()is coming separately so that each accessor can be reviewed independently.Test plan
cargo testpasses (228 tests, 3 new)cargo clippy --all-targets -- -D warningscleancargo fmt --checkclean