#bevy_mod_picking: the upstreamening
1 messages · Page 3 of 1
I’m trying to use the new bevy picking with bevy_prototype_lyon but not getting pointer over and pointer out events, when I spawn a plain mesh2d I do get these events (I have added the MeshPickingPlugin, and have the correct observers for each. If one of the picking sme’s here can tell me that there’s nothing else I should need to do then I’ll file a bug report on the bevy_prototype_lyon repo and try to fix this with Nilirad. I’ll post a link the MRE for this once I’m back at my computer. Thanks in advance for your help!
I don't think there is support for mesh2d
As promised here's the MRE repo:
https://github.com/colepoirier/bevy_15_bevy_prototype_lyon_picking_bug_mre
Maybe I'm misunderstanding something but the picking appears to work for the plain Mesh2d in the code
odd, does it have an aabb?
Oh is that how that picking backend works? So if say a mesh2d Rectangle automatically gets an aabb picking will work? But if the bevy_prototype_lyon mesh2d doesn’t get an aabb that’s why this difference in behaviour manifests?
of course no actual 2D ray casting in the XY plane, but you can cast rays against 2D meshes as if they were 3D, which is enough for picking
Cool, for some reason I thought 3d was only implemented
I wanted to use avian2d Colliders with bevy_mod_picking but I think that's not possible for now, right? I will try to implement avian2d backend if that's the case. Should be quite straightforward. Just wanted to ask if there is already a backend for that, that I didn't find. 🙂
there's an avian backend in the works, and one in the mod_picking crate that should be compatible.
Yeah there's a picking backend on Avian's main branch, it will be in the next release
https://github.com/Jondolf/avian/pull/554
ahh nice didn't see that MR 🥳
Report from user that some interactions are broken on mobile
Both browser emulators and phones
Could be that touch pointers are broken? Do the things they are pointing to use the picking events at all?
Probably that. I haven't tested on a touch device yet.
same
I'm trying to figure out from that code why a manually spawned 2d mesh works with that picking code but one spawned via bevy_prototype_lyon does not. I have a MRE of this here (https://github.com/colepoirier/bevy_15_bevy_prototype_lyon_picking_bug_mre) can you provide some guidance on how I could start investigating this? My first thought is that the lyon mesh2d's are somehow 'behind' in layers or z-index or 3d space the point which the rays are being cast from?
You could try a manual ray cast at the mesh with the MeshRayCast system parameter to see if it's a picking-specific issue or if something goes wrong with the actual ray cast
Another thing to check is if the mesh has the correct Aabb, since lyon updates the mesh at runtime. IIRC it does this by swapping the mesh handle though, and I think that should trigger AABB recomputation
Thanks! I tried manually adding a mesh-aabb re-computation system and that had no effect on the picking
fn force_update_aabb(
mut commands: Commands,
shapes: Query<(Entity, &Mesh2d), With<Path>>,
meshes: Res<Assets<Mesh>>,
) {
for (entity, mesh) in shapes.iter() {
let mesh = meshes.get(mesh).unwrap();
let aabb = mesh.compute_aabb().unwrap();
println!("new aabb is {aabb:?}");
commands.entity(entity).insert(aabb);
}
}
new aabb is Aabb { center: Vec3A(0.0, 0.0, 0.0), half_extents: Vec3A(130.0, 130.0, 0.0) }
new aabb is Aabb { center: Vec3A(0.0, 0.0, 0.0), half_extents: Vec3A(130.0, 130.0, 0.0) }
Looks correct to me?
Yup
Where in the picking code could I determine the point (?) that the ray is being cast from?
Looks like bevy_picking/src/backend.rs, ray::RayMap::repopulate
What does ray casting 'at' the mesh mean? Like the ray direction is towards it?
Yes
Thank you, new terminology for me
A ray towards -Z ("away from the screen")
camera.viewport_to_world(camera_tfm, viewport_pos).ok() creates the ray?
Then in theory we could print the ray map to determine the rays?
Yes you could get Res<RayMap> and log them
Thanks for the hand holding through the code, it's well written and logical, but hard to step into a new code base, haven't looked at bevy internals in 2 years
Hmm nothing obvious is jumping out at me after printing out the transforms
Tried printing out the render layers but looks like neither of the two entities uses them (I probably misunderstood the purpose of render layers and they aren't at play here)
I'd still like to know the reason why this isn't working, but I think I'm going to try implementing a point in polygon backend for 2d for now
I'd look at the signature of queries, but last I recall all that is needed is a handle to a mesh, globaltransform, and an Aabb
next step would be to check that the AABB is even being hit by debug printing or using gizmos
Thanks for the guidance!
Was https://docs.rs/bevy_mod_picking/latest/bevy_mod_picking/debug/struct.DebugPickingPlugin.html not ported to bevy_picking?
Logs events for debugging
Correct
Aevyrie said we shouldn't bother
Might make a nice example though
I think that could be useful for implementing backends. Is there a better way to debug picking issues now that picking is upstreamed?
not currently. We'll probably remake that bit.
could be added in a patch release no problem.
Sorry are you saying it won't be useful or it wasn't upstreamed?
Ah sorry misread your message
it might be useful, and it hasn't been upstreamed, but we might make something (new) that's similar
Still trying to debug why bevy_prototype_lyon mesh2d's don't get picked, the gizmo aabb debug are correct
Going to have to println debug the picking process now I think 😅
if you copy the debug stuff from mod_picking into your project it will probably (mostly) work
i was not closely involved with any of the back-end work unfortunately
no idea what could be causing that.
a minimal working reproduction of the issue would go a long way
Does the repo not count as an MRE?
there's a repo 👀
Yup!
No worries, hard to track who see which messages in these threads!
sort of ignored it because it wasn't in my direct area, but i'll take a look
i've got to sign off for the day, but i'll try to have a look tomorrow
nothing stands out as wrong to me
i'm surprised it doesn't work
Me too, no rush on this I've been investigating small amounts with days in between
@flat basin any ideas so far, have had the same issue and haven't been able to find anything obvious, especially since picking a "normal bevy mesh" works
Glad to have someone else to work on finding the root cause!
For some spammy log debugging:
fn debug_aabb(mut config_store: ResMut<GizmoConfigStore>) {
let (_, config) = config_store.config_mut::<AabbGizmoConfigGroup>();
config.default_color = Some(HOT_PINK.into());
config.draw_all = true;
}
fn debug_rays(rays: Res<RayMap>, debug: Res<DebugPicking>, mut ray_cast: MeshRayCast) {
if debug.0 {
rays.iter().for_each(|(id, ray)| {
debug!("ray: {id:?} => {ray:?}");
let visibility = RayCastVisibility::Any;
let settings = RayCastSettings::default()
.with_visibility(visibility)
.never_early_exit();
let hits = ray_cast.cast_ray(*ray, &settings);
debug!("{hits:#?}");
});
}
}
fn debug_picking(mut mouse_event: EventReader<PointerHits>, debug: Res<DebugPicking>) {
if debug.0 {
for ev in mouse_event.read() {
trace!("{ev:?}");
}
}
}
Sorry haven’t had the time to annotate with println debugging myself
I’ll run this when I have time (probably Thursday pst)
Thanks for the debugging code!
Next is probably to add printlns within the internal picking functions and systems
This is something that I wish we could write a unit test for
I'll definitely continue hacking on it tonight and have a 3hr train ride tomorrow I should be able to dedicate to that
Here’s hoping by the time I get around to testing you’ve already solved it 😁
fn debug_rays2(
mouse: Query<&PointerLocation>,
debug: Res<DebugPicking>,
mut ray_cast: MeshRayCast,
camera_query: Query<(&Camera, &GlobalTransform)>,
) {
if debug.0 {
let (camera, camera_transform) = camera_query.single();
mouse
.iter()
.filter_map(|p| p.location.as_ref())
.for_each(|loc| {
let pos = camera
.viewport_to_world_2d(camera_transform, loc.position)
.unwrap()
.extend(-1000.0);
let ray = Ray3d::new(pos, Dir3::Z);
debug!("ray: {ray:?}");
let visibility = RayCastVisibility::Any;
let settings = RayCastSettings::default()
.with_visibility(visibility)
.never_early_exit();
let hits = ray_cast.cast_ray(ray, &settings);
debug!("{hits:#?}");
});
}
}
Hah, it's pickable from below
If I am interpreting that correctly
probably a normals issue then
.extend(1000.0);
let ray = Ray3d::new(pos, Dir3::NEG_Z);
instead of the above doesn't hit
would you expect the issue being in bevy or bevy_prototype_lyon?
a bit of both. maybe lyon's normals are backwards for some reason, but we should probably still hit faces with backwards normals ideally.
Is there an easy way to override "all of bevy" to be from a local path? I seem to have to override each of bevy_* to not have two different versions pulled in using [patch.crates-io]
https://github.com/bevyengine/bevy/blob/main/crates/bevy_picking/src/mesh_picking/ray_cast/mod.rs#L279 flipping that to Include fixes the issue, but seems to originally have been intentional to not include those hits?
@thick umbra opinions on raycast backface culling?
the renderer dosn't seem to distinguish faces for 2d meshes
so there's a visual discrepancy currently
Maybe the ray casting should always use Backfaces::Include just for 2D meshes?
For 3D it makes sense to cull by default I think
i'd be cool with that
we don't render 3d backfaces, so it would be confusing not to cull there
No
https://github.com/blip-radar/bevy/commit/0f4c240562a9e330941614c5307994be39f738eb That fixes it for me and should only apply to Mesh2d
Can you PR this?
@summer talon does that look like a proper fix?
I previously had no idea how the code works and not really sure this is completely correct
maybe? it looks like a fix. But something's up with RayCastBackfaces, maybe we should just have Mesh2d require RayCastBackfaces?
That feels wrong: picking is optional
Thanks for investigating and finding the issue, I don’t think I’d have found it 🙂
backfaces should probably not be a marker component, but matched by value.
Not sure if this question makes sense but could we… flip(?) the bevy prototype lyon mesh2d’s?
The problem is winding order
So the backfaces become front faces?
Nonetheless if the backfaces are rendered by Camera2d it seems illogical to not be able to pick them
Ideally it should match whatever the mesh/camera is set to.
Am I misunderstanding the problem? My interpretation of the description of the issue is that the lyon shapes are being rebdered flipped upside down. Why can’t we fix the issue by flipping the lyon meshes?
We can and should do that
But bevy_picking should be robust to this
Since you never want to do this deliberately
Ah ok, thank you, my understanding of rendering is almost non-existent
Yeah so in 3D it makes sense to be "inside" something
But in 2D, if something is visible you should always be able to select it
Even if it's somehow upside down
Thanks for the eli5 🙂
Really appreciate yours and everyone else’s help with this, I’d have just kept trying to figure it out periodically and getting frustrated that I couldn’t figure out what was wrong
You generally only want to render the triangles of a mesh that are facing the camera. In 2D, you probably don't want this, because you might want to flip your mesh and see the backside. Bevy does not cull backfaces of 2D meshes, so picking raycasts shouldn't either.
As far as I know, there isn't really even a concept of backface or frontface in 2d, because it's an optimizaiton that only really makes sense for 3d shapes that have volume, where there will always be front-facing triangles covering up backfacing triangles.
Thanks for the eli5 from you as well Aevyrie 🙂
Doing a little review of some of the open groups. It seems like there is still a reasonable amount of picking work to do on the ui integration side. I think we should keep this group open thought the 0.16 cycle until the integration seems stable and complete.
@summer talon @stoic flicker PR opened: https://github.com/bevyengine/bevy/pull/16657
Objective
This fixes raycast picking with lyon
reverse winding of 2D meshes currently results in them being rendered but not pickable as the raycast passes through the backface and would only hit ...
https://github.com/bevyengine/bevy/pull/16103 got merged before I could bring this up, but how do you deal with non-window render targets? e.g. image render targets.
For example, I have my entire game scene rendered to a texture, with custom pointer events set to the texture as the location target. Where should the events be propagated here?
Ah, the inverse problem of https://github.com/bevyengine/bevy/issues/16046 😅
I think the solution would be essentially the same. Instead of treating the window entity as the lowest hit, treat the viewport entity as the lowest hit. Because the viewport is in the UI, this coulde also bubble up to the root and thus the window.
I don't think this is the inverse, these are effectively one and the same - if you want this behavior you need a robust viewport widget.
The viewport widget handles both mapping picks on the surface into the camera's world, as well as bubbling up any inputs that fail to hit anything else.
(That's what I meant :p) Thanks for the info aevyrie
Fully agreed
But how do you determine the viewport entity just from the image handle?
presumably you have a system running to do this, so you are querying the viewport component on some entity
I guess you need a new mechanism for that. Currently, Traversal<T> only has access to the Pointer<E> (along with the location's render target), so there's no way to know the entity from there.
Oh wait I guess you can put it inside PointerTraversal somehow? Not really sure how it works.
Oh it's just a query. But I still don't think there's a way to obtain the viewport entity information without a new mechanism.
Your picking backend is just sending an event that says the viewport entity is being hit at the lowest depth. If that ends up being the only thing hit, that sends pointer events to that viewport entity.
So, pretty much identical to the linked window picking PR.
Oh yeah, if I could somehow override it with my own custom impl that'd make it a lot easier. But I don't think there's a way to override PointerTraversal, so I'd not only need to create a custom pointer event, I'd need to override all backends.
I guess I could also make a system that catches all pointer events and sends it to the viewport entity if it has no parent. But it seems inefficient because we're checking twice now.
You don't need to override anything. Just send a PointerHit to the viewport entity when the pointer is interacting with it.
For passing inut, you also need an input plugin for your viewports to inform them what pointers are interacting with the surface, and pipe that into the picking system.
Never mind, I don't think trying to manually implement propagation this way would end well. Stuff like trigger.propagate(false) would just stop working.
Would people be opposed to renaming RayCastSettings to MeshRayCastSettings? It conflicts annoyingly with physics, I need to name my type RayCastConfig because of it
The system param is also MeshRayCast already, and there's MeshPickingSettings
No please do this 🙂
btw, idk if i mentioned this but we were looking at Enter/Leave events and we had two options: do up-traversal every from every hovered object between every two frames and diff, or try to exploit events already doing traversal and do it only when the hover state changes. The latter would be much more efficient, but it can't account for hierarchy changes, so I decided it wasn't going to work.
with the immutable hooks approach to the hierarchy being worked on rn, the second approach becomes feasible again, because we can do automatic cleanup when the hierarchy changes.
so i'm holding off on working on it until the hierarchy stuff is a bit further along, to see which seems more viable.
@summer talon I'm attempting to use the window picking stuff, and something is not working. Specifically, in bevy_input_focus, if an element has focus, keyboard events are dispatched to the focus element which (if not handled) will eventually reach the window; otherwise if there's no focus element, then events are dispatched to the window directly.
However, when I place an observer on the window, I see events which are dispatched to the window directly, but not events which bubbled up from the focus. The focus element is getting the event (and not calling propagate(false)), but the event never reaches the window for some reason.
Do I need to do something special with the event?
hmm, sounds like the window back-end is working but the bubble-to-window traversal is not
i'll look into it, give me a bit
seems like a bug
Actually, I'm probably doing something wrong
are you using custom events or picking events?
Custom events
they need to use PointerTraversal as the traversal strategy
again, this api is kind of raw and unfinished. I'd like to hide some of this behind the event macro.
setting type Traversal = &'static Parent; will only traverse to parents.
the picking pointer events use type Traversal = PointerTraversal;
but they only work with Pointer events
#[derive(QueryData)]
pub struct PointerTraversal {
parent: Option<&'static Parent>,
window: Option<&'static Window>,
}
impl<E> Traversal<Pointer<E>> for PointerTraversal
where
E: Debug + Clone + Reflect,
{
fn traverse(item: Self::Item<'_>, pointer: &Pointer<E>) -> Option<Entity> {
let PointerTraversalItem { parent, window } = item;
// Send event to parent, if it has one.
if let Some(parent) = parent {
return Some(parent.get());
};
// Otherwise, send it to the window entity (unless this is a window entity).
if window.is_none() {
if let NormalizedRenderTarget::Window(window_ref) = pointer.pointer_location.target {
return Some(window_ref.entity());
}
}
None
}
}
the event needs to know which window to dispatch itself to, which means the traversal needs to access that information from the event.
the trait bound `bevy_picking::events::PointerTraversal: bevy_ecs::traversal::Traversal<FocusKeyboardInput>` is not satisfied
the trait `bevy_ecs::traversal::Traversal<bevy_picking::events::Pointer<_>>` is implemented for `bevy_picking::events::PointerTraversal`
for that trait implementation, expected `bevy_picking::events::Pointer<_>`, found `FocusKeyboardInput`
Oh, I need to implement it for my custom event
OK, so keyboard events don't have a window field
if you have a custom event type, I would do something like the following
#[derive(QueryData)]
/// These are for accessing components defined on the targeted entity
pub struct WindowTraversal {
parent: Option<&'static Parent>,
window: Option<&'static Window>,
}
trait HasWindow {
fn get_window(&self) -> Option<Entity>;
}
impl<E> Traversal<E> for WindowTraversal
where
E: HasWindow + Debug + Clone + Reflect,
{
fn traverse(item: Self::Item<'_>, event: &E) -> Option<Entity> {
let WindowTraversalItem { parent, window } = item;
// Send event to parent, if it has one.
if let Some(parent) = parent {
return Some(parent.get());
};
// Otherwise, send it to the window entity (unless this is a window entity).
if window.is_none() {
event.get_winddow()
}
None
}
}
then you can implement HasWindow on your custom events, and use WindowTraversal
this api is... very convoluted and low level
i would like to wrap it up into something nice, but you are the first person to use it other than me in bevy_picking
but it is very flexible.
because you can now have events propagate in arbitrary ways depending on both the components of the current entity, and the data contained within the event itself.
but if this doesn't work for your needs we can change it.
@knotty dune (forgot to ping in response)
So first problem is that I can't use PointerTraversalItem because its fields are private.
There's a larger issue, though, which is for keyboard events, which window should we propagate to? I'm assuming the PrimaryWindow
I guess we will have to modify FocusKeyboardEvent to have a window field
that's sort of the problem, event's can't currently split, they have to go exactly one way during propagation.
we could allow them to split and go to multiple entities (that would allow downward propagation) but I remember it being complex to implement.
The good news is that we do know the primary window when the event is triggered
Here's the logic:
// If an element has keyboard focus, then dispatch the key event to that element.
if let Some(focus_elt) = focus.0 {
for ev in key_events.read() {
commands.trigger_targets(FocusKeyboardInput(ev.clone()), focus_elt);
}
} else {
// If no element has input focus, then dispatch the key event to the primary window.
// There should be only one primary window.
if let Ok(window) = windows.get_single() {
for ev in key_events.read() {
commands.trigger_targets(FocusKeyboardInput(ev.clone()), window);
}
}
}
I might be able to make it so that you can pull in the primary window from the ecs somehow
having to put it into the event is not super nice.
interesting. this will bounce to the focused element after the initial entity that is targeted, and then directly to the window.
Not sure I understand
I mean, this is really a question of "how should keyboard shortcuts in multi-window apps behave?", which is not a question we can really answer. However, you can always install a keyboard listener on the UI root for each window, so in a sense it doesn't matter what we decide, because you can override it.
In any case, I guess what we need to do is change:
pub struct FocusKeyboardInput(pub KeyboardInput);
into
pub struct FocusKeyboardInput {
input: pub KeyboardInput,
window: Entity,
}
yeah, basically, and then do the song and dance to implement the traversal for that type.
i feel like keyboard events should go to whatever window the mouse is hovering. If you have multiple mice then you'd need a custom seats abstraction.
but then, what if you don't have a mouse... what if you're on a touch screen.
not something we need to solve now, but will be a headache if it ever comes up
Well, the dispatcher is just a system so you can do whatever you want
But I don't think I can implement this as things stand
why not?
That is, I don't think I can implement PointerTraversal, because of the private fields
yeah, you'll need to define a new traversial type that implements QueryData. Like #1236111180624297984 message
// The event we want to propagate
pub struct FocusKeyboardInput {
/// The keyboard input payload
input: pub KeyboardInput,
/// The window we want to propagate to after we visit all the ancestors
window: Entity,
}
impl Event for FocusKeyboardInput {
type Traversal = FocusTraversal;
const AUTO_PROPAGATE: bool = true;
}
#[derive(QueryData)]
/// The type that knows how to propagate a `FocusKeyboardInput` event
pub struct FocusTraversal {
/// Gets the `Parent` component on the current target, if it has one
parent: Option<&'static Parent>,
/// Gets the `Window` component on the current target, if it has one
window: Option<&'static Window>,
}
/// The propagation logic
impl Traversal<FocusKeyboardInput> for FocusTraversal {
/// Traverses to the parent, if one exists, then to the window indicated in the event.
/// Stops propagation when the current target is a window.
fn traverse(item: Self::Item<'_>, event: &FocusKeyboardInput) -> Option<Entity> {
// Access the query data on the current target.
let FocusTraversalItem { parent, window } = item;
// If the current target is a window, stop propagating.
if window.is_some() {
return None;
}
// If the current target has a parent, propagate to the parent.
if let Some(parent) = parent {
return Some(parent.get());
};
// If the current taget has no parent (we have reached the root) send it to the window entity specified in the event.
Some(event.window)
}
}
that ought to do it
FocusTraversalItem is created automatically by the QueryData derive
Why is window a Window and not an Entity?
FocusTraversal is pulling data off the entity that is being visited by the observer executor.
we query for window because we want to know if we are already on a window.
if we didn't check that, it would get to the window, see that it has no parents, and propagate to the window again
and get suck in a loop
I added some more context to the example above, hope it helps.
I would assume only the focused window can receive keyboard events
Does winit expose that?
Oh hey it has a whole api for which window has keyboard focus.
@fluid sandal @summer talon @stoic flicker https://github.com/bevyengine/bevy/pull/16795
Nice! I’m going to play around with the traversal api to make custom implementations a bit more ergonomic.
Notice in particular how the tab groups are out of order - this gives you flexibility in determining the tab order within your UI, so it doesn't have to be strictly based on ECS order, although ECS order is the default.
Note: we still need to do the work of hooking this up to bevy_a11y::Focus
Looking good!
Something that I'm not planning on doing, but which would be a nice project for someone else, is to come up with a "gamepad navigation" add-on which uses the on-screen coordinates of the current focus element, and then searches for the next element in the left/right/up/down direction.
@summer talon So with regard to Enter/Leave events, there's a solution that can work today that is not too difficult:
- User adds a
Hovering(pub bool)component to any entity which is interested in getting enter/leave events. - An ECS system iterates through all
Hoveringcomponents, and sets the inner value based on whether it is an ancestor of the current entity in the hover map. - Regular Bevy change detection can now be used to detect enter and leave on a per-entity basis.
/// Component which indicates that the entity is interested in knowing when the mouse is hovering
/// over it or any of its children.
#[derive(Debug, Clone, Copy, Component, Default)]
pub struct Hovering(pub bool);
// Note: previously this was implemented as a Reaction, however it was reacting every frame
// because HoverMap is mutated every frame regardless of whether or not it changed.
pub(crate) fn update_hover_states(
hover_map: Option<Res<HoverMap>>,
mut hovers: Query<(Entity, &mut Hovering)>,
parent_query: Query<&Parent>,
) {
let Some(hover_map) = hover_map else { return };
let hover_set = hover_map.get(&PointerId::Mouse);
for (entity, mut hoverable) in hovers.iter_mut() {
let is_hovering = match hover_set {
Some(map) => map.iter().any(|(ha, _)| {
*ha == entity || parent_query.iter_ancestors(*ha).any(|e| e == entity)
}),
None => false,
};
if hoverable.0 != is_hovering {
hoverable.0 = is_hovering;
}
}
}
that's a pretty reasonable way of doing things. if you want an observer, i have plans but as i mentioned above it's more complex because you have to capture and respond to hierarchy changes.
Is there a new or more up to date tracking issue for this working group? Interested in seeing if there's work I could contribute here but the issue linked in the OP is marked as completed
The bulk of it is complete: now we're just adding more features and fixes 🙂
That said, folks have been missing the debug picking plugin from bevy_mod_picking
And I'll want reviews on my Interaction work soon
Sounds good - I'll glance through the debug stuff to see if there's a reasonable slice to take from there, may just continue looking around the issue tracker for other areas that spark interest too
So, just a general rough breakdown question here - is the work here:
- Upstream the
DebugPickingPlugin, fixing any issues that may have been introduced as other parts ofbevy_mod_pickingwere pulled intobevy_picking - Add examples
- Add / verify support for
MeshPickingPlugin
I believe so!
Mesh picking should already work though
Ah, good to know, I didn't see a direct 1:1 in bevy_picking so I assumed that it was more recent / might not be compatible for some unforeseen reason
It's mostly a direct port.
mod_raycast was also upstreamed as a meshraycast systemparam.
First stumbling block I think... we'd need a dependency on bevy_ui for actually doing the debug draw, but bevy_ui itself has a dependency on bevy_picking
Not really sure what the correct path forward here would be, feels like we need to extract a subset of one of the dependencies into a common crate to break the dependency cycle but no real idea on what to move
I suppose the best option is moving it out of bevy_picking and into bevy_dev_tools?
Exactly
Can you not layer the debug ui on top of both bevy_ui and bevy_picking?
Thanks you two - and yeah, the debug ui being in bevy_dev_tools is effectively doing what you suggested, Talin
Was the selection feature (bevy_picking_selection) excluded intentionally, or is it work that's still pending potential implementation?
This was intentionally excluded because it's very opinionated. We could add a selection module to bevy_input_focus in the future though
It's also an absolutely tiny standalone crate that you can fork and maintain yourself.
I think it's a single file.
Was just curious since there was some specific debug code that handled aggregating and printing related info with the feature enabled
Yup, not particularly important imo
While you're around, @fluid sandal , had another related question - there was a DragMap struct that was removed in the process of upstreaming, but it seemed to only be implemented (& relevant?) for usage with bevy_egui. Any thoughts on if it would be useful / feasible to port something similar for drag events after the initial upstreaming is done?
Huh, that is surprising, I would expect that to still be around, you need it to track drags between pointers.
looks like it is here now: PointerState
State for all pointers.
Ahh, though still, AFAICS, it was only used in the debug.rs file for populating PointerDebug.drag_start, which seems to only have actually been used in the debug_draw_egui code path
Yeah I can elaborate on this change if needed, drag map was combined with some other state to make the event ordering better specified.
Didn't know if the omission in the "normal" debug_draw method was intentional
If you'd like to provide community review for some refactoring I have a PR up here!
I left another note, sorry for the delay!
I'll try to get caldera loaded again and check tonight.
Oh sweet, will take a look when I get a chance. I didn't want to keep bugging you in case you were busy ^^
No worries. Life is pretty busy, I don't mind pings, I just can't promise I will be able to do anything about it. 🙂
not too shabby
Left an approval, did some testing, and your PR is faster than main, so I'd say ship it. 🙂
I migrating to bevy_picking and noticed that if I have UI on the scene, I can't pick avian colliders, for example.
Is this expected?
In my game I have a UI node that takes the entire screen, but it's transparent and have some buttons on it.
Ah, I need to use PickingBehavior::IGNORE
Yeah, this has been a common issue, but we haven't decided if changing behavior is the right call here.
That's not what this does
But I agree. The backend plugins should probably not be added in the DefaultPlugins
oh, yeah haven't looked at the code yet tbh