-
-
Notifications
You must be signed in to change notification settings - Fork 3.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Raycasting #615
Raycasting #615
Conversation
I think we probably don't need a separate crate for this. I'd just add a method to the existing Wherever As far as where to put the |
Having to access the window is a bit inconvenient, but gets the current information. |
How would you? I think right now it's necessary to first query for a |
I was trying to suggest that the size is kept up to date between the |
I mean, right, you have to get the Camera and Windows resources to your system, but then just pass them to the casting method and let the raycaster pull whatever information it wants. |
} | ||
|
||
pub fn from_mouse_position( | ||
mouse_position: &Vec2, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Window now has .cursor_position()
method. We could add:
pub fn from_window(
window: &Window,
camera: &Camera,
camera_transform: &GlobalTransform,
) -> Self {
Self::from_mouse_position(window.cursor_position(), camera, camera_transform)
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice. I'll add it.
examples/physics/raycast.rs
Outdated
|
||
let hit = if let Some(plane_hit) = plane_hit { | ||
if let Some(sphere_hit) = sphere_hit { | ||
if plane_hit.t() < sphere_hit.t() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have 6 nested (for and if) statements here, that is very complex.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Although I disagree with 6 nested blocks being inherently complex, I agree that this particular instance is unnecessarily verbose and doesn't get the point across. I'm looking for something more elegant but feel free to propose changes where you see fit.
use glam::Vec3; | ||
|
||
pub struct RayHit { | ||
t: f32, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please consider renaming it to something more meaningful.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a good idea!
|
||
impl RayIntersector for Plane { | ||
fn intersect_ray(&self, ray: &Ray) -> Option<RayHit> { | ||
let d = self.normal().dot(*ray.direction()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please describe what is this line doing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It assigns the dot product between the plane normal and the ray direction to the variable d (now changed to denominator). I don't think that needs a comment.
let d = self.normal().dot(*ray.direction()); | ||
if d.abs() > f32::EPSILON { | ||
let t = (*self.center() - *ray.origin()).dot(*self.normal()) / d; | ||
if t > 0.0 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am guessing the t and d is taken from some formula. We can give it a more verbose name in our code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would agree and have changed the names.
camera_transform: &GlobalTransform, | ||
) -> Self { | ||
if window.id() != camera.window { | ||
panic!("Generating Ray from Camera with wrong Window"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correct me if i'm wrong, this can terminate the program?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It can, you're right. This is by design. Passing a non-matching window and camera to from_mouse_position(..) would result in undefined behavior and should be checked before calling the method. Do you think a Log Error would be more sensible? I didn't familiarize myself very much with the Diagnostics Plugin, so maybe that could help.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TBH I don't know the right answer, I am learning here 👍
} | ||
} | ||
} | ||
|
||
impl RayIntersector for Triangle { | ||
// using the Moeller-Trumbore intersection algorithm | ||
// Can anyone think of sensible names for theese? | ||
#[allow(clippy::many_single_char_names)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this allow acceptable?
@@ -54,6 +54,8 @@ struct MouseState { | |||
cursor_position: Vec2, | |||
} | |||
|
|||
// Is there a way to reduce the arguments? | |||
#[allow(clippy::too_many_arguments)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this allow acceptable?
We have a community crate for this now as well: I definitely think this functionality is useful though, and I'm of the opinion that raycasting probably deserves a home in bevy itself once it matures a bit more and we want to build functionality (like the editor, PBR or convenience functions) on top of raycasting. |
I'm not sure merging everything under Bevy umbrella is a sustainable approach. This creates a contract for supporting these things. Maybe it would be better to provide an easy way of adding&integrating 3rd party plugins - like a "plugin store" etc. |
Yeah I've been holding off on this because first party raycasting isn't a priority and its a relatively opinionated feature. In the short term, do I think it makes sense to let the community handle raycasting in 3rd party plugins. Eventually I think we'll need to adopt something officially, at least for the editor. But I think that raycasting is a common enough operation that we will want an official general-purpose solution (in the long term). I also agree that a "plugin store" is a good idea. Crates.io isn't great for Bevy plugin discovery and awesome-bevy isn't great at sorting / prioritizing / finding information. I think eventually we should migrate awesome-bevy to a more interactive / informative alternative on bevyengine.org. It would basically be a database of crates.io links with additional metadata (images, category, etc) and a searchable interface. I can't say I will prioritize that in the short term though :) |
@cart Looking back on this, I still want to push for having 1st party support for at least the bare-minimum functionality that calculates a ray (position, vector) from screen coordinates and a camera (transform, projection). This math is not trivial and can vary based on how the engine implements cameras. I agree that doing much more than that is probably not a high priority. |
@bonsairobo I agree with the need for first-party support. I expect that @aevyrie will be working on a raycasting RFC, following up on the geometric primitives chain of work. |
Thanks for the ping. 😄 In short, I agree with:
If you have suggestions for API/features in Until the feature becomes a priority for the engine, we can continue to experiment in external crates without burdening the engine with more code to support. |
most of this exist now in Bevy except ray intersection with a sphere or a triangle |
Adding this as a draft, as I made some assumptions I am unsure of:
bevy_physics
Ray::from_mouse_position(..)
should be a method ofRay
raycast.rs
is as simple as possible (e.g. themove mouse.system()
could certainly be removed)Looking forward to your guys feedback 😄