5.5 KiB
Context
The USD Layer Manager application currently has a viewport panel (ViewportPanel) driven by a built-in ViewportCamera class. The camera supports orbit, pan, zoom, and framing via bounding box. Input handling uses a direct LMB/MMB/scroll mapping without modifier keys. There is no concept of switching to a USD stage camera prim — the viewport always renders from the free camera's viewpoint.
The target users are Maya artists who expect Alt+button viewport navigation and the ability to view through authored cameras in the USD stage. The current input scheme is a friction point, and the inability to look through stage cameras limits creative preview workflows.
Current State
ViewportCamerastores eye, focal point, orbit angles (yaw/pitch), distance, FOV, clip planes, aspect ratioViewportPanel::HandleInput()maps: LMB=orbit, MMB=pan, scroll=zoom, Shift+LMB=panViewportPanel::FrameScene()frames on the entire stage bounds- No USD camera prim integration; no per-prim framing; no hotkey support
Goals / Non-Goals
Goals:
- Replace the viewport input mapping with Maya-style Alt+button navigation (Alt+LMB orbit, Alt+MMB pan, Alt+RMB dolly, scroll zoom)
- Allow switching between the built-in free camera and any UsdCamera prim on the stage
- Support framing the viewport on the selected prim's bounding box (F key) and the full stage (A key)
- Add a camera selector dropdown in the viewport panel UI
Non-Goals:
- Authoring or editing USD camera prims through the viewport (that belongs in the Property Panel)
- Camera animation or sequencing (playblast, camera sequencer)
- Multiple viewports or split-view layouts
- Custom key binding configuration UI (hardcoded Maya-style for now)
Decisions
D1: Alt+button navigation with scroll exception
Decision: Use Alt+LMB for orbit, Alt+MMB for pan, Alt+RMB for dolly. Mouse scroll zooms without Alt (matching Maya behavior).
Rationale: This is the standard Maya viewport convention. Scroll zoom without Alt is expected because scroll has no other viewport conflict.
Alternative considered: Keep current LMB/MMB/scroll mapping as an option — rejected to avoid maintaining two input schemes and confusing users about the default.
D2: Dual-mode ViewportCamera (free vs USD camera)
Decision: Extend ViewportCamera with an enum mode (Free / UsdCamera). In UsdCamera mode, the view/projection matrices are derived from the UsdCamera prim's transforms and attributes; the orbit/pan/zoom controls are disabled. In Free mode, behavior is unchanged.
Rationale: Keeping both modes in one class avoids duplicating the projection math and makes switching seamless. Disabling manual navigation when looking through a USD camera matches Maya's behavior (you navigate the camera's transform instead, which is out of scope for now).
Alternative considered: Separate UsdCameraAdapter class that wraps a UsdCamera into the same interface — more complex, no clear benefit until camera manipulation is needed.
D3: Camera prim discovery and selection UI
Decision: Traverse the stage for all UsdCamera-typed prims on each frame (or on stage change). Present them in an ImGui combo dropdown above the viewport canvas. The first entry is always "Free Camera".
Rationale: Simple implementation; camera lists in typical USD scenes are small. Cache invalidation is handled by re-traversing on stage change notifications.
Alternative considered: Maintain a persistent camera registry — over-engineered for the current scope.
D4: Frame selected via SceneHierarchyPanel selection
Decision: The ViewportPanel holds a callback/string for the selected prim path. Application wires the SceneHierarchyPanel selection callback to update this path. Pressing F computes the selected prim's bounding box and calls FrameBoundingBox. Pressing A calls the existing FrameScene.
Rationale: Minimal coupling; ViewportPanel doesn't need to know about SceneHierarchyPanel directly. The Application layer already owns both panels and can wire them.
D5: Bounding box computation for selected prim
Decision: Use UsdGeomBBoxCache to compute the world-space bounding box of the selected prim and its descendants, then call ViewportCamera::FrameBoundingBox.
Rationale: This is the standard OpenUSD approach for bounding box queries and handles instancing, transforms, and purpose correctly.
Risks / Trade-offs
- [Alt key conflicts with ImGui] → ImGui may consume Alt for menu activation. Mitigation: Set
ImGuiConfigFlags_NoNavor handle Alt detection via GLFW directly before ImGui processes it. If ImGui captures Alt, fall back to detecting Alt viaio.KeyAltand consuming the input in the viewport'sHandleInput(). - [Camera prim traversal cost on large stages] → Re-traversing every frame is wasteful for stages with thousands of prims. Mitigation: Cache the camera list and invalidate on stage change only. For initial implementation, traversal per frame is acceptable; optimize later.
- [USD camera attribute coverage] → Not all UsdCamera attributes (e.g., lens distortion, stereo) can be represented in the current ViewportCamera projection. Mitigation: Support core attributes (focalLength, horizontalAperture, clippingRange, projection type) and ignore unsupported attributes gracefully.
- [Free camera state lost on switch] → When switching from USD camera back to free camera, the free camera's last position is restored. Mitigation: Store the free camera state separately and restore it on switch-back.