11use bevy_math:: { bounding:: Aabb3d , Dir3 , Mat4 , Ray3d , Vec3 , Vec3A } ;
22use bevy_reflect:: Reflect ;
3- use bevy_render:: mesh:: { Indices , Mesh , PrimitiveTopology , VertexAttributeValues } ;
4- use bevy_utils:: tracing:: { error, warn} ;
3+ use bevy_render:: mesh:: { Indices , Mesh , PrimitiveTopology } ;
54
65use super :: Backfaces ;
76
@@ -17,7 +16,7 @@ pub struct RayMeshHit {
1716 /// The distance from the ray origin to the intersection point.
1817 pub distance : f32 ,
1918 /// The vertices of the triangle that was hit.
20- pub triangle : Option < [ Vec3A ; 3 ] > ,
19+ pub triangle : Option < [ Vec3 ; 3 ] > ,
2120 /// The index of the triangle that was hit.
2221 pub triangle_index : Option < usize > ,
2322}
@@ -32,84 +31,41 @@ pub struct RayTriangleHit {
3231/// Casts a ray on a mesh, and returns the intersection.
3332pub ( super ) fn ray_intersection_over_mesh (
3433 mesh : & Mesh ,
35- mesh_transform : & Mat4 ,
34+ transform : & Mat4 ,
3635 ray : Ray3d ,
37- backface_culling : Backfaces ,
36+ culling : Backfaces ,
3837) -> Option < RayMeshHit > {
3938 if mesh. primitive_topology ( ) != PrimitiveTopology :: TriangleList {
40- error ! (
41- "Invalid intersection check: `TriangleList` is the only supported `PrimitiveTopology`"
42- ) ;
43- return None ;
39+ return None ; // ray_mesh_intersection assumes vertices are laid out in a triangle list
4440 }
41+ // Vertex positions are required
42+ let positions = mesh. attribute ( Mesh :: ATTRIBUTE_POSITION ) ?. as_float3 ( ) ?;
4543
46- // Get the vertex positions and normals from the mesh.
47- let vertex_positions: & Vec < [ f32 ; 3 ] > = match mesh. attribute ( Mesh :: ATTRIBUTE_POSITION ) {
48- None => {
49- error ! ( "Mesh does not contain vertex positions" ) ;
50- return None ;
44+ // Normals are optional
45+ let normals = mesh
46+ . attribute ( Mesh :: ATTRIBUTE_NORMAL )
47+ . and_then ( |normal_values| normal_values. as_float3 ( ) ) ;
48+
49+ match mesh. indices ( ) {
50+ Some ( Indices :: U16 ( indices) ) => {
51+ ray_mesh_intersection ( ray, transform, positions, normals, Some ( indices) , culling)
5152 }
52- Some ( vertex_values) => match & vertex_values {
53- VertexAttributeValues :: Float32x3 ( positions) => positions,
54- _ => {
55- error ! ( "Unexpected types in {:?}" , Mesh :: ATTRIBUTE_POSITION ) ;
56- return None ;
57- }
58- } ,
59- } ;
60- let vertex_normals: Option < & [ [ f32 ; 3 ] ] > =
61- if let Some ( normal_values) = mesh. attribute ( Mesh :: ATTRIBUTE_NORMAL ) {
62- match & normal_values {
63- VertexAttributeValues :: Float32x3 ( normals) => Some ( normals) ,
64- _ => None ,
65- }
66- } else {
67- None
68- } ;
69-
70- if let Some ( indices) = & mesh. indices ( ) {
71- match indices {
72- Indices :: U16 ( vertex_indices) => ray_mesh_intersection (
73- ray,
74- mesh_transform,
75- vertex_positions,
76- vertex_normals,
77- Some ( vertex_indices) ,
78- backface_culling,
79- ) ,
80- Indices :: U32 ( vertex_indices) => ray_mesh_intersection (
81- ray,
82- mesh_transform,
83- vertex_positions,
84- vertex_normals,
85- Some ( vertex_indices) ,
86- backface_culling,
87- ) ,
53+ Some ( Indices :: U32 ( indices) ) => {
54+ ray_mesh_intersection ( ray, transform, positions, normals, Some ( indices) , culling)
8855 }
89- } else {
90- ray_mesh_intersection (
91- ray,
92- mesh_transform,
93- vertex_positions,
94- vertex_normals,
95- None :: < & [ usize ] > ,
96- backface_culling,
97- )
56+ None => ray_mesh_intersection :: < usize > ( ray, transform, positions, normals, None , culling) ,
9857 }
9958}
10059
10160/// Checks if a ray intersects a mesh, and returns the nearest intersection if one exists.
102- pub fn ray_mesh_intersection < Index : Clone + Copy > (
61+ pub fn ray_mesh_intersection < I : TryInto < usize > + Clone + Copy > (
10362 ray : Ray3d ,
10463 mesh_transform : & Mat4 ,
105- vertex_positions : & [ [ f32 ; 3 ] ] ,
64+ positions : & [ [ f32 ; 3 ] ] ,
10665 vertex_normals : Option < & [ [ f32 ; 3 ] ] > ,
107- indices : Option < & [ Index ] > ,
66+ indices : Option < & [ I ] > ,
10867 backface_culling : Backfaces ,
109- ) -> Option < RayMeshHit >
110- where
111- usize : TryFrom < Index > ,
112- {
68+ ) -> Option < RayMeshHit > {
11369 // The ray cast can hit the same mesh many times, so we need to track which hit is
11470 // closest to the camera, and record that.
11571 let mut closest_hit_distance = f32:: MAX ;
@@ -123,38 +79,36 @@ where
12379 ) ;
12480
12581 if let Some ( indices) = indices {
126- // Make sure this chunk has 3 vertices to avoid a panic.
82+ // The index list must be a multiple of three. If not, the mesh is malformed and the raycast
83+ // result might be nonsensical.
12784 if indices. len ( ) % 3 != 0 {
128- warn ! ( "Index list not a multiple of 3" ) ;
12985 return None ;
13086 }
13187
132- // Now that we're in the vector of vertex indices, we want to look at the vertex
133- // positions for each triangle, so we'll take indices in chunks of three, where each
134- // chunk of three indices are references to the three vertices of a triangle.
135- for index_chunk in indices. chunks_exact ( 3 ) {
136- let [ index1, index2, index3] = [
137- usize:: try_from ( index_chunk[ 0 ] ) . ok ( ) ?,
138- usize:: try_from ( index_chunk[ 1 ] ) . ok ( ) ?,
139- usize:: try_from ( index_chunk[ 2 ] ) . ok ( ) ?,
88+ for triangle in indices. chunks_exact ( 3 ) {
89+ let [ a, b, c] = [
90+ triangle[ 0 ] . try_into ( ) . ok ( ) ?,
91+ triangle[ 1 ] . try_into ( ) . ok ( ) ?,
92+ triangle[ 2 ] . try_into ( ) . ok ( ) ?,
14093 ] ;
141- let triangle_index = Some ( index1) ;
142- let tri_vertex_positions = [
143- Vec3A :: from ( vertex_positions[ index1] ) ,
144- Vec3A :: from ( vertex_positions[ index2] ) ,
145- Vec3A :: from ( vertex_positions[ index3] ) ,
94+
95+ let triangle_index = Some ( a) ;
96+ let tri_vertex_positions = & [
97+ Vec3 :: from ( positions[ a] ) ,
98+ Vec3 :: from ( positions[ b] ) ,
99+ Vec3 :: from ( positions[ c] ) ,
146100 ] ;
147101 let tri_normals = vertex_normals. map ( |normals| {
148102 [
149- Vec3A :: from ( normals[ index1 ] ) ,
150- Vec3A :: from ( normals[ index2 ] ) ,
151- Vec3A :: from ( normals[ index3 ] ) ,
103+ Vec3 :: from ( normals[ a ] ) ,
104+ Vec3 :: from ( normals[ b ] ) ,
105+ Vec3 :: from ( normals[ c ] ) ,
152106 ]
153107 } ) ;
154108
155109 let Some ( hit) = triangle_intersection (
156110 tri_vertex_positions,
157- tri_normals,
111+ tri_normals. as_ref ( ) ,
158112 closest_hit_distance,
159113 & mesh_space_ray,
160114 backface_culling,
@@ -171,33 +125,33 @@ where
171125 . length ( ) ,
172126 triangle : hit. triangle . map ( |tri| {
173127 [
174- mesh_transform. transform_point3a ( tri[ 0 ] ) ,
175- mesh_transform. transform_point3a ( tri[ 1 ] ) ,
176- mesh_transform. transform_point3a ( tri[ 2 ] ) ,
128+ mesh_transform. transform_point3 ( tri[ 0 ] ) ,
129+ mesh_transform. transform_point3 ( tri[ 1 ] ) ,
130+ mesh_transform. transform_point3 ( tri[ 2 ] ) ,
177131 ]
178132 } ) ,
179133 triangle_index,
180134 } ) ;
181135 closest_hit_distance = hit. distance ;
182136 }
183137 } else {
184- for ( i, chunk ) in vertex_positions . chunks_exact ( 3 ) . enumerate ( ) {
185- let & [ a, b, c] = chunk else {
138+ for ( i, triangle ) in positions . chunks_exact ( 3 ) . enumerate ( ) {
139+ let & [ a, b, c] = triangle else {
186140 continue ;
187141 } ;
188142 let triangle_index = Some ( i) ;
189- let tri_vertex_positions = [ Vec3A :: from ( a) , Vec3A :: from ( b) , Vec3A :: from ( c) ] ;
143+ let tri_vertex_positions = & [ Vec3 :: from ( a) , Vec3 :: from ( b) , Vec3 :: from ( c) ] ;
190144 let tri_normals = vertex_normals. map ( |normals| {
191145 [
192- Vec3A :: from ( normals[ i] ) ,
193- Vec3A :: from ( normals[ i + 1 ] ) ,
194- Vec3A :: from ( normals[ i + 2 ] ) ,
146+ Vec3 :: from ( normals[ i] ) ,
147+ Vec3 :: from ( normals[ i + 1 ] ) ,
148+ Vec3 :: from ( normals[ i + 2 ] ) ,
195149 ]
196150 } ) ;
197151
198152 let Some ( hit) = triangle_intersection (
199153 tri_vertex_positions,
200- tri_normals,
154+ tri_normals. as_ref ( ) ,
201155 closest_hit_distance,
202156 & mesh_space_ray,
203157 backface_culling,
@@ -214,9 +168,9 @@ where
214168 . length ( ) ,
215169 triangle : hit. triangle . map ( |tri| {
216170 [
217- mesh_transform. transform_point3a ( tri[ 0 ] ) ,
218- mesh_transform. transform_point3a ( tri[ 1 ] ) ,
219- mesh_transform. transform_point3a ( tri[ 2 ] ) ,
171+ mesh_transform. transform_point3 ( tri[ 0 ] ) ,
172+ mesh_transform. transform_point3 ( tri[ 1 ] ) ,
173+ mesh_transform. transform_point3 ( tri[ 2 ] ) ,
220174 ]
221175 } ) ,
222176 triangle_index,
@@ -228,15 +182,14 @@ where
228182 closest_hit
229183}
230184
231- #[ inline( always) ]
232185fn triangle_intersection (
233- tri_vertices : [ Vec3A ; 3 ] ,
234- tri_normals : Option < [ Vec3A ; 3 ] > ,
186+ tri_vertices : & [ Vec3 ; 3 ] ,
187+ tri_normals : Option < & [ Vec3 ; 3 ] > ,
235188 max_distance : f32 ,
236189 ray : & Ray3d ,
237190 backface_culling : Backfaces ,
238191) -> Option < RayMeshHit > {
239- let hit = ray_triangle_intersection ( ray, & tri_vertices, backface_culling) ?;
192+ let hit = ray_triangle_intersection ( ray, tri_vertices, backface_culling) ?;
240193
241194 if hit. distance < 0.0 || hit. distance > max_distance {
242195 return None ;
@@ -258,25 +211,24 @@ fn triangle_intersection(
258211
259212 Some ( RayMeshHit {
260213 point,
261- normal : normal . into ( ) ,
214+ normal,
262215 barycentric_coords : barycentric,
263216 distance : hit. distance ,
264- triangle : Some ( tri_vertices) ,
217+ triangle : Some ( * tri_vertices) ,
265218 triangle_index : None ,
266219 } )
267220}
268221
269222/// Takes a ray and triangle and computes the intersection.
270- #[ inline( always) ]
271223fn ray_triangle_intersection (
272224 ray : & Ray3d ,
273- triangle : & [ Vec3A ; 3 ] ,
225+ triangle : & [ Vec3 ; 3 ] ,
274226 backface_culling : Backfaces ,
275227) -> Option < RayTriangleHit > {
276228 // Source: https://www.scratchapixel.com/lessons/3d-basic-rendering/ray-tracing-rendering-a-triangle/moller-trumbore-ray-triangle-intersection
277- let vector_v0_to_v1: Vec3A = triangle[ 1 ] - triangle[ 0 ] ;
278- let vector_v0_to_v2: Vec3A = triangle[ 2 ] - triangle[ 0 ] ;
279- let p_vec: Vec3A = ( Vec3A :: from ( * ray. direction ) ) . cross ( vector_v0_to_v2) ;
229+ let vector_v0_to_v1: Vec3 = triangle[ 1 ] - triangle[ 0 ] ;
230+ let vector_v0_to_v2: Vec3 = triangle[ 2 ] - triangle[ 0 ] ;
231+ let p_vec: Vec3 = ray. direction . cross ( vector_v0_to_v2) ;
280232 let determinant: f32 = vector_v0_to_v1. dot ( p_vec) ;
281233
282234 match backface_culling {
@@ -298,14 +250,14 @@ fn ray_triangle_intersection(
298250
299251 let determinant_inverse = 1.0 / determinant;
300252
301- let t_vec = Vec3A :: from ( ray. origin ) - triangle[ 0 ] ;
253+ let t_vec = ray. origin - triangle[ 0 ] ;
302254 let u = t_vec. dot ( p_vec) * determinant_inverse;
303255 if !( 0.0 ..=1.0 ) . contains ( & u) {
304256 return None ;
305257 }
306258
307259 let q_vec = t_vec. cross ( vector_v0_to_v1) ;
308- let v = Vec3A :: from ( * ray. direction ) . dot ( q_vec) * determinant_inverse;
260+ let v = ( * ray. direction ) . dot ( q_vec) * determinant_inverse;
309261 if v < 0.0 || u + v > 1.0 {
310262 return None ;
311263 }
0 commit comments