Skip to content

Add support for custom picking data#23245

Merged
alice-i-cecile merged 11 commits into
bevyengine:mainfrom
m-edlund:generic-picking-hit-data
Apr 23, 2026
Merged

Add support for custom picking data#23245
alice-i-cecile merged 11 commits into
bevyengine:mainfrom
m-edlund:generic-picking-hit-data

Conversation

@m-edlund

@m-edlund m-edlund commented Mar 6, 2026

Copy link
Copy Markdown
Contributor

Objective

Solution

  • Adds an extra field to the HitData struct which can take any Data that implements HitDataExtra. This is stored in an Arc which can be downcast with a helper function in the system that consumes the hit.
  • In the original ticket I suggested using a generic, however this caused extensive code changes and complications down the line with the HoverMap and OverMap so I decided against it.

Testing

  • I added an example custom_hit_data to test the new feature
  • I tested all other picking examples to ensure they still work as expected
  • I tested the examples on Ubuntu
  • I additionally tested the custom_hit_data example in wasm

Showcase

Click to view showcase

Creating custom hits:

let picks: Vec<(Entity, HitData)> = ray_cast
            .cast_ray(ray, &settings)
            .iter()
            .map(|(entity, hit)| {
                let extra = TriangleHitInfo {
                    triangle_vertices: hit.triangle,
                };

                let hit_data = HitData::new_with_extra(
                    ray_id.camera,
                    hit.distance,
                    Some(hit.point),
                    Some(hit.normal),
                    extra,
                );

                (*entity, hit_data)
            })
            .collect();

Reading custom hits:

   for hits in pointer_hits.read() {
        for (_, hit) in &hits.picks {
            let Some(info) = hit.extra_as::<TriangleHitInfo>() else {
                continue;
            };
            let Some(vertices) = info.triangle_vertices else {
                continue;
            };

            // do something cool with your custom hit data
        }
    }

An example of what you can do with this

image

@kfc35 kfc35 added C-Feature A new feature, making something new possible D-Modest A "normal" level of difficulty; suitable for simple features or challenging fixes S-Needs-Review Needs reviewer attention (from anyone!) to move forward A-Picking Pointing at and selecting objects of all sorts labels Mar 6, 2026

@kfc35 kfc35 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This is cool. I approve. I checked out the branch and the example works.

The overarching comment I have is that the example can be improved to be more beginner friendly for comprehension, since examples serve as documentation of sorts and that code is accessible for people to read. I made a bunch of smaller comments to help with that.

Comment thread examples/picking/custom_hit_data.rs
Comment thread examples/picking/custom_hit_data.rs
Comment thread examples/picking/custom_hit_data.rs
Comment thread examples/picking/custom_hit_data.rs
Comment thread examples/picking/custom_hit_data.rs Outdated
@m-edlund

Copy link
Copy Markdown
Contributor Author

Is #23285 considered a blocker? The new example uses no Interaction, so I assumed it should be independent of the changes in that PR.

@kfc35

kfc35 commented Apr 22, 2026

Copy link
Copy Markdown
Contributor

@m-edlund I don’t think it’s considered a blocker. As someone who reviewed that PR, I think the author may have been mistaken.

Also, I saw your message on Discord regarding this PR. Sorry others haven’t been able to review! I think after the 0.19 milestone is cut, people will have more bandwidth to consider reviewing this. I’m not sure if this will get merged because we are only focusing on merging bug fixes currently, but I’ll try bumping your message one time to see if we can get anyone else to look at the PR. Since I don’t think it would add that much complication, maybe it can be considered.

&& self.depth == other.depth
&& self.position == other.position
&& self.normal == other.normal
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why doesn't this check extra? This should be documented and justified in that documentation.

It looks like PartialEq is derived for all events, I'm not sure if they are deduplicated somewhere.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Equality would require downcasting both sides every time there is a comparison (https://users.rust-lang.org/t/how-to-compare-two-trait-objects-for-equality/88063), which feels overkill. The explanation was added in e7c410d

Comment thread crates/bevy_picking/src/backend.rs Outdated
Comment thread crates/bevy_picking/src/backend.rs Outdated
/// }
/// }
/// ```
pub trait HitDataExtra: Any + Send + Sync + fmt::Debug {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should this have a name method or similar to help aid debugging / figure out what to downcast to?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Since HitDataExtra requires Debug, devs can just print the hit data to help with debugging at runtime. So unless I'm missing something, a name function feels like it just duplicates what Debug is already doing.

Comment thread crates/bevy_picking/src/backend.rs
Comment thread crates/bevy_picking/src/backend.rs Outdated

@alice-i-cecile alice-i-cecile left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

On board with the motivation. The prior art was really compelling, thanks! Good docs, broadly solid implementation. Fixes needed:

  • the upcasting strategy needs cleanup
  • I would like a unit test
  • the choice of Arc is good but needs clear documentation

Other feedback is non-blocking, but I am curious about your thoughts :)

Comment thread crates/bevy_picking/src/backend.rs Outdated
@m-edlund
m-edlund force-pushed the generic-picking-hit-data branch from d4c67be to 94183a8 Compare April 23, 2026 10:38
@alice-i-cecile alice-i-cecile added S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it and removed S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Apr 23, 2026
@alice-i-cecile
alice-i-cecile added this pull request to the merge queue Apr 23, 2026
Merged via the queue into bevyengine:main with commit c3c118c Apr 23, 2026
44 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-Picking Pointing at and selecting objects of all sorts C-Feature A new feature, making something new possible D-Modest A "normal" level of difficulty; suitable for simple features or challenging fixes S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Extend the information included in HitData

4 participants