Bullet Collision Detection & Physics Library
gim_tri_collision.cpp
Go to the documentation of this file.
1
5/*
6-----------------------------------------------------------------------------
7This source file is part of GIMPACT Library.
8
9For the latest info, see http://gimpact.sourceforge.net/
10
11Copyright (c) 2006 Francisco Leon Najera. C.C. 80087371.
12email: projectileman@yahoo.com
13
14 This library is free software; you can redistribute it and/or
15 modify it under the terms of EITHER:
16 (1) The GNU Lesser General Public License as published by the Free
17 Software Foundation; either version 2.1 of the License, or (at
18 your option) any later version. The text of the GNU Lesser
19 General Public License is included with this library in the
20 file GIMPACT-LICENSE-LGPL.TXT.
21 (2) The BSD-style license that is included with this library in
22 the file GIMPACT-LICENSE-BSD.TXT.
23 (3) The zlib/libpng license that is included with this library in
24 the file GIMPACT-LICENSE-ZLIB.TXT.
25
26 This library is distributed in the hope that it will be useful,
27 but WITHOUT ANY WARRANTY; without even the implied warranty of
28 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files
29 GIMPACT-LICENSE-LGPL.TXT, GIMPACT-LICENSE-ZLIB.TXT and GIMPACT-LICENSE-BSD.TXT for more details.
30
31-----------------------------------------------------------------------------
32*/
33
34#include "gim_tri_collision.h"
35
36#define TRI_LOCAL_EPSILON 0.000001f
37#define MIN_EDGE_EDGE_DIS 0.00001f
38
40{
41public:
60
63 const GREAL &D0,
64 const GREAL &D1,
65 const GREAL &D2,
66 const GREAL &D0D1,
67 const GREAL &D0D2,
68 GREAL &scale_edge0,
69 GREAL &scale_edge1,
70 GUINT &edge_index0,
71 GUINT &edge_index1)
72 {
73 if (D0D1 > 0.0f)
74 {
75 /* here we know that D0D2<=0.0 */
76 /* that is D0, D1 are on the same side, D2 on the other or on the plane */
77 scale_edge0 = -D2 / (D0 - D2);
78 scale_edge1 = -D1 / (D2 - D1);
79 edge_index0 = 2;
80 edge_index1 = 1;
81 }
82 else if (D0D2 > 0.0f)
83 {
84 /* here we know that d0d1<=0.0 */
85 scale_edge0 = -D0 / (D1 - D0);
86 scale_edge1 = -D1 / (D2 - D1);
87 edge_index0 = 0;
88 edge_index1 = 1;
89 }
90 else if (D1 * D2 > 0.0f || D0 != 0.0f)
91 {
92 /* here we know that d0d1<=0.0 or that D0!=0.0 */
93 scale_edge0 = -D0 / (D1 - D0);
94 scale_edge1 = -D2 / (D0 - D2);
95 edge_index0 = 0;
96 edge_index1 = 2;
97 }
98 else
99 {
100 return false;
101 }
102 return true;
103 }
104
106
109 const btVector4 &tri_plane,
110 const btVector3 *tripoints,
111 const btVector3 *srcpoints,
112 btVector3 *clip_points)
113 {
114 // edge 0
115
116 btVector4 edgeplane;
117
118 EDGE_PLANE(tripoints[0], tripoints[1], tri_plane, edgeplane);
119
120 GUINT clipped_count = PLANE_CLIP_TRIANGLE3D(
121 edgeplane, srcpoints[0], srcpoints[1], srcpoints[2], temp_points);
122
123 if (clipped_count == 0) return 0;
124
125 // edge 1
126
127 EDGE_PLANE(tripoints[1], tripoints[2], tri_plane, edgeplane);
128
129 clipped_count = PLANE_CLIP_POLYGON3D(
130 edgeplane, temp_points, clipped_count, temp_points1);
131
132 if (clipped_count == 0) return 0;
133
134 // edge 2
135
136 EDGE_PLANE(tripoints[2], tripoints[0], tri_plane, edgeplane);
137
138 clipped_count = PLANE_CLIP_POLYGON3D(
139 edgeplane, temp_points1, clipped_count, clip_points);
140
141 return clipped_count;
142
143 /*GUINT i0 = (tri_plane.closestAxis()+1)%3;
144 GUINT i1 = (i0+1)%3;
145 // edge 0
146 btVector3 temp_points[MAX_TRI_CLIPPING];
147 btVector3 temp_points1[MAX_TRI_CLIPPING];
148
149 GUINT clipped_count= PLANE_CLIP_TRIANGLE_GENERIC(
150 0,srcpoints[0],srcpoints[1],srcpoints[2],temp_points,
151 DISTANCE_EDGE(tripoints[0],tripoints[1],i0,i1));
152
153
154 if(clipped_count == 0) return 0;
155
156 // edge 1
157 clipped_count = PLANE_CLIP_POLYGON_GENERIC(
158 0,temp_points,clipped_count,temp_points1,
159 DISTANCE_EDGE(tripoints[1],tripoints[2],i0,i1));
160
161 if(clipped_count == 0) return 0;
162
163 // edge 2
164 clipped_count = PLANE_CLIP_POLYGON_GENERIC(
165 0,temp_points1,clipped_count,clipped_points,
166 DISTANCE_EDGE(tripoints[2],tripoints[0],i0,i1));
167
168 return clipped_count;*/
169 }
170
172 GREAL &isect0, GREAL &isect1, GUINT &e0, GUINT &e1, btVector3 &vec0, btVector3 &vec1)
173 {
174 if (isect1 < isect0)
175 {
176 //swap
177 GIM_SWAP_NUMBERS(isect0, isect1);
178 GIM_SWAP_NUMBERS(e0, e1);
179 btVector3 tmp = vec0;
180 vec0 = vec1;
181 vec1 = tmp;
182 }
183 }
184
186
198 {
199 // Compute direction of intersection line
201 GREAL Dlen;
203
204 if (Dlen < 0.0001)
205 {
206 return 0; //faces near paralele
207 }
208
209 edge_edge_dir *= 1 / Dlen; //normalize
210
211 // Compute interval for triangle 1
212 GUINT tu_e0, tu_e1; //edge indices
213 GREAL tu_scale_e0, tu_scale_e1; //edge scale
214 if (!compute_intervals(du[0], du[1], du[2],
215 du0du1, du0du2, tu_scale_e0, tu_scale_e1, tu_e0, tu_e1)) return 0;
216
217 // Compute interval for triangle 2
218 GUINT tv_e0, tv_e1; //edge indices
219 GREAL tv_scale_e0, tv_scale_e1; //edge scale
220
221 if (!compute_intervals(dv[0], dv[1], dv[2],
222 dv0dv1, dv0dv2, tv_scale_e0, tv_scale_e1, tv_e0, tv_e1)) return 0;
223
224 //proyected vertices
225 btVector3 up_e0 = tu_vertices[tu_e0].lerp(tu_vertices[(tu_e0 + 1) % 3], tu_scale_e0);
226 btVector3 up_e1 = tu_vertices[tu_e1].lerp(tu_vertices[(tu_e1 + 1) % 3], tu_scale_e1);
227
228 btVector3 vp_e0 = tv_vertices[tv_e0].lerp(tv_vertices[(tv_e0 + 1) % 3], tv_scale_e0);
229 btVector3 vp_e1 = tv_vertices[tv_e1].lerp(tv_vertices[(tv_e1 + 1) % 3], tv_scale_e1);
230
231 //proyected intervals
232 GREAL isect_u[] = {up_e0.dot(edge_edge_dir), up_e1.dot(edge_edge_dir)};
233 GREAL isect_v[] = {vp_e0.dot(edge_edge_dir), vp_e1.dot(edge_edge_dir)};
234
235 sort_isect(isect_u[0], isect_u[1], tu_e0, tu_e1, up_e0, up_e1);
236 sort_isect(isect_v[0], isect_v[1], tv_e0, tv_e1, vp_e0, vp_e1);
237
238 const GREAL midpoint_u = 0.5f * (isect_u[0] + isect_u[1]); // midpoint
239 const GREAL midpoint_v = 0.5f * (isect_v[0] + isect_v[1]); // midpoint
240
241 if (midpoint_u < midpoint_v)
242 {
243 if (isect_u[1] >= isect_v[1]) // face U casts face V
244 {
245 return 1;
246 }
247 else if (isect_v[0] <= isect_u[0]) // face V casts face U
248 {
249 return 2;
250 }
251 // closest points
252 closest_point_u = up_e1;
253 closest_point_v = vp_e0;
254 // calc edges and separation
255
256 if (isect_u[1] + MIN_EDGE_EDGE_DIS < isect_v[0]) //calc distance between two lines instead
257 {
259 tu_vertices[tu_e1], tu_vertices[(tu_e1 + 1) % 3],
260 tv_vertices[tv_e0], tv_vertices[(tv_e0 + 1) % 3],
263
266 edge_edge_dir *= 1.0f / distances[2]; // normalize
267 }
268 else
269 {
270 distances[2] = isect_v[0] - isect_u[1]; //distance negative
271 //edge_edge_dir *= -1.0f; //normal pointing from V to U
272 }
273 }
274 else
275 {
276 if (isect_v[1] >= isect_u[1]) // face V casts face U
277 {
278 return 2;
279 }
280 else if (isect_u[0] <= isect_v[0]) // face U casts face V
281 {
282 return 1;
283 }
284 // closest points
285 closest_point_u = up_e0;
286 closest_point_v = vp_e1;
287 // calc edges and separation
288
289 if (isect_v[1] + MIN_EDGE_EDGE_DIS < isect_u[0]) //calc distance between two lines instead
290 {
292 tu_vertices[tu_e0], tu_vertices[(tu_e0 + 1) % 3],
293 tv_vertices[tv_e1], tv_vertices[(tv_e1 + 1) % 3],
296
299 edge_edge_dir *= 1.0f / distances[2]; // normalize
300 }
301 else
302 {
303 distances[2] = isect_u[0] - isect_v[1]; //distance negative
304 //edge_edge_dir *= -1.0f; //normal pointing from V to U
305 }
306 }
307 return 3;
308 }
309
312 const btVector3 &u0,
313 const btVector3 &u1,
314 const btVector3 &u2,
315 GREAL margin_u,
316 const btVector3 &v0,
317 const btVector3 &v1,
318 const btVector3 &v2,
319 GREAL margin_v,
321 {
322 margin = margin_u + margin_v;
323
324 tu_vertices[0] = u0;
325 tu_vertices[1] = u1;
326 tu_vertices[2] = u2;
327
328 tv_vertices[0] = v0;
329 tv_vertices[1] = v1;
330 tv_vertices[2] = v2;
331
332 //create planes
333 // plane v vs U points
334
336
340
341 du0du1 = du[0] * du[1];
342 du0du2 = du[0] * du[2];
343
344 if (du0du1 > 0.0f && du0du2 > 0.0f) // same sign on all of them + not equal 0 ?
345 {
346 if (du[0] < 0) //we need test behind the triangle plane
347 {
348 distances[0] = GIM_MAX3(du[0], du[1], du[2]);
349 distances[0] = -distances[0];
350 if (distances[0] > margin) return false; //never intersect
351
352 //reorder triangle v
355 }
356 else
357 {
358 distances[0] = GIM_MIN3(du[0], du[1], du[2]);
359 if (distances[0] > margin) return false; //never intersect
360 }
361 }
362 else
363 {
364 //Look if we need to invert the triangle
365 distances[0] = (du[0] + du[1] + du[2]) / 3.0f; //centroid
366
367 if (distances[0] < 0.0f)
368 {
369 //reorder triangle v
372
373 distances[0] = GIM_MAX3(du[0], du[1], du[2]);
374 distances[0] = -distances[0];
375 }
376 else
377 {
378 distances[0] = GIM_MIN3(du[0], du[1], du[2]);
379 }
380 }
381
382 // plane U vs V points
383
385
389
390 dv0dv1 = dv[0] * dv[1];
391 dv0dv2 = dv[0] * dv[2];
392
393 if (dv0dv1 > 0.0f && dv0dv2 > 0.0f) // same sign on all of them + not equal 0 ?
394 {
395 if (dv[0] < 0) //we need test behind the triangle plane
396 {
397 distances[1] = GIM_MAX3(dv[0], dv[1], dv[2]);
398 distances[1] = -distances[1];
399 if (distances[1] > margin) return false; //never intersect
400
401 //reorder triangle u
404 }
405 else
406 {
407 distances[1] = GIM_MIN3(dv[0], dv[1], dv[2]);
408 if (distances[1] > margin) return false; //never intersect
409 }
410 }
411 else
412 {
413 //Look if we need to invert the triangle
414 distances[1] = (dv[0] + dv[1] + dv[2]) / 3.0f; //centroid
415
416 if (distances[1] < 0.0f)
417 {
418 //reorder triangle v
421
422 distances[1] = GIM_MAX3(dv[0], dv[1], dv[2]);
423 distances[1] = -distances[1];
424 }
425 else
426 {
427 distances[1] = GIM_MIN3(dv[0], dv[1], dv[2]);
428 }
429 }
430
431 GUINT bl;
432 /* bl = cross_line_intersection_test();
433 if(bl==3)
434 {
435 //take edge direction too
436 bl = distances.maxAxis();
437 }
438 else
439 {*/
440 bl = 0;
441 if (distances[0] < distances[1]) bl = 1;
442 //}
443
444 if (bl == 2) //edge edge separation
445 {
446 if (distances[2] > margin) return false;
447
448 contacts.m_penetration_depth = -distances[2] + margin;
449 contacts.m_points[0] = closest_point_v;
450 contacts.m_point_count = 1;
452
453 return true;
454 }
455
456 //clip face against other
457
458 GUINT point_count;
459 //TODO
460 if (bl == 0) //clip U points against V
461 {
463 if (point_count == 0) return false;
464 contacts.merge_points(tv_plane, margin, contact_points, point_count);
465 }
466 else //clip V points against U
467 {
469 if (point_count == 0) return false;
470 contacts.merge_points(tu_plane, margin, contact_points, point_count);
471 contacts.m_separating_normal *= -1.f;
472 }
473 if (contacts.m_point_count == 0) return false;
474 return true;
475 }
476};
477
478/*class GIM_TRIANGLE_CALCULATION_CACHE
479{
480public:
481 GREAL margin;
482 GUINT clipped_count;
483 btVector3 tu_vertices[3];
484 btVector3 tv_vertices[3];
485 btVector3 temp_points[MAX_TRI_CLIPPING];
486 btVector3 temp_points1[MAX_TRI_CLIPPING];
487 btVector3 clipped_points[MAX_TRI_CLIPPING];
488 GIM_TRIANGLE_CONTACT_DATA contacts1;
489 GIM_TRIANGLE_CONTACT_DATA contacts2;
490
491
493 GUINT clip_triangle(
494 const btVector4 & tri_plane,
495 const btVector3 * tripoints,
496 const btVector3 * srcpoints,
497 btVector3 * clipped_points)
498 {
499 // edge 0
500
501 btVector4 edgeplane;
502
503 EDGE_PLANE(tripoints[0],tripoints[1],tri_plane,edgeplane);
504
505 GUINT clipped_count = PLANE_CLIP_TRIANGLE3D(
506 edgeplane,srcpoints[0],srcpoints[1],srcpoints[2],temp_points);
507
508 if(clipped_count == 0) return 0;
509
510 // edge 1
511
512 EDGE_PLANE(tripoints[1],tripoints[2],tri_plane,edgeplane);
513
514 clipped_count = PLANE_CLIP_POLYGON3D(
515 edgeplane,temp_points,clipped_count,temp_points1);
516
517 if(clipped_count == 0) return 0;
518
519 // edge 2
520
521 EDGE_PLANE(tripoints[2],tripoints[0],tri_plane,edgeplane);
522
523 clipped_count = PLANE_CLIP_POLYGON3D(
524 edgeplane,temp_points1,clipped_count,clipped_points);
525
526 return clipped_count;
527 }
528
529
530
531
533 bool triangle_collision(
534 const btVector3 & u0,
535 const btVector3 & u1,
536 const btVector3 & u2,
537 GREAL margin_u,
538 const btVector3 & v0,
539 const btVector3 & v1,
540 const btVector3 & v2,
541 GREAL margin_v,
542 GIM_TRIANGLE_CONTACT_DATA & contacts)
543 {
544
545 margin = margin_u + margin_v;
546
547
548 tu_vertices[0] = u0;
549 tu_vertices[1] = u1;
550 tu_vertices[2] = u2;
551
552 tv_vertices[0] = v0;
553 tv_vertices[1] = v1;
554 tv_vertices[2] = v2;
555
556 //create planes
557 // plane v vs U points
558
559
560 TRIANGLE_PLANE(tv_vertices[0],tv_vertices[1],tv_vertices[2],contacts1.m_separating_normal);
561
562 clipped_count = clip_triangle(
563 contacts1.m_separating_normal,tv_vertices,tu_vertices,clipped_points);
564
565 if(clipped_count == 0 )
566 {
567 return false;//Reject
568 }
569
570 //find most deep interval face1
571 contacts1.merge_points(contacts1.m_separating_normal,margin,clipped_points,clipped_count);
572 if(contacts1.m_point_count == 0) return false; // too far
573
574 //Normal pointing to triangle1
575 //contacts1.m_separating_normal *= -1.f;
576
577 //Clip tri1 by tri2 edges
578
579 TRIANGLE_PLANE(tu_vertices[0],tu_vertices[1],tu_vertices[2],contacts2.m_separating_normal);
580
581 clipped_count = clip_triangle(
582 contacts2.m_separating_normal,tu_vertices,tv_vertices,clipped_points);
583
584 if(clipped_count == 0 )
585 {
586 return false;//Reject
587 }
588
589 //find most deep interval face1
590 contacts2.merge_points(contacts2.m_separating_normal,margin,clipped_points,clipped_count);
591 if(contacts2.m_point_count == 0) return false; // too far
592
593 contacts2.m_separating_normal *= -1.f;
594
596 if(contacts2.m_penetration_depth<contacts1.m_penetration_depth)
597 {
598 contacts.copy_from(contacts2);
599 }
600 else
601 {
602 contacts.copy_from(contacts1);
603 }
604 return true;
605 }
606
607
608};*/
609
611 const GIM_TRIANGLE &other,
612 GIM_TRIANGLE_CONTACT_DATA &contact_data) const
613{
615 return calc_cache.triangle_collision(
617 other.m_vertices[0], other.m_vertices[1], other.m_vertices[2], other.m_margin,
618 contact_data);
619}
#define SIMD_FORCE_INLINE
Definition: btScalar.h:98
#define MAX_TRI_CLIPPING
btVector3 temp_points[MAX_TRI_CLIPPING]
void sort_isect(GREAL &isect0, GREAL &isect1, GUINT &e0, GUINT &e1, btVector3 &vec0, btVector3 &vec1)
bool triangle_collision(const btVector3 &u0, const btVector3 &u1, const btVector3 &u2, GREAL margin_u, const btVector3 &v0, const btVector3 &v1, const btVector3 &v2, GREAL margin_v, GIM_TRIANGLE_CONTACT_DATA &contacts)
collides by two sides
btVector3 temp_points1[MAX_TRI_CLIPPING]
bool compute_intervals(const GREAL &D0, const GREAL &D1, const GREAL &D2, const GREAL &D0D1, const GREAL &D0D2, GREAL &scale_edge0, GREAL &scale_edge1, GUINT &edge_index0, GUINT &edge_index1)
if returns false, the faces are paralele
GUINT cross_line_intersection_test()
Test verifying interval intersection with the direction between planes.
GUINT clip_triangle(const btVector4 &tri_plane, const btVector3 *tripoints, const btVector3 *srcpoints, btVector3 *clip_points)
clip triangle
btVector3 contact_points[MAX_TRI_CLIPPING]
Class for colliding triangles.
btVector3 m_vertices[3]
bool collide_triangle_hard_test(const GIM_TRIANGLE &other, GIM_TRIANGLE_CONTACT_DATA &contact_data) const
Test triangles by finding separating axis.
btVector3 can be used to represent 3D points and vectors.
Definition: btVector3.h:82
btVector3 cross(const btVector3 &v) const
Return the cross product between this and another vector.
Definition: btVector3.h:380
btScalar dot(const btVector3 &v) const
Return the dot product.
Definition: btVector3.h:229
btVector3 lerp(const btVector3 &v, const btScalar &t) const
Return the linear interpolation between this and another vector.
Definition: btVector3.h:521
#define DISTANCE_PLANE_POINT(plane, point)
#define TRIANGLE_PLANE(v1, v2, v3, plane)
plane is a vec4f
#define EDGE_PLANE(e1, e2, n, plane)
Calc a plane from an edge an a normal. plane is a vec4f.
void SEGMENT_COLLISION(const CLASS_POINT &vA1, const CLASS_POINT &vA2, const CLASS_POINT &vB1, const CLASS_POINT &vB2, CLASS_POINT &vPointA, CLASS_POINT &vPointB)
Find closest points on segments.
GUINT PLANE_CLIP_POLYGON3D(const CLASS_PLANE &plane, const CLASS_POINT *polygon_points, GUINT polygon_point_count, CLASS_POINT *clipped)
GUINT PLANE_CLIP_TRIANGLE3D(const CLASS_PLANE &plane, const CLASS_POINT &point0, const CLASS_POINT &point1, const CLASS_POINT &point2, CLASS_POINT *clipped)
#define VEC_SWAP(b, a)
VECTOR SWAP.
#define VEC_COPY(b, a)
Copy 3D vector.
#define VEC_LENGTH(a, l)
Vector length.
#define VEC_SCALE_4(c, a, b)
scalar times vector
#define GREAL
Definition: gim_math.h:37
#define GIM_SWAP_NUMBERS(a, b)
Swap numbers.
Definition: gim_math.h:105
#define GUINT
Definition: gim_math.h:40
#define GIM_MIN3(a, b, c)
Definition: gim_math.h:89
#define GIM_MAX3(a, b, c)
Definition: gim_math.h:88
#define MIN_EDGE_EDGE_DIS
Structure for collision.
btVector3 m_points[MAX_TRI_CLIPPING]
void merge_points(const btVector4 &plane, GREAL margin, const btVector3 *points, GUINT point_count)
classify points that are closer