Skip to content

Conversation

BigWingBeat
Copy link
Contributor

Objective

Fixes #20399

Solution

Realistically this should have been PR'd a lot earlier, but I was unable to work on it for a couple of weeks. Most of the changes described in the issue have been implemented, plus some extra stuff that turned out to also be needed.

The SubCameraView struct has been entirely changed. Rather than the behaviour of the sub view being controlled by implicit and poorly documented interactions between its fields, it now has two independent fields with intuitive behaviours.

/// Old layout
pub struct SubCameraView {
    /// Size of the entire camera view
    pub full_size: UVec2,
    /// Offset of the sub camera
    pub offset: Vec2,
    /// Size of the sub camera
    pub size: UVec2,
}

/// New layout
pub struct SubCameraView {
    /// Scaling factor for the size of the sub view. The height of the sub view will be scale * the height of the base view
    pub scale: f32,
    /// Percentage offset of the top-left corner of the sub view, from top-left at `0,0` to bottom-right at `1,1`
    pub offset: Vec2,
}

The docs on this type have also been updated, I think the new example does a far better job of explaining what a sub view is than the old one.

There is also a new addition to the API, the SubViewSourceProjection and SubViewsUsingThisProjection relationship components. Certain use cases for sub views can be boiled down to "visually alter part of the screen". The example I wrote for this uses magnification, but it also includes applying arbitrary shader effects. Under the previous impl, these use cases required the user to write some incredibly non-intuitive, foot-gunny math to make the effect work. The new relationship components can optionally be inserted onto a camera with a sub view, to alter the behaviour of the sub view in a way that drastically simplifies this math.

Part of implementing these relationship components required making some minor additional changes to the API.

  • The signature of the get_clip_from_view_for_sub on the CameraProjection trait has changed slightly. I don't think this is relevant for most users, as it only affects custom projection impls (which are quite rare), and even then, such impls typically wrap one of Bevy's built-in projections, to which the method call is forwarded. This can be seen in the change to the custom projection example.
  • The camera_system is no longer public, due to it now being part of a piped system. I think this also doesn't affect much, as it already wasn't directly referenced anywhere within bevy itself, thanks to the CameraUpdateSystems system set, which already existed and was already being used for exactly this.

The existing camera sub view example has been entirely re-written, and now demonstrates a specific, simple use case for sub views. Namely, splitting an image across multiple render targets. There is also a new magnifier example, which shows a more complex way of using sub views to magnify part of the screen.

Testing

I added some unit tests for the SubViewSourceProjection relationship behaviour, and also tested that sub views work correctly in general, by running the examples and confirming that they visually look correct. I also tested the examples with orthographic projections, to confirm that sub views work properly with those too, but that hasn't been included in the PR.


Showcase

The SubCameraView API has been refactored to be much more intuitive to use, and also has drastically improved documentation and examples.

Old API:

// What are these magic numbers?
camera.sub_camera_view = Some(SubCameraView {
    full_size: UVec2::new(32, 18),
    offset: UVec2::new(0, 9),
    size: UVec2::new(16, 9),
});

New API:

// Just pass in the fractions you want directly
camera.sub_camera_view = Some(SubCameraView {
    scale: 0.5,
    offset: Vec2::new(0.0, 0.5),
});

Copy link
Contributor

github-actions bot commented Oct 7, 2025

The generated examples/README.md is out of sync with the example metadata in Cargo.toml or the example readme template. Please run cargo run -p build-templated-pages -- update examples to update it, and commit the file change.

@alice-i-cecile alice-i-cecile added C-Bug An unexpected or incorrect behavior A-Rendering Drawing game state to the screen C-Usability A targeted quality-of-life change that makes Bevy easier to use M-Needs-Migration-Guide A breaking change to Bevy's public API that needs to be noted in a migration guide labels Oct 7, 2025
@alice-i-cecile alice-i-cecile added the S-Needs-Review Needs reviewer attention (from anyone!) to move forward label Oct 7, 2025
@BigWingBeat BigWingBeat force-pushed the camerasubview_refactor branch from 9d36bcf to 31a2dbb Compare October 7, 2025 21:23
Copy link
Member

@tychedelia tychedelia left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested with a variety of values and verified working.

This is out of scope of this PR but it's possible to trigger a crash when resizing the window.

Caused by:
  In a CommandEncoder
    In a set_scissor_rect command
      Scissor Rect { x: 452, y: 0, w: 200, h: 200 } is not contained in the render target (652, 180, 1)

Need to more closely review the implementation, but the high-level API does seem improved.

@tychedelia tychedelia added this to the 0.18 milestone Oct 8, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-Rendering Drawing game state to the screen C-Bug An unexpected or incorrect behavior C-Usability A targeted quality-of-life change that makes Bevy easier to use M-Needs-Migration-Guide A breaking change to Bevy's public API that needs to be noted in a migration guide S-Needs-Review Needs reviewer attention (from anyone!) to move forward

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

Refactor SubCameraView

3 participants