UsdLayerManager/openspec/changes/implement-scene-hierarchy-p.../design.md

5.4 KiB

Context

The application currently has a SceneHierarchyPanel class (92 lines) that implements a functional tree view of USD prims:

  • Uses PropertyManager::GetPrimPaths() to get all prims
  • Recursively renders prims with RenderPrimNode() showing name, type, and selection state
  • Supports selection highlighting, tooltips with type/path, and double-click/arrow expansion
  • Has a callback mechanism (PrimSelectCallback) for notifying when a prim is selected

However, Application::RenderUI() (lines 94-103) ignores this class and renders an inline placeholder instead:

ImGui::Begin("Scene Hierarchy", nullptr, ImGuiWindowFlags_NoCollapse);
if (m_stageManager->HasStage()) {
    ImGui::Text("Stage loaded: %s", m_stageManager->GetRootLayerIdentifier().c_str());
    ImGui::Separator();
    ImGui::Text("Scene hierarchy will be displayed here");
} else {
    ImGui::TextDisabled("No stage loaded");
    ImGui::Text("Open a USD file to view scene hierarchy");
}
ImGui::End();

Meanwhile, the LayerPanel class is properly wired in (lines 105-111) and functions correctly:

ImGui::Begin("Layer Panel", nullptr, ImGuiWindowFlags_NoCollapse);
if (m_stageManager->HasStage()) {
    m_layerPanel->Render();
} else {
    ImGui::TextDisabled("No stage loaded");
}
ImGui::End();

The PropertyPanel class exists as a header only (no .cpp file) and is also rendered as a placeholder.

Goals / Non-Goals

Goals:

  • Wire the existing SceneHierarchyPanel into Application so it functions as a dockable panel
  • Enhance the panel with prim type icons, visibility/active state indicators, and context menus
  • Ensure prim selection drives other panels (Property Panel) via the existing callback mechanism
  • Maintain consistency with the existing LayerPanel wiring pattern

Non-Goals:

  • Do not create a new panel class from scratch (the class already exists)
  • Do not modify the core USD traversal logic in PropertyManager (it's already functional)
  • Do not implement 3D viewport or property editing in this change
  • Do not change the docking architecture or ImGui context management

Decisions

1. Wiring Pattern: Follow Existing LayerPanel Approach

Decision: Wire SceneHierarchyPanel exactly like LayerPanel - create instance in Application::Initialize(), call SetPropertyManager(), and invoke Render() in Application::RenderUI().

Rationale:

  • Consistency with existing working pattern (LayerPanel)
  • Minimal changes required
  • Clear separation of concerns (Application manages lifecycle, panel handles rendering)
  • Avoids duplicating the placeholder code

Alternatives Considered:

  • Inline rendering in Application (current placeholder) - rejected because it duplicates existing functionality
  • Creating panel on-demand in RenderUI - rejected because it loses state and breaks consistency

2. Enhancement: Add Visual Indicators for Prim State

Decision: Enhance SceneHierarchyPanel::RenderPrimNode() to show:

  • Prim type icons (using Unicode characters or colored text)
  • Visibility/inactive state indicators (eye icon or strike-through)
  • Reference/instance indicators
  • Context menu for common operations (toggle visibility, toggle active)

Rationale:

  • Provides immediate visual feedback about prim state without opening property panel
  • Matches user expectations from similar tools (Maya Outliner, Unity Hierarchy)
  • Leverages existing USD API (GetVisibility(), GetActive())
  • Non-invasive enhancement that builds on solid foundation

Implementation Notes:

  • Use prim.GetVisibility() and prim.GetActive() to determine state
  • Show icons before prim name: 👁️ (visible), 👁️‍🗨️ (invisible), ○ (active), ● (inactive)
  • Context menu via ImGui::BeginPopupContextItem() on the tree node

3. Integration: Connect Selection to Property Panel

Decision: Implement the PrimSelectCallback in Application to update the PropertyPanel when selection changes (once PropertyPanel is implemented).

Rationale:

  • Leverages existing callback mechanism in SceneHierarchyPanel
  • Enables future integration with PropertyPanel
  • Follows event-driven pattern already established
  • No changes needed to SceneHierarchyPanel itself

Note: PropertyPanel currently doesn't exist as .cpp, so this sets up the foundation for when it's implemented.

4. Performance: Maintain Existing Traversal Approach

Decision: Keep the existing PropertyManager::GetPrimPaths() + recursive traversal approach.

Rationale:

  • Already implemented and working
  • GetPrimPaths() uses efficient UsdPrimRange traversal
  • Caching isn't needed for typical scene sizes (<10k prims)
  • Premature optimization would complicate the clean implementation

Risks / Trade-offs

[Performance] → Acceptable for typical USD scenes; GetPrimPaths() is O(N) but only called when stage changes or panel refreshes needed.

[UI Clutter] → Added icons and context menus enhance usability without overwhelming the interface; users can ignore extra visual cues if not needed.

[Tight Coupling] → Application now depends on SceneHierarchyPanel class; however, this follows the same pattern as LayerPanel and is acceptable for core UI components.

[Missing PropertyPanel] → Selection callback won't have immediate effect until PropertyPanel is implemented; this is expected and sets up proper integration for future work.

Open Questions

None - the path forward is clear: wire the existing panel, enhance it with visual indicators, and maintain consistency with existing patterns.