From beb473f81d75885f3ce885cd27f9da0cba043187 Mon Sep 17 00:00:00 2001 From: Aevyrie Date: Sat, 26 Oct 2024 09:03:28 -0700 Subject: [PATCH 1/7] Remove noisy mesh topology error --- .../bevy_picking/src/mesh_picking/ray_cast/intersections.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/crates/bevy_picking/src/mesh_picking/ray_cast/intersections.rs b/crates/bevy_picking/src/mesh_picking/ray_cast/intersections.rs index 0cea98e566fc3..569e3f71ae634 100644 --- a/crates/bevy_picking/src/mesh_picking/ray_cast/intersections.rs +++ b/crates/bevy_picking/src/mesh_picking/ray_cast/intersections.rs @@ -37,9 +37,7 @@ pub(super) fn ray_intersection_over_mesh( backface_culling: Backfaces, ) -> Option { if mesh.primitive_topology() != PrimitiveTopology::TriangleList { - error!( - "Invalid intersection check: `TriangleList` is the only supported `PrimitiveTopology`" - ); + // ray_mesh_intersection assumes vertices are laid out in a triangle list return None; } From d6ec62dc41375c4515c7b5abbd25571f59ec0156 Mon Sep 17 00:00:00 2001 From: Aevyrie Date: Sat, 26 Oct 2024 09:05:21 -0700 Subject: [PATCH 2/7] Disable the mesh picking plugin by default --- crates/bevy_picking/src/lib.rs | 11 +----- examples/picking/mesh_picking.rs | 28 +++++++++++--- examples/picking/simple_picking.rs | 61 ++++++++++++++++++------------ 3 files changed, 62 insertions(+), 38 deletions(-) diff --git a/crates/bevy_picking/src/lib.rs b/crates/bevy_picking/src/lib.rs index 6c62eb5b142be..b991c45f3c74e 100644 --- a/crates/bevy_picking/src/lib.rs +++ b/crates/bevy_picking/src/lib.rs @@ -284,17 +284,10 @@ impl PluginGroup for DefaultPickingPlugins { reason = "Group is not mutated when `bevy_mesh` is not enabled." ) )] - let mut group = PluginGroupBuilder::start::() + PluginGroupBuilder::start::() .add(input::PointerInputPlugin::default()) .add(PickingPlugin::default()) - .add(InteractionPlugin); - - #[cfg(feature = "bevy_mesh")] - { - group = group.add(mesh_picking::MeshPickingPlugin); - }; - - group + .add(InteractionPlugin) } } diff --git a/examples/picking/mesh_picking.rs b/examples/picking/mesh_picking.rs index 9c0d813042e73..5193c4ea8faee 100644 --- a/examples/picking/mesh_picking.rs +++ b/examples/picking/mesh_picking.rs @@ -1,10 +1,23 @@ //! A simple 3D scene to demonstrate mesh picking. //! -//! By default, all meshes are pickable. Picking can be disabled for individual entities -//! by adding [`PickingBehavior::IGNORE`]. +//! [`bevy::picking::backend`] provides an API for adding picking hit tests to any entity. To get +//! started with picking 3d meshes, the [`MeshPickingPlugin`] is provided as a simple starting +//! point, especially useful for debugging. For your game, you may want to use a 3d picking backend +//! provided by your physics engine, or a picking shader, depending on your specific use case. //! -//! If you want mesh picking to be entirely opt-in, you can set [`MeshPickingSettings::require_markers`] -//! to `true` and add a [`RayCastPickable`] component to the desired camera and target entities. +//! [`bevy::picking`] allows you to compose backends together to make any entity on screen pickable +//! with pointers, regardless of how that entity is rendered. For example, `bevy_ui` and +//! `bevy_sprite` provide their own picking backends that can be enabled at the same time as this +//! mesh picking backend. This makes it painless to deal with cases like the UI or sprites blocking +//! meshes underneath them, or vice versa. +//! +//! If you want to build more complex interactions than afforded by the provided pointer events, you +//! may want to use [`MeshRayCast`] or a full physics engine with raycasting capabilities. +//! +//! By default, the mesh picking plugin will raycast against all entities, which is especially +//! useful for debugging. If you want mesh picking to be opt-in, you can set +//! [`MeshPickingSettings::require_markers`] to `true` and add a [`RayCastPickable`] component to +//! the desired camera and target entities. use std::f32::consts::PI; @@ -19,7 +32,12 @@ use bevy::{ fn main() { App::new() - .add_plugins(DefaultPlugins) + .add_plugins(( + DefaultPlugins, + // The mesh picking plugin is not enabled by default, because raycasting against all + // meshes has a performance cost. + MeshPickingPlugin, + )) .init_resource::() .add_systems(Startup, setup) .add_systems(Update, (on_mesh_hover, rotate)) diff --git a/examples/picking/simple_picking.rs b/examples/picking/simple_picking.rs index d3e3ce2b3fe41..d71e4dcda2254 100644 --- a/examples/picking/simple_picking.rs +++ b/examples/picking/simple_picking.rs @@ -1,14 +1,15 @@ -//! A simple scene to demonstrate picking events +//! A simple scene to demonstrate picking events for UI and mesh entities. -use bevy::{color::palettes::tailwind::CYAN_400, prelude::*}; +use bevy::prelude::*; fn main() { - let mut app = App::new(); - app.add_plugins(DefaultPlugins); - - app.add_systems(Startup, setup); - - app.run(); + App::new() + .add_plugins(( + DefaultPlugins, + MeshPickingPlugin, // Needed for mesh picking, not added by default + )) + .add_systems(Startup, setup) + .run(); } /// set up a simple 3D scene @@ -19,7 +20,7 @@ fn setup( ) { commands .spawn(( - Text::new("Click Me to get a box"), + Text::new("Click Me to get a box\nDrag cubes to rotate"), Node { position_type: PositionType::Absolute, top: Val::Percent(12.0), @@ -27,20 +28,7 @@ fn setup( ..default() }, )) - .observe( - |_click: Trigger>, - mut commands: Commands, - mut meshes: ResMut>, - mut materials: ResMut>, - mut num: Local| { - commands.spawn(( - Mesh3d(meshes.add(Cuboid::new(1.0, 1.0, 1.0))), - MeshMaterial3d(materials.add(Color::srgb_u8(124, 144, 255))), - Transform::from_xyz(0.0, 0.5 + 1.1 * *num as f32, 0.0), - )); - *num += 1; - }, - ) + .observe(on_pointer_click_spawn_cube) .observe( |evt: Trigger>, mut texts: Query<&mut TextColor>| { let mut color = texts.get_mut(evt.entity()).unwrap(); @@ -50,7 +38,7 @@ fn setup( .observe( |evt: Trigger>, mut texts: Query<&mut TextColor>| { let mut color = texts.get_mut(evt.entity()).unwrap(); - color.0 = CYAN_400.into(); + color.0 = bevy::color::palettes::tailwind::CYAN_400.into(); }, ); // circular base @@ -73,3 +61,28 @@ fn setup( Transform::from_xyz(-2.5, 4.5, 9.0).looking_at(Vec3::ZERO, Vec3::Y), )); } + +fn on_pointer_click_spawn_cube( + _click: Trigger>, + mut commands: Commands, + mut meshes: ResMut>, + mut materials: ResMut>, + mut num: Local, +) { + commands + .spawn(( + Mesh3d(meshes.add(Cuboid::new(0.5, 0.5, 0.5))), + MeshMaterial3d(materials.add(Color::srgb_u8(124, 144, 255))), + Transform::from_xyz(0.0, 0.25 + 0.55 * *num as f32, 0.0), + )) + // With the MeshPickingPlugin added, you can add pointer event observers to meshes as well: + .observe( + |drag: Trigger>, mut transforms: Query<&mut Transform>| { + if let Ok(mut transform) = transforms.get_mut(drag.entity()) { + transform.rotate_y(drag.delta.x * 0.02); + transform.rotate_x(drag.delta.y * 0.02); + } + }, + ); + *num += 1; +} From c3e9775ce817c8cd9f6400a8d71d544937ed99a6 Mon Sep 17 00:00:00 2001 From: Aevyrie Date: Sat, 26 Oct 2024 12:26:25 -0700 Subject: [PATCH 3/7] Remove unneeded attribute. --- crates/bevy_picking/src/lib.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/crates/bevy_picking/src/lib.rs b/crates/bevy_picking/src/lib.rs index b991c45f3c74e..0ba8042046073 100644 --- a/crates/bevy_picking/src/lib.rs +++ b/crates/bevy_picking/src/lib.rs @@ -277,13 +277,6 @@ pub struct DefaultPickingPlugins; impl PluginGroup for DefaultPickingPlugins { fn build(self) -> PluginGroupBuilder { - #[cfg_attr( - not(feature = "bevy_mesh"), - expect( - unused_mut, - reason = "Group is not mutated when `bevy_mesh` is not enabled." - ) - )] PluginGroupBuilder::start::() .add(input::PointerInputPlugin::default()) .add(PickingPlugin::default()) From db14b50f082961b709e871ca1b08dae2ab578dd0 Mon Sep 17 00:00:00 2001 From: Aevyrie Date: Sat, 26 Oct 2024 12:36:42 -0700 Subject: [PATCH 4/7] Clean up intersection code and remove tracing events. --- .../bevy_picking/ray_mesh_intersection.rs | 4 +- .../mesh_picking/ray_cast/intersections.rs | 121 ++++++------------ 2 files changed, 42 insertions(+), 83 deletions(-) diff --git a/benches/benches/bevy_picking/ray_mesh_intersection.rs b/benches/benches/bevy_picking/ray_mesh_intersection.rs index 6be84a649dd7b..934e86a9a498d 100644 --- a/benches/benches/bevy_picking/ray_mesh_intersection.rs +++ b/benches/benches/bevy_picking/ray_mesh_intersection.rs @@ -1,5 +1,6 @@ use bevy_math::{Dir3, Mat4, Ray3d, Vec3}; use bevy_picking::{mesh_picking::ray_cast, prelude::*}; +use bevy_render::mesh::Indices; use criterion::{black_box, criterion_group, criterion_main, Criterion}; fn ptoxznorm(p: u32, size: u32) -> (f32, f32) { @@ -10,7 +11,7 @@ fn ptoxznorm(p: u32, size: u32) -> (f32, f32) { struct SimpleMesh { positions: Vec<[f32; 3]>, normals: Vec<[f32; 3]>, - indices: Vec, + indices: Indices, } fn mesh_creation(vertices_per_side: u32) -> SimpleMesh { @@ -31,6 +32,7 @@ fn mesh_creation(vertices_per_side: u32) -> SimpleMesh { indices.extend_from_slice(&[p + vertices_per_side, p + 1, p + vertices_per_side + 1]); } } + let indices = Indices::U32(indices); SimpleMesh { positions, diff --git a/crates/bevy_picking/src/mesh_picking/ray_cast/intersections.rs b/crates/bevy_picking/src/mesh_picking/ray_cast/intersections.rs index 569e3f71ae634..bc56845df185f 100644 --- a/crates/bevy_picking/src/mesh_picking/ray_cast/intersections.rs +++ b/crates/bevy_picking/src/mesh_picking/ray_cast/intersections.rs @@ -1,7 +1,6 @@ use bevy_math::{bounding::Aabb3d, Dir3, Mat4, Ray3d, Vec3, Vec3A}; use bevy_reflect::Reflect; -use bevy_render::mesh::{Indices, Mesh, PrimitiveTopology, VertexAttributeValues}; -use bevy_utils::tracing::{error, warn}; +use bevy_render::mesh::{Indices, Mesh, PrimitiveTopology}; use super::Backfaces; @@ -37,77 +36,33 @@ pub(super) fn ray_intersection_over_mesh( backface_culling: Backfaces, ) -> Option { if mesh.primitive_topology() != PrimitiveTopology::TriangleList { - // ray_mesh_intersection assumes vertices are laid out in a triangle list - return None; - } - - // Get the vertex positions and normals from the mesh. - let vertex_positions: &Vec<[f32; 3]> = match mesh.attribute(Mesh::ATTRIBUTE_POSITION) { - None => { - error!("Mesh does not contain vertex positions"); - return None; - } - Some(vertex_values) => match &vertex_values { - VertexAttributeValues::Float32x3(positions) => positions, - _ => { - error!("Unexpected types in {:?}", Mesh::ATTRIBUTE_POSITION); - return None; - } - }, - }; - let vertex_normals: Option<&[[f32; 3]]> = - if let Some(normal_values) = mesh.attribute(Mesh::ATTRIBUTE_NORMAL) { - match &normal_values { - VertexAttributeValues::Float32x3(normals) => Some(normals), - _ => None, - } - } else { - None - }; - - if let Some(indices) = &mesh.indices() { - match indices { - Indices::U16(vertex_indices) => ray_mesh_intersection( - ray, - mesh_transform, - vertex_positions, - vertex_normals, - Some(vertex_indices), - backface_culling, - ), - Indices::U32(vertex_indices) => ray_mesh_intersection( - ray, - mesh_transform, - vertex_positions, - vertex_normals, - Some(vertex_indices), - backface_culling, - ), - } - } else { - ray_mesh_intersection( - ray, - mesh_transform, - vertex_positions, - vertex_normals, - None::<&[usize]>, - backface_culling, - ) + return None; // ray_mesh_intersection assumes vertices are laid out in a triangle list } + // Vertex positions are required + let vertex_positions = mesh.attribute(Mesh::ATTRIBUTE_POSITION)?.as_float3()?; + // Normals are optional + let vertex_normals = mesh + .attribute(Mesh::ATTRIBUTE_NORMAL) + .and_then(|normal_values| normal_values.as_float3()); + ray_mesh_intersection( + ray, + mesh_transform, + vertex_positions, + vertex_normals, + mesh.indices(), + backface_culling, + ) } /// Checks if a ray intersects a mesh, and returns the nearest intersection if one exists. -pub fn ray_mesh_intersection( +pub fn ray_mesh_intersection( ray: Ray3d, mesh_transform: &Mat4, vertex_positions: &[[f32; 3]], vertex_normals: Option<&[[f32; 3]]>, - indices: Option<&[Index]>, + indices: Option<&Indices>, backface_culling: Backfaces, -) -> Option -where - usize: TryFrom, -{ +) -> Option { // The ray cast can hit the same mesh many times, so we need to track which hit is // closest to the camera, and record that. let mut closest_hit_distance = f32::MAX; @@ -121,32 +76,34 @@ where ); if let Some(indices) = indices { - // Make sure this chunk has 3 vertices to avoid a panic. + // The index list must be a multiple of three. If not, the mesh is malformed and the raycast + // result might be nonsensical. if indices.len() % 3 != 0 { - warn!("Index list not a multiple of 3"); return None; } - // Now that we're in the vector of vertex indices, we want to look at the vertex - // positions for each triangle, so we'll take indices in chunks of three, where each - // chunk of three indices are references to the three vertices of a triangle. - for index_chunk in indices.chunks_exact(3) { - let [index1, index2, index3] = [ - usize::try_from(index_chunk[0]).ok()?, - usize::try_from(index_chunk[1]).ok()?, - usize::try_from(index_chunk[2]).ok()?, - ]; - let triangle_index = Some(index1); + // Iterate over chunks of three indices, representing the corners of a triangle. + let mut indices = indices.iter(); + let mut next_triangle = || { + indices + .next() + .zip(indices.next()) + .zip(indices.next()) + .map(|((a, b), c)| [a, b, c]) + }; + + while let Some(triangle) = next_triangle() { + let triangle_index = Some(triangle[0]); let tri_vertex_positions = [ - Vec3A::from(vertex_positions[index1]), - Vec3A::from(vertex_positions[index2]), - Vec3A::from(vertex_positions[index3]), + Vec3A::from(vertex_positions[triangle[0]]), + Vec3A::from(vertex_positions[triangle[1]]), + Vec3A::from(vertex_positions[triangle[2]]), ]; let tri_normals = vertex_normals.map(|normals| { [ - Vec3A::from(normals[index1]), - Vec3A::from(normals[index2]), - Vec3A::from(normals[index3]), + Vec3A::from(normals[triangle[0]]), + Vec3A::from(normals[triangle[1]]), + Vec3A::from(normals[triangle[2]]), ] }); From ad7745e951a8083f5bcf453bd76fe537d6252e2d Mon Sep 17 00:00:00 2001 From: Aevyrie Date: Sat, 26 Oct 2024 13:19:26 -0700 Subject: [PATCH 5/7] Fix perf regression --- .../bevy_picking/ray_mesh_intersection.rs | 3 +- .../mesh_picking/ray_cast/intersections.rs | 66 ++++++++----------- 2 files changed, 30 insertions(+), 39 deletions(-) diff --git a/benches/benches/bevy_picking/ray_mesh_intersection.rs b/benches/benches/bevy_picking/ray_mesh_intersection.rs index 934e86a9a498d..2ce0252c8ca49 100644 --- a/benches/benches/bevy_picking/ray_mesh_intersection.rs +++ b/benches/benches/bevy_picking/ray_mesh_intersection.rs @@ -11,7 +11,7 @@ fn ptoxznorm(p: u32, size: u32) -> (f32, f32) { struct SimpleMesh { positions: Vec<[f32; 3]>, normals: Vec<[f32; 3]>, - indices: Indices, + indices: Vec, } fn mesh_creation(vertices_per_side: u32) -> SimpleMesh { @@ -32,7 +32,6 @@ fn mesh_creation(vertices_per_side: u32) -> SimpleMesh { indices.extend_from_slice(&[p + vertices_per_side, p + 1, p + vertices_per_side + 1]); } } - let indices = Indices::U32(indices); SimpleMesh { positions, diff --git a/crates/bevy_picking/src/mesh_picking/ray_cast/intersections.rs b/crates/bevy_picking/src/mesh_picking/ray_cast/intersections.rs index bc56845df185f..26f221cc63033 100644 --- a/crates/bevy_picking/src/mesh_picking/ray_cast/intersections.rs +++ b/crates/bevy_picking/src/mesh_picking/ray_cast/intersections.rs @@ -31,36 +31,38 @@ pub struct RayTriangleHit { /// Casts a ray on a mesh, and returns the intersection. pub(super) fn ray_intersection_over_mesh( mesh: &Mesh, - mesh_transform: &Mat4, + transform: &Mat4, ray: Ray3d, - backface_culling: Backfaces, + culling: Backfaces, ) -> Option { if mesh.primitive_topology() != PrimitiveTopology::TriangleList { return None; // ray_mesh_intersection assumes vertices are laid out in a triangle list } // Vertex positions are required - let vertex_positions = mesh.attribute(Mesh::ATTRIBUTE_POSITION)?.as_float3()?; + let positions = mesh.attribute(Mesh::ATTRIBUTE_POSITION)?.as_float3()?; // Normals are optional - let vertex_normals = mesh + let normals = mesh .attribute(Mesh::ATTRIBUTE_NORMAL) .and_then(|normal_values| normal_values.as_float3()); - ray_mesh_intersection( - ray, - mesh_transform, - vertex_positions, - vertex_normals, - mesh.indices(), - backface_culling, - ) + + match mesh.indices() { + Some(Indices::U16(indices)) => { + ray_mesh_intersection(ray, transform, positions, normals, Some(indices), culling) + } + Some(Indices::U32(indices)) => { + ray_mesh_intersection(ray, transform, positions, normals, Some(indices), culling) + } + None => ray_mesh_intersection::(ray, transform, positions, normals, None, culling), + } } /// Checks if a ray intersects a mesh, and returns the nearest intersection if one exists. -pub fn ray_mesh_intersection( +pub fn ray_mesh_intersection + Clone + Copy>( ray: Ray3d, mesh_transform: &Mat4, - vertex_positions: &[[f32; 3]], + positions: &[[f32; 3]], vertex_normals: Option<&[[f32; 3]]>, - indices: Option<&Indices>, + indices: Option<&[I]>, backface_culling: Backfaces, ) -> Option { // The ray cast can hit the same mesh many times, so we need to track which hit is @@ -82,29 +84,19 @@ pub fn ray_mesh_intersection( return None; } - // Iterate over chunks of three indices, representing the corners of a triangle. - let mut indices = indices.iter(); - let mut next_triangle = || { - indices - .next() - .zip(indices.next()) - .zip(indices.next()) - .map(|((a, b), c)| [a, b, c]) - }; - - while let Some(triangle) = next_triangle() { - let triangle_index = Some(triangle[0]); + for triangle in indices.chunks_exact(3) { + let triangle_index = Some(triangle[0].try_into().ok()?); let tri_vertex_positions = [ - Vec3A::from(vertex_positions[triangle[0]]), - Vec3A::from(vertex_positions[triangle[1]]), - Vec3A::from(vertex_positions[triangle[2]]), + Vec3A::from(positions[triangle[0].try_into().ok()?]), + Vec3A::from(positions[triangle[1].try_into().ok()?]), + Vec3A::from(positions[triangle[2].try_into().ok()?]), ]; - let tri_normals = vertex_normals.map(|normals| { - [ - Vec3A::from(normals[triangle[0]]), - Vec3A::from(normals[triangle[1]]), - Vec3A::from(normals[triangle[2]]), - ] + let tri_normals = vertex_normals.and_then(|normals| { + Some([ + Vec3A::from(normals[triangle[0].try_into().ok()?]), + Vec3A::from(normals[triangle[1].try_into().ok()?]), + Vec3A::from(normals[triangle[2].try_into().ok()?]), + ]) }); let Some(hit) = triangle_intersection( @@ -136,7 +128,7 @@ pub fn ray_mesh_intersection( closest_hit_distance = hit.distance; } } else { - for (i, chunk) in vertex_positions.chunks_exact(3).enumerate() { + for (i, chunk) in positions.chunks_exact(3).enumerate() { let &[a, b, c] = chunk else { continue; }; From 57884fdbac64458a3c82e35b47474b7341fd942c Mon Sep 17 00:00:00 2001 From: Aevyrie Date: Sat, 26 Oct 2024 15:41:54 -0700 Subject: [PATCH 6/7] Performance improvements --- .../mesh_picking/ray_cast/intersections.rs | 83 ++++++++++--------- 1 file changed, 44 insertions(+), 39 deletions(-) diff --git a/crates/bevy_picking/src/mesh_picking/ray_cast/intersections.rs b/crates/bevy_picking/src/mesh_picking/ray_cast/intersections.rs index 26f221cc63033..d4ec97e1f3549 100644 --- a/crates/bevy_picking/src/mesh_picking/ray_cast/intersections.rs +++ b/crates/bevy_picking/src/mesh_picking/ray_cast/intersections.rs @@ -16,7 +16,7 @@ pub struct RayMeshHit { /// The distance from the ray origin to the intersection point. pub distance: f32, /// The vertices of the triangle that was hit. - pub triangle: Option<[Vec3A; 3]>, + pub triangle: Option<[Vec3; 3]>, /// The index of the triangle that was hit. pub triangle_index: Option, } @@ -40,6 +40,7 @@ pub(super) fn ray_intersection_over_mesh( } // Vertex positions are required let positions = mesh.attribute(Mesh::ATTRIBUTE_POSITION)?.as_float3()?; + // Normals are optional let normals = mesh .attribute(Mesh::ATTRIBUTE_NORMAL) @@ -85,23 +86,29 @@ pub fn ray_mesh_intersection + Clone + Copy>( } for triangle in indices.chunks_exact(3) { - let triangle_index = Some(triangle[0].try_into().ok()?); - let tri_vertex_positions = [ - Vec3A::from(positions[triangle[0].try_into().ok()?]), - Vec3A::from(positions[triangle[1].try_into().ok()?]), - Vec3A::from(positions[triangle[2].try_into().ok()?]), + let [a, b, c] = [ + triangle[0].try_into().ok()?, + triangle[1].try_into().ok()?, + triangle[2].try_into().ok()?, + ]; + + let triangle_index = Some(a); + let tri_vertex_positions = &[ + Vec3::from(positions[a]), + Vec3::from(positions[b]), + Vec3::from(positions[c]), ]; - let tri_normals = vertex_normals.and_then(|normals| { - Some([ - Vec3A::from(normals[triangle[0].try_into().ok()?]), - Vec3A::from(normals[triangle[1].try_into().ok()?]), - Vec3A::from(normals[triangle[2].try_into().ok()?]), - ]) + let tri_normals = vertex_normals.map(|normals| { + [ + Vec3::from(normals[a]), + Vec3::from(normals[b]), + Vec3::from(normals[c]), + ] }); let Some(hit) = triangle_intersection( tri_vertex_positions, - tri_normals, + tri_normals.as_ref(), closest_hit_distance, &mesh_space_ray, backface_culling, @@ -118,9 +125,9 @@ pub fn ray_mesh_intersection + Clone + Copy>( .length(), triangle: hit.triangle.map(|tri| { [ - mesh_transform.transform_point3a(tri[0]), - mesh_transform.transform_point3a(tri[1]), - mesh_transform.transform_point3a(tri[2]), + mesh_transform.transform_point3(tri[0]), + mesh_transform.transform_point3(tri[1]), + mesh_transform.transform_point3(tri[2]), ] }), triangle_index, @@ -128,23 +135,23 @@ pub fn ray_mesh_intersection + Clone + Copy>( closest_hit_distance = hit.distance; } } else { - for (i, chunk) in positions.chunks_exact(3).enumerate() { - let &[a, b, c] = chunk else { + for (i, triangle) in positions.chunks_exact(3).enumerate() { + let &[a, b, c] = triangle else { continue; }; let triangle_index = Some(i); - let tri_vertex_positions = [Vec3A::from(a), Vec3A::from(b), Vec3A::from(c)]; + let tri_vertex_positions = &[Vec3::from(a), Vec3::from(b), Vec3::from(c)]; let tri_normals = vertex_normals.map(|normals| { [ - Vec3A::from(normals[i]), - Vec3A::from(normals[i + 1]), - Vec3A::from(normals[i + 2]), + Vec3::from(normals[i]), + Vec3::from(normals[i + 1]), + Vec3::from(normals[i + 2]), ] }); let Some(hit) = triangle_intersection( tri_vertex_positions, - tri_normals, + tri_normals.as_ref(), closest_hit_distance, &mesh_space_ray, backface_culling, @@ -161,9 +168,9 @@ pub fn ray_mesh_intersection + Clone + Copy>( .length(), triangle: hit.triangle.map(|tri| { [ - mesh_transform.transform_point3a(tri[0]), - mesh_transform.transform_point3a(tri[1]), - mesh_transform.transform_point3a(tri[2]), + mesh_transform.transform_point3(tri[0]), + mesh_transform.transform_point3(tri[1]), + mesh_transform.transform_point3(tri[2]), ] }), triangle_index, @@ -175,15 +182,14 @@ pub fn ray_mesh_intersection + Clone + Copy>( closest_hit } -#[inline(always)] fn triangle_intersection( - tri_vertices: [Vec3A; 3], - tri_normals: Option<[Vec3A; 3]>, + tri_vertices: &[Vec3; 3], + tri_normals: Option<&[Vec3; 3]>, max_distance: f32, ray: &Ray3d, backface_culling: Backfaces, ) -> Option { - let hit = ray_triangle_intersection(ray, &tri_vertices, backface_culling)?; + let hit = ray_triangle_intersection(ray, tri_vertices, backface_culling)?; if hit.distance < 0.0 || hit.distance > max_distance { return None; @@ -205,25 +211,24 @@ fn triangle_intersection( Some(RayMeshHit { point, - normal: normal.into(), + normal, barycentric_coords: barycentric, distance: hit.distance, - triangle: Some(tri_vertices), + triangle: Some(*tri_vertices), triangle_index: None, }) } /// Takes a ray and triangle and computes the intersection. -#[inline(always)] fn ray_triangle_intersection( ray: &Ray3d, - triangle: &[Vec3A; 3], + triangle: &[Vec3; 3], backface_culling: Backfaces, ) -> Option { // Source: https://www.scratchapixel.com/lessons/3d-basic-rendering/ray-tracing-rendering-a-triangle/moller-trumbore-ray-triangle-intersection - let vector_v0_to_v1: Vec3A = triangle[1] - triangle[0]; - let vector_v0_to_v2: Vec3A = triangle[2] - triangle[0]; - let p_vec: Vec3A = (Vec3A::from(*ray.direction)).cross(vector_v0_to_v2); + let vector_v0_to_v1: Vec3 = triangle[1] - triangle[0]; + let vector_v0_to_v2: Vec3 = triangle[2] - triangle[0]; + let p_vec: Vec3 = ray.direction.cross(vector_v0_to_v2); let determinant: f32 = vector_v0_to_v1.dot(p_vec); match backface_culling { @@ -245,14 +250,14 @@ fn ray_triangle_intersection( let determinant_inverse = 1.0 / determinant; - let t_vec = Vec3A::from(ray.origin) - triangle[0]; + let t_vec = ray.origin - triangle[0]; let u = t_vec.dot(p_vec) * determinant_inverse; if !(0.0..=1.0).contains(&u) { return None; } let q_vec = t_vec.cross(vector_v0_to_v1); - let v = Vec3A::from(*ray.direction).dot(q_vec) * determinant_inverse; + let v = (*ray.direction).dot(q_vec) * determinant_inverse; if v < 0.0 || u + v > 1.0 { return None; } From 8f5b679934dd0df057f94ba462c313d00d663c76 Mon Sep 17 00:00:00 2001 From: Aevyrie Date: Sat, 26 Oct 2024 15:50:51 -0700 Subject: [PATCH 7/7] Warnings in benches --- benches/benches/bevy_picking/ray_mesh_intersection.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/benches/benches/bevy_picking/ray_mesh_intersection.rs b/benches/benches/bevy_picking/ray_mesh_intersection.rs index 2ce0252c8ca49..f451b790612c3 100644 --- a/benches/benches/bevy_picking/ray_mesh_intersection.rs +++ b/benches/benches/bevy_picking/ray_mesh_intersection.rs @@ -1,6 +1,5 @@ use bevy_math::{Dir3, Mat4, Ray3d, Vec3}; -use bevy_picking::{mesh_picking::ray_cast, prelude::*}; -use bevy_render::mesh::Indices; +use bevy_picking::mesh_picking::ray_cast; use criterion::{black_box, criterion_group, criterion_main, Criterion}; fn ptoxznorm(p: u32, size: u32) -> (f32, f32) {