1
1
use bevy_math:: { bounding:: Aabb3d , Dir3 , Mat4 , Ray3d , Vec3 , Vec3A } ;
2
2
use 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 } ;
5
4
6
5
use super :: Backfaces ;
7
6
@@ -17,7 +16,7 @@ pub struct RayMeshHit {
17
16
/// The distance from the ray origin to the intersection point.
18
17
pub distance : f32 ,
19
18
/// The vertices of the triangle that was hit.
20
- pub triangle : Option < [ Vec3A ; 3 ] > ,
19
+ pub triangle : Option < [ Vec3 ; 3 ] > ,
21
20
/// The index of the triangle that was hit.
22
21
pub triangle_index : Option < usize > ,
23
22
}
@@ -32,84 +31,41 @@ pub struct RayTriangleHit {
32
31
/// Casts a ray on a mesh, and returns the intersection.
33
32
pub ( super ) fn ray_intersection_over_mesh (
34
33
mesh : & Mesh ,
35
- mesh_transform : & Mat4 ,
34
+ transform : & Mat4 ,
36
35
ray : Ray3d ,
37
- backface_culling : Backfaces ,
36
+ culling : Backfaces ,
38
37
) -> Option < RayMeshHit > {
39
38
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
44
40
}
41
+ // Vertex positions are required
42
+ let positions = mesh. attribute ( Mesh :: ATTRIBUTE_POSITION ) ?. as_float3 ( ) ?;
45
43
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)
51
52
}
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)
88
55
}
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) ,
98
57
}
99
58
}
100
59
101
60
/// 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 > (
103
62
ray : Ray3d ,
104
63
mesh_transform : & Mat4 ,
105
- vertex_positions : & [ [ f32 ; 3 ] ] ,
64
+ positions : & [ [ f32 ; 3 ] ] ,
106
65
vertex_normals : Option < & [ [ f32 ; 3 ] ] > ,
107
- indices : Option < & [ Index ] > ,
66
+ indices : Option < & [ I ] > ,
108
67
backface_culling : Backfaces ,
109
- ) -> Option < RayMeshHit >
110
- where
111
- usize : TryFrom < Index > ,
112
- {
68
+ ) -> Option < RayMeshHit > {
113
69
// The ray cast can hit the same mesh many times, so we need to track which hit is
114
70
// closest to the camera, and record that.
115
71
let mut closest_hit_distance = f32:: MAX ;
@@ -123,38 +79,36 @@ where
123
79
) ;
124
80
125
81
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.
127
84
if indices. len ( ) % 3 != 0 {
128
- warn ! ( "Index list not a multiple of 3" ) ;
129
85
return None ;
130
86
}
131
87
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 ( ) ?,
140
93
] ;
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] ) ,
146
100
] ;
147
101
let tri_normals = vertex_normals. map ( |normals| {
148
102
[
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 ] ) ,
152
106
]
153
107
} ) ;
154
108
155
109
let Some ( hit) = triangle_intersection (
156
110
tri_vertex_positions,
157
- tri_normals,
111
+ tri_normals. as_ref ( ) ,
158
112
closest_hit_distance,
159
113
& mesh_space_ray,
160
114
backface_culling,
@@ -171,33 +125,33 @@ where
171
125
. length ( ) ,
172
126
triangle : hit. triangle . map ( |tri| {
173
127
[
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 ] ) ,
177
131
]
178
132
} ) ,
179
133
triangle_index,
180
134
} ) ;
181
135
closest_hit_distance = hit. distance ;
182
136
}
183
137
} 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 {
186
140
continue ;
187
141
} ;
188
142
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) ] ;
190
144
let tri_normals = vertex_normals. map ( |normals| {
191
145
[
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 ] ) ,
195
149
]
196
150
} ) ;
197
151
198
152
let Some ( hit) = triangle_intersection (
199
153
tri_vertex_positions,
200
- tri_normals,
154
+ tri_normals. as_ref ( ) ,
201
155
closest_hit_distance,
202
156
& mesh_space_ray,
203
157
backface_culling,
@@ -214,9 +168,9 @@ where
214
168
. length ( ) ,
215
169
triangle : hit. triangle . map ( |tri| {
216
170
[
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 ] ) ,
220
174
]
221
175
} ) ,
222
176
triangle_index,
@@ -228,15 +182,14 @@ where
228
182
closest_hit
229
183
}
230
184
231
- #[ inline( always) ]
232
185
fn triangle_intersection (
233
- tri_vertices : [ Vec3A ; 3 ] ,
234
- tri_normals : Option < [ Vec3A ; 3 ] > ,
186
+ tri_vertices : & [ Vec3 ; 3 ] ,
187
+ tri_normals : Option < & [ Vec3 ; 3 ] > ,
235
188
max_distance : f32 ,
236
189
ray : & Ray3d ,
237
190
backface_culling : Backfaces ,
238
191
) -> Option < RayMeshHit > {
239
- let hit = ray_triangle_intersection ( ray, & tri_vertices, backface_culling) ?;
192
+ let hit = ray_triangle_intersection ( ray, tri_vertices, backface_culling) ?;
240
193
241
194
if hit. distance < 0.0 || hit. distance > max_distance {
242
195
return None ;
@@ -258,25 +211,24 @@ fn triangle_intersection(
258
211
259
212
Some ( RayMeshHit {
260
213
point,
261
- normal : normal . into ( ) ,
214
+ normal,
262
215
barycentric_coords : barycentric,
263
216
distance : hit. distance ,
264
- triangle : Some ( tri_vertices) ,
217
+ triangle : Some ( * tri_vertices) ,
265
218
triangle_index : None ,
266
219
} )
267
220
}
268
221
269
222
/// Takes a ray and triangle and computes the intersection.
270
- #[ inline( always) ]
271
223
fn ray_triangle_intersection (
272
224
ray : & Ray3d ,
273
- triangle : & [ Vec3A ; 3 ] ,
225
+ triangle : & [ Vec3 ; 3 ] ,
274
226
backface_culling : Backfaces ,
275
227
) -> Option < RayTriangleHit > {
276
228
// 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) ;
280
232
let determinant: f32 = vector_v0_to_v1. dot ( p_vec) ;
281
233
282
234
match backface_culling {
@@ -298,14 +250,14 @@ fn ray_triangle_intersection(
298
250
299
251
let determinant_inverse = 1.0 / determinant;
300
252
301
- let t_vec = Vec3A :: from ( ray. origin ) - triangle[ 0 ] ;
253
+ let t_vec = ray. origin - triangle[ 0 ] ;
302
254
let u = t_vec. dot ( p_vec) * determinant_inverse;
303
255
if !( 0.0 ..=1.0 ) . contains ( & u) {
304
256
return None ;
305
257
}
306
258
307
259
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;
309
261
if v < 0.0 || u + v > 1.0 {
310
262
return None ;
311
263
}
0 commit comments