1use rg3d_core::{
14 math::vec3::Vec3,
15 math,
16};
17use crate::convex_shape::ConvexShape;
18
19pub const GJK_MAX_ITERATIONS: usize = 64;
20pub const EPA_TOLERANCE: f32 = 0.0001;
21pub const EPA_MAX_ITERATIONS: usize = 64;
22pub const EPA_MAX_LOOSE_EDGES: usize = 32;
23pub const EPA_MAX_FACES: usize = 64;
24
25#[derive(Copy, Clone)]
27pub struct MinkowskiVertex {
28 shape_a_world_space: Vec3,
31
32 minkowski_dif: Vec3,
36}
37
38impl Default for MinkowskiVertex {
39 fn default() -> Self {
40 Self {
41 shape_a_world_space: Default::default(),
42 minkowski_dif: Default::default(),
43 }
44 }
45}
46
47#[derive(Copy, Clone)]
48struct PolytopeTriangle {
49 vertices: [MinkowskiVertex; 3],
50 normal: Vec3,
51}
52
53impl Default for PolytopeTriangle {
54 fn default() -> Self {
55 Self {
56 vertices: Default::default(),
57 normal: Default::default(),
58 }
59 }
60}
61
62#[derive(Copy, Clone)]
63struct PolytopeEdge {
64 begin: MinkowskiVertex,
65 end: MinkowskiVertex,
66}
67
68impl Default for PolytopeEdge {
69 fn default() -> Self {
70 Self {
71 begin: Default::default(),
72 end: Default::default(),
73 }
74 }
75}
76
77impl PolytopeEdge {
78 fn eq_ccw(&self, other: &PolytopeEdge) -> bool {
81 self.begin.minkowski_dif == other.end.minkowski_dif &&
82 self.end.minkowski_dif == other.begin.minkowski_dif
83 }
84}
85
86pub struct Simplex {
87 a: MinkowskiVertex,
90 b: MinkowskiVertex,
91 c: MinkowskiVertex,
92 d: MinkowskiVertex,
93 rank: usize,
99}
100
101impl Default for Simplex {
102 fn default() -> Self {
103 Self {
104 a: Default::default(),
105 b: Default::default(),
106 c: Default::default(),
107 d: Default::default(),
108 rank: 0,
109 }
110 }
111}
112
113impl Simplex {
114 fn update_triangle(&mut self) -> Vec3 {
115 let ca = self.c.minkowski_dif - self.a.minkowski_dif;
116 let ba = self.b.minkowski_dif - self.a.minkowski_dif;
117
118 let ao = -self.a.minkowski_dif;
120
121 self.rank = 2;
122
123 let triangle_normal = ba.cross(&ca);
124
125 if ba.cross(&triangle_normal).is_same_direction_as(&ao) {
126 self.c = self.a;
128 return ba.cross(&ao).cross(&ba);
129 }
130
131 if triangle_normal.cross(&ca).is_same_direction_as(&ao) {
132 self.b = self.a;
134 return ca.cross(&ao).cross(&ca);
135 }
136
137 self.rank = 3;
138
139 if triangle_normal.is_same_direction_as(&ao) {
140 self.d = self.c;
142 self.c = self.b;
143 self.b = self.a;
144 return triangle_normal;
145 }
146
147 self.d = self.b;
149 self.b = self.a;
150
151 -triangle_normal
152 }
153
154 fn update_tetrahedron(&mut self) -> Result<(), Vec3> {
155 let ao = -self.a.minkowski_dif;
159
160 self.rank = 3;
165
166 let ba = self.b.minkowski_dif - self.a.minkowski_dif;
167 let ca = self.c.minkowski_dif - self.a.minkowski_dif;
168
169 let abc_normal = ba.cross(&ca);
170 if abc_normal.is_same_direction_as(&ao) {
171 self.d = self.c;
173 self.c = self.b;
174 self.b = self.a;
175 return Err(abc_normal);
176 }
177
178 let da = self.d.minkowski_dif - self.a.minkowski_dif;
179 let acd_normal = ca.cross(&da);
180 if acd_normal.is_same_direction_as(&ao) {
181 self.b = self.a;
183 return Err(acd_normal);
184 }
185
186 let adb_normal = da.cross(&ba);
187 if adb_normal.is_same_direction_as(&ao) {
188 self.c = self.d;
190 self.d = self.b;
191 self.b = self.a;
192 return Err(adb_normal);
193 }
194
195 Ok(())
197 }
198}
199
200fn de_gjk_support(shape1: &ConvexShape, shape1_position: Vec3, shape2: &ConvexShape, shape2_position: Vec3, dir: &Vec3) -> MinkowskiVertex
201{
202 let shape_a_world_space = shape1.get_farthest_point(shape1_position, *dir);
203 let b = shape2.get_farthest_point(shape2_position, -*dir);
204
205 MinkowskiVertex {
206 shape_a_world_space,
207 minkowski_dif: shape_a_world_space - b,
208 }
209}
210
211pub fn gjk_is_intersects(shape1: &ConvexShape, shape1_position: Vec3, shape2: &ConvexShape, shape2_position: Vec3) -> Option<Simplex> {
212 let mut search_dir = shape1_position - shape2_position;
214
215 if search_dir.sqr_len() == 0.0 {
216 search_dir.x = 1.0;
217 }
218
219 let mut simplex = Simplex::default();
221 simplex.c = de_gjk_support(shape1, shape1_position, shape2, shape2_position, &search_dir);
222 search_dir = -simplex.c.minkowski_dif; simplex.b = de_gjk_support(shape1, shape1_position, shape2, shape2_position, &search_dir);
226
227 if !simplex.b.minkowski_dif.is_same_direction_as(&search_dir) {
228 return None;
229 }
230
231 let cb = simplex.c.minkowski_dif - simplex.b.minkowski_dif;
232
233 search_dir = cb.cross(&(-simplex.b.minkowski_dif)).cross(&cb);
235
236 if search_dir.sqr_len() == 0.0 {
238 search_dir = cb.cross(&Vec3::new(1.0, 0.0, 0.0));
240 if search_dir.sqr_len() == 0.0 {
241 search_dir = cb.cross(&Vec3::new(0.0, 0.0, -1.0));
243 }
244 }
245
246 simplex.rank = 2;
247 for _ in 0..GJK_MAX_ITERATIONS {
248 simplex.a = de_gjk_support(shape1, shape1_position, shape2, shape2_position, &search_dir);
249
250 if !simplex.a.minkowski_dif.is_same_direction_as(&search_dir) {
251 return None;
252 }
253
254 simplex.rank += 1;
255 if simplex.rank == 3 {
256 search_dir = simplex.update_triangle();
257 } else {
258 match simplex.update_tetrahedron() {
259 Ok(_) => return Some(simplex),
260 Err(dir) => search_dir = dir,
261 }
262 }
263 }
264
265 None
267}
268
269fn epa_compute_contact_point(closest_triangle: PolytopeTriangle) -> Vec3 {
270 let proj = closest_triangle.normal.scale(
272 closest_triangle.vertices[0].minkowski_dif.dot(&closest_triangle.normal));
273
274 let (u, v, w) = math::get_barycentric_coords(
276 &proj, &closest_triangle.vertices[0].minkowski_dif,
277 &closest_triangle.vertices[1].minkowski_dif,
278 &closest_triangle.vertices[2].minkowski_dif);
279
280 closest_triangle.vertices[0].shape_a_world_space.scale(u) +
283 closest_triangle.vertices[1].shape_a_world_space.scale(v) +
284 closest_triangle.vertices[2].shape_a_world_space.scale(w)
285}
286
287pub struct PenetrationInfo {
288 pub penetration_vector: Vec3,
289 pub contact_point: Vec3,
290}
291
292pub fn epa_get_penetration_info(simplex: Simplex, shape1: &ConvexShape, shape1_position: Vec3,
293 shape2: &ConvexShape, shape2_position: Vec3) -> Option<PenetrationInfo> {
294 let mut triangles = [PolytopeTriangle::default(); EPA_MAX_FACES];
295
296 let ba = simplex.b.minkowski_dif - simplex.a.minkowski_dif;
300 let ca = simplex.c.minkowski_dif - simplex.a.minkowski_dif;
301
302 let abc_normal = ba.cross(&ca);
303 if let Some(abc_normal) = abc_normal.normalized() {
304 triangles[0] = PolytopeTriangle {
305 vertices: [simplex.a, simplex.b, simplex.c],
306 normal: abc_normal,
307 };
308 } else {
309 return None;
310 }
311
312 let da = simplex.d.minkowski_dif - simplex.a.minkowski_dif;
314
315 let acd_normal = ca.cross(&da);
316 if let Some(acd_normal) = acd_normal.normalized() {
317 triangles[1] = PolytopeTriangle {
318 vertices: [simplex.a, simplex.c, simplex.d],
319 normal: acd_normal,
320 };
321 } else {
322 return None;
323 }
324
325 let adb_normal = da.cross(&ba);
327 if let Some(adb_normal) = adb_normal.normalized() {
328 triangles[2] = PolytopeTriangle {
329 vertices: [simplex.a, simplex.d, simplex.b],
330 normal: adb_normal,
331 };
332 } else {
333 return None;
334 }
335
336 let db = simplex.d.minkowski_dif - simplex.b.minkowski_dif;
338 let cb = simplex.c.minkowski_dif - simplex.b.minkowski_dif;
339
340 let bdc_normal = db.cross(&cb);
341 if let Some(bdc_normal) = bdc_normal.normalized() {
342 triangles[3] = PolytopeTriangle {
343 vertices: [simplex.b, simplex.d, simplex.c],
344 normal: bdc_normal,
345 };
346 } else {
347 return None;
348 }
349
350 let mut triangle_count = 4;
351 let mut closest_triangle_index = 0;
352
353 for _ in 0..EPA_MAX_ITERATIONS {
354 let mut min_dist = triangles[0].vertices[0].minkowski_dif.dot(&triangles[0].normal);
356 closest_triangle_index = 0;
357 for (i, triangle) in triangles.iter().enumerate().take(triangle_count).skip(1) {
358 let dist = triangle.vertices[0].minkowski_dif.dot(&triangle.normal);
359 if dist < min_dist {
360 min_dist = dist;
361 closest_triangle_index = i;
362 }
363 }
364
365 let closest_triangle = triangles[closest_triangle_index];
367 let search_dir = closest_triangle.normal;
368 let new_point = de_gjk_support(shape1, shape1_position, shape2, shape2_position, &search_dir);
369
370 let distance_to_origin = new_point.minkowski_dif.dot(&search_dir);
371 if distance_to_origin - min_dist < EPA_TOLERANCE {
372 return Some(PenetrationInfo {
373 penetration_vector: closest_triangle.normal.scale(distance_to_origin),
374 contact_point: epa_compute_contact_point(closest_triangle),
375 });
376 }
377
378 let mut loose_edge_count = 0;
381 let mut loose_edges = [PolytopeEdge::default(); EPA_MAX_LOOSE_EDGES];
382
383 let mut i = 0;
385 while i < triangle_count {
386 let triangle = triangles[i];
387
388 let to_new_point = new_point.minkowski_dif - triangle.vertices[0].minkowski_dif;
391
392 if triangle.normal.dot(&to_new_point) > 0.0 {
393 for j in 0..3 {
394 let current_edge = PolytopeEdge {
395 begin: triangle.vertices[j],
396 end: triangle.vertices[(j + 1) % 3],
397 };
398
399 let mut already_in_list = false;
400 let last_loose_edge = loose_edge_count;
402 for k in 0..last_loose_edge {
403 if loose_edges[k].eq_ccw(¤t_edge) {
404 loose_edge_count -= 1;
463 loose_edges.swap(k, loose_edge_count);
464
465 already_in_list = true;
466 break;
467 }
468 }
469
470 if !already_in_list {
471 if loose_edge_count >= EPA_MAX_LOOSE_EDGES {
473 break;
474 }
475 loose_edges[loose_edge_count] = current_edge;
476 loose_edge_count += 1;
477 }
478 }
479
480 triangle_count -= 1;
484 triangles.swap(i, triangle_count);
485 } else {
486 i += 1;
487 }
488 }
489
490 for loose_edge in loose_edges[0..loose_edge_count].iter() {
492 if triangle_count >= EPA_MAX_FACES {
493 break;
494 }
495 let new_triangle = triangles.get_mut(triangle_count).unwrap();
496 new_triangle.vertices = [loose_edge.begin, loose_edge.end, new_point];
497
498 let edge_vector = loose_edge.begin.minkowski_dif - loose_edge.end.minkowski_dif;
499 let begin_to_point = loose_edge.begin.minkowski_dif - new_point.minkowski_dif;
500
501 new_triangle.normal = edge_vector.cross(&begin_to_point).normalized().unwrap_or(Vec3::UP);
502
503 let bias = 2.0 * std::f32::EPSILON;
505 if new_triangle.vertices[0].minkowski_dif.dot(&new_triangle.normal) + bias < 0.0 {
506 new_triangle.vertices.swap(0, 1);
508 new_triangle.normal = -new_triangle.normal;
509 }
510 triangle_count += 1;
511 }
512 }
513
514 let closest_triangle = triangles[closest_triangle_index];
517 Some(PenetrationInfo {
518 penetration_vector: closest_triangle.normal.scale(closest_triangle.vertices[0].minkowski_dif.dot(&closest_triangle.normal)),
519 contact_point: epa_compute_contact_point(closest_triangle),
520 })
521}