UsdLayerManager/openspec/changes/camera-wireframe-viewport/tasks.md

4.6 KiB
Raw Permalink Blame History

1. UsdSceneRenderer — DrawCameraWireframes

  • 1.1 Add to UsdSceneRenderer.h: void DrawCameraWireframes(pxr::UsdStageRefPtr stage, const pxr::SdfPathVector& selectedPaths, const pxr::SdfPath& activeCameraPath, const pxr::GfMatrix4d& viewProjMatrix, double viewportCameraDist) and private helpers BuildCameraWireframeLines(const pxr::GfCamera& gfCam, double scale, std::vector<float>& outVerts) and pxr::SdfPathVector m_cachedCameraPaths + bool m_cameraCacheDirty = true
  • 1.2 In UsdSceneRenderer.cpp implement DrawCameraWireframes:
    • If m_cameraCacheDirty, traverse stage for UsdGeomCamera prims and cache paths; clear dirty flag
    • For each cached camera path, resolve world transform + lens params via UsdGeomCamera::GetCamera(UsdTimeCode::Default())GfCamera
    • Compute frustumScale = std::min(viewportCameraDist * 0.12, 50.0)
    • Call BuildCameraWireframeLines to produce a std::vector<float> of XYZ vertex pairs (GL_LINES)
    • Determine colour: selected → (1.0,0.75,0.1,1.0), active → (0.2,0.9,1.0,1.0), inactive → (0.55,0.55,0.55,0.85)
    • BindDrawTarget(), draw all segments using the existing axis GLSL program + a dynamic VBO (same pattern as DrawBoundingBoxes), UnbindDrawTarget()
  • 1.3 Implement BuildCameraWireframeLines: given GfCamera and scale, produce:
    • Body box — 12 edges of a small box (width × height × depth = scale×0.15 each) centred at camera origin in local space, transformed to world space by the camera's transform matrix
    • Frustum pyramid — 4 lines from camera origin to each corner of a near-display quad at depth max(nearClip, 0.01), scaled so the quad width/height match horizontalAperture/focalLength * nearDepth (perspective divide)
    • Up arrow — one line from body-box top-centre upward by scale * 0.2 along camera local Y
  • 1.4 Set m_cameraCacheDirty = true inside SetStage (already exists) and inside the SetForceRefresh(true) path

2. UsdSceneRenderer — PickCameraAtPoint

  • 2.1 Add to UsdSceneRenderer.h: bool PickCameraAtPoint(pxr::UsdStageRefPtr stage, const ImVec2& mousePosAbsolute, const pxr::GfMatrix4d& viewProjMatrix, const ImVec2& imagePos, int viewW, int viewH, double viewportCameraDist, pxr::SdfPath* outCameraPath)
  • 2.2 In UsdSceneRenderer.cpp implement PickCameraAtPoint:
    • Iterate m_cachedCameraPaths (build cache if needed)
    • For each camera: build wireframe vertex list via BuildCameraWireframeLines
    • Project each vertex pair to screen space using the same WorldToScreen math as TransformManipulator
    • Compute PointToSegmentDist for each segment against mousePosAbsolute
    • Track minimum distance and corresponding path; if < kCameraPickRadius (10 px) return true with that path
    • If tie between multiple cameras, return the one with the smallest minimum distance

3. ViewportPanel — Integration

  • 3.1 In ViewportPanel.h: add pxr::SdfPath GetActiveCameraPath() const (returns m_camera.GetUsdCameraPath() when in UsdCamera mode, else SdfPath()) — check ViewportCamera API for the getter name
  • 3.2 In ViewportPanel.cpp Render(): after the DrawBoundingBoxes call, add:
    m_renderer.DrawCameraWireframes(m_stage, m_selectedSdfPaths,
        m_camera.GetUsdCameraPath(), viewProj, m_camera.GetDist());
    
    (Use the local viewProj already computed in that scope)
  • 3.3 In ViewportPanel.cpp HandleInput(), single-click path (before the existing PickObject call): add camera pick:
    pxr::SdfPath camPath;
    if (m_renderer.PickCameraAtPoint(m_stage, mouse, viewProj,
            m_imageScreenPos, m_viewWidth, m_viewHeight,
            m_camera.GetDist(), &camPath)) {
        // fire selection callbacks with camPath
    }
    
    Only fall through to PickObject if PickCameraAtPoint returns false

4. Build and Verification

  • 4.1 Run cmake --preset default (only needed if new .cpp files were added; all changes here are in existing files so this may be skipped) then cmake --build build --config Release — resolve any compilation errors
  • 4.2 Install and launch install/bin/App.exe; create a Camera prim via Stage menu, verify its frustum wireframe appears in the viewport at the world origin
  • 4.3 Verify clicking the camera wireframe selects the prim in the Scene Hierarchy panel
  • 4.4 Verify the Move (W) gizmo appears on the selected camera and dragging repositions it; the wireframe moves to match
  • 4.5 Switch the viewport to that camera via the camera toolbar; verify the wireframe turns cyan
  • 4.6 With the camera active in the toolbar, click it in the viewport; verify it turns yellow-orange (selected overrides active colour)