-
-
Notifications
You must be signed in to change notification settings - Fork 4.3k
Description
Bevy version
0.15.0
Relevant system information
- cargo 1.83.0 (5ffbef321 2024-10-29)
- MacOS Sonoma 14.1.1 (23B81)
- SystemInfo { os: "MacOS 14.1.1 ", kernel: "23.1.0", cpu: "Apple M1 Max", core_count: "10", memory: "64.0 GiB" }
- AdapterInfo { name: "Apple M1 Max", vendor: 0, device: 0, device_type: IntegratedGpu, driver: "", driver_info: "", backend: Metal }
What you did
I'm using bevy::picking to pick meshes from the main camera. I also have a different camera with some UI overlay that provides context information (it is shown over the objects). In my case I have only few types of entities that can be picked, so instead of marking everything with PickingBehavior::IGNORE I'm just marking which entities I want to be pickable with RayCastPickable (also MeshPickingSettings.require_markers = true).
What went wrong
UI entity always steals all pointer events:

All this happens despite both entity and its camera having no RayCastPickable marker:


Additional information
The only workaround so far is to manually mark every UI node with PickingBehavior::IGNORE but this becomes very tedious and error prone with ever increasing number of different entities.
Example code:
use bevy::prelude::*;
use bevy::render::view::RenderLayers;
use bevy_inspector_egui::quick::WorldInspectorPlugin;
fn main() {
let app = &mut App::new();
app
.add_plugins((
DefaultPlugins,
MeshPickingPlugin, WorldInspectorPlugin::default(),
))
.add_systems(Startup, startup);
app.world_mut().resource_mut::<MeshPickingSettings>().require_markers = true;
app.run();
}
fn startup(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
commands.spawn((
Camera3d::default(),
Transform::from_xyz(2.0, 1.0, 2.0).looking_at(Vec3::ZERO, Vec3::Y),
RayCastPickable,
));
commands.spawn((
PointLight {
shadows_enabled: true,
..default()
},
Transform::from_xyz(4.0, 8.0, 4.0),
));
commands.spawn((
Mesh3d(meshes.add(Cuboid::from_length(1.0))),
MeshMaterial3d(materials.add(Color::srgb(1.0, 0.0, 0.0))),
RayCastPickable,
))
.observe(on_pointer_enter)
.observe(on_pointer_leave);
let ui_camera = commands.spawn((
Name::new("UI Camera"),
Camera2d,
Camera {
clear_color: ClearColorConfig::None,
order: 1,
..default()
},
RenderLayers::layer(1),
)).id();
commands.spawn((
Name::new("UI Node"),
Node {
position_type: PositionType::Absolute,
top: Val::Percent(33.0),
width: Val::Percent(100.0),
height: Val::Percent(33.0),
..default()
},
TargetCamera(ui_camera),
BackgroundColor(Color::WHITE.with_alpha(0.1)),
));
}
fn on_pointer_enter(
event: Trigger<Pointer<Over>>,
query: Query<&MeshMaterial3d<StandardMaterial>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
if let Ok(material) = query.get(event.target) {
if let Some(material) = materials.get_mut(material) {
material.base_color = Color::srgb(0.0, 0.0, 1.0);
}
}
}
fn on_pointer_leave(
event: Trigger<Pointer<Out>>,
query: Query<&MeshMaterial3d<StandardMaterial>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
if let Ok(material) = query.get(event.target) {
if let Some(material) = materials.get_mut(material) {
material.base_color = Color::srgb(1.0, 0.0, 0.0);
}
}
}