Honor SceneView::viewport (split-screen / picture-in-picture) #76

Open
opened 2026-09-30 18:39:27 -07:00 by burkkyy · 0 comments
Owner

SceneView::viewport (engine/include/sophia/scene_view.hpp) is declared but never read. Every scene view pass renders to its whole target: RenderGraph::recordRendering sets the viewport and scissor to the full attachment, and SceneRenderer::render computes the camera's aspect ratio from the full target extent. So several views can't share one target side by side.

Proposed approach

  • Convert viewport (normalized x, y, width, height) to a pixel vk::Rect2D for the target, clamped to it. Skip views whose rect is empty.
  • In SceneRenderer::render, set the viewport and scissor to that rect, and compute aspect from the rect instead of the full extent.
  • Clearing: a pass's loadOp clear always covers the whole attachment, so a second split-screen view would wipe the first. When a view doesn't cover its whole target:
    • clear only its rect from inside the pass with vkCmdClearAttachments, according to clearFlags;
    • have the first pass on the target in the frame still clear the whole attachment (to the background color, with depth 1.0), so areas no view covers aren't left undefined. This matters most for the swapchain.
  • Full-target views keep using loadOp clears.
  • Decide and document the origin: top-left (matches Vulkan and ImGui) or bottom-left (matches Unity and the Y-up world).
  • Revisit the "view clears its target after another view already rendered to it" warning in application.cpp. It should only fire when the clear actually overlaps an earlier view's area.

Notes

  • The editor viewport's screen↔world math (editor/panels/viewport_panel.cpp) assumes the view fills the target. It would need the rect too if the editor ever uses a partial viewport.
`SceneView::viewport` (`engine/include/sophia/scene_view.hpp`) is declared but never read. Every scene view pass renders to its whole target: `RenderGraph::recordRendering` sets the viewport and scissor to the full attachment, and `SceneRenderer::render` computes the camera's aspect ratio from the full target extent. So several views can't share one target side by side. ## Proposed approach - Convert `viewport` (normalized `x, y, width, height`) to a pixel `vk::Rect2D` for the target, clamped to it. Skip views whose rect is empty. - In `SceneRenderer::render`, set the viewport and scissor to that rect, and compute aspect from the rect instead of the full extent. - **Clearing:** a pass's `loadOp` clear always covers the *whole* attachment, so a second split-screen view would wipe the first. When a view doesn't cover its whole target: - clear only its rect from inside the pass with `vkCmdClearAttachments`, according to `clearFlags`; - have the first pass on the target in the frame still clear the whole attachment (to the background color, with depth 1.0), so areas no view covers aren't left undefined. This matters most for the swapchain. - Full-target views keep using `loadOp` clears. - Decide and document the origin: top-left (matches Vulkan and ImGui) or bottom-left (matches Unity and the Y-up world). - Revisit the "view clears its target after another view already rendered to it" warning in `application.cpp`. It should only fire when the clear actually overlaps an earlier view's area. ## Notes - The editor viewport's screen↔world math (`editor/panels/viewport_panel.cpp`) assumes the view fills the target. It would need the rect too if the editor ever uses a partial viewport.
burkkyy added the enhancement label 2026-09-30 18:39:27 -07:00
burkkyy added this to the sophia project 2026-09-30 18:40:06 -07:00
Sign in to join this conversation.