From 169254b9384f14db89f5ea7bca488650677a0ecb Mon Sep 17 00:00:00 2001 From: Jannik Obermann <50554200+jannik4@users.noreply.github.com> Date: Tue, 1 Jul 2025 00:46:44 +0200 Subject: [PATCH] Fix sprite picking viewport (#19747) # Objective Fixes sprite picking when using a viewport. Related to #19744. ## Solution - Do not substract `viewport.min` as `Camera::viewport_to_world` already does that. - Skip pointers outside the viewport. ## Testing Tested with the following example:
Click to expand code ```rust use bevy::{ prelude::*, render::camera::Viewport, window::SystemCursorIcon, winit::cursor::CursorIcon, }; fn main() -> AppExit { App::new() .add_plugins(DefaultPlugins) .add_systems(Startup, setup) .insert_resource(ClearColor(Color::BLACK)) .run() } fn setup(mut commands: Commands, window: Single<&Window>) { commands.spawn(( Camera2d, Camera { clear_color: ClearColorConfig::Custom(Color::WHITE), viewport: Some(Viewport { physical_position: UVec2::new( window.physical_width() / 4, window.physical_height() / 4, ), physical_size: UVec2::new( window.physical_width() / 2, window.physical_height() / 2, ), ..default() }), ..default() }, )); commands .spawn(( Transform::from_xyz(100.0, 100.0, 0.0), Sprite::from_color(Color::srgb(0.0, 1.0, 0.0), Vec2::new(200.0, 200.0)), Pickable::default(), )) .observe( |trigger: On>, mut transform: Query<&mut Transform>| { let mut transform = transform.get_mut(trigger.target()).unwrap(); transform.translation.x += trigger.delta.x; transform.translation.y -= trigger.delta.y; }, ) .observe( |_: On>, window: Single>, mut commands: Commands| { commands .entity(*window) .insert(CursorIcon::from(SystemCursorIcon::Grabbing)); }, ) .observe( |_: On>, window: Single>, mut commands: Commands| { commands.entity(*window).remove::(); }, ); } ```
--- crates/bevy_sprite/src/picking_backend.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/crates/bevy_sprite/src/picking_backend.rs b/crates/bevy_sprite/src/picking_backend.rs index bde1a34b63..cda9955b95 100644 --- a/crates/bevy_sprite/src/picking_backend.rs +++ b/crates/bevy_sprite/src/picking_backend.rs @@ -145,13 +145,15 @@ fn sprite_picking( continue; }; - let viewport_pos = camera - .logical_viewport_rect() - .map(|v| v.min) - .unwrap_or_default(); - let pos_in_viewport = location.position - viewport_pos; + let viewport_pos = location.position; + if let Some(viewport) = camera.logical_viewport_rect() { + if !viewport.contains(viewport_pos) { + // The pointer is outside the viewport, skip it + continue; + } + } - let Ok(cursor_ray_world) = camera.viewport_to_world(cam_transform, pos_in_viewport) else { + let Ok(cursor_ray_world) = camera.viewport_to_world(cam_transform, viewport_pos) else { continue; }; let cursor_ray_len = cam_ortho.far - cam_ortho.near;