1 2 /*! \file gim_tri_collision.h 3 \author Francisco Leon Najera 4 */ 5 /* 6 ----------------------------------------------------------------------------- 7 This source file is part of GIMPACT Library. 8 9 For the latest info, see http://gimpact.sourceforge.net/ 10 11 Copyright (c) 2006 Francisco Leon Najera. C.C. 80087371. 12 email: projectileman (at) 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 37 #define TRI_LOCAL_EPSILON 0.000001f 38 #define MIN_EDGE_EDGE_DIS 0.00001f 39 40 41 class GIM_TRIANGLE_CALCULATION_CACHE 42 { 43 public: 44 GREAL margin; 45 btVector3 tu_vertices[3]; 46 btVector3 tv_vertices[3]; 47 btVector4 tu_plane; 48 btVector4 tv_plane; 49 btVector3 closest_point_u; 50 btVector3 closest_point_v; 51 btVector3 edge_edge_dir; 52 btVector3 distances; 53 GREAL du[4]; 54 GREAL du0du1; 55 GREAL du0du2; 56 GREAL dv[4]; 57 GREAL dv0dv1; 58 GREAL dv0dv2; 59 btVector3 temp_points[MAX_TRI_CLIPPING]; 60 btVector3 temp_points1[MAX_TRI_CLIPPING]; 61 btVector3 contact_points[MAX_TRI_CLIPPING]; 62 63 64 65 //! if returns false, the faces are paralele 66 SIMD_FORCE_INLINE bool compute_intervals( 67 const GREAL &D0, 68 const GREAL &D1, 69 const GREAL &D2, 70 const GREAL &D0D1, 71 const GREAL &D0D2, 72 GREAL & scale_edge0, 73 GREAL & scale_edge1, 74 GUINT &edge_index0, 75 GUINT &edge_index1) 76 { 77 if(D0D1>0.0f) 78 { 79 /* here we know that D0D2<=0.0 */ 80 /* that is D0, D1 are on the same side, D2 on the other or on the plane */ 81 scale_edge0 = -D2/(D0-D2); 82 scale_edge1 = -D1/(D2-D1); 83 edge_index0 = 2;edge_index1 = 1; 84 } 85 else if(D0D2>0.0f) 86 { 87 /* here we know that d0d1<=0.0 */ 88 scale_edge0 = -D0/(D1-D0); 89 scale_edge1 = -D1/(D2-D1); 90 edge_index0 = 0;edge_index1 = 1; 91 } 92 else if(D1*D2>0.0f || D0!=0.0f) 93 { 94 /* here we know that d0d1<=0.0 or that D0!=0.0 */ 95 scale_edge0 = -D0/(D1-D0); 96 scale_edge1 = -D2/(D0-D2); 97 edge_index0 = 0 ;edge_index1 = 2; 98 } 99 else 100 { 101 return false; 102 } 103 return true; 104 } 105 106 107 //! clip triangle 108 /*! 109 */ 110 SIMD_FORCE_INLINE GUINT clip_triangle( 111 const btVector4 & tri_plane, 112 const btVector3 * tripoints, 113 const btVector3 * srcpoints, 114 btVector3 * clip_points) 115 { 116 // edge 0 117 118 btVector4 edgeplane; 119 120 EDGE_PLANE(tripoints[0],tripoints[1],tri_plane,edgeplane); 121 122 GUINT clipped_count = PLANE_CLIP_TRIANGLE3D( 123 edgeplane,srcpoints[0],srcpoints[1],srcpoints[2],temp_points); 124 125 if(clipped_count == 0) return 0; 126 127 // edge 1 128 129 EDGE_PLANE(tripoints[1],tripoints[2],tri_plane,edgeplane); 130 131 clipped_count = PLANE_CLIP_POLYGON3D( 132 edgeplane,temp_points,clipped_count,temp_points1); 133 134 if(clipped_count == 0) return 0; 135 136 // edge 2 137 138 EDGE_PLANE(tripoints[2],tripoints[0],tri_plane,edgeplane); 139 140 clipped_count = PLANE_CLIP_POLYGON3D( 141 edgeplane,temp_points1,clipped_count,clip_points); 142 143 return clipped_count; 144 145 146 /*GUINT i0 = (tri_plane.closestAxis()+1)%3; 147 GUINT i1 = (i0+1)%3; 148 // edge 0 149 btVector3 temp_points[MAX_TRI_CLIPPING]; 150 btVector3 temp_points1[MAX_TRI_CLIPPING]; 151 152 GUINT clipped_count= PLANE_CLIP_TRIANGLE_GENERIC( 153 0,srcpoints[0],srcpoints[1],srcpoints[2],temp_points, 154 DISTANCE_EDGE(tripoints[0],tripoints[1],i0,i1)); 155 156 157 if(clipped_count == 0) return 0; 158 159 // edge 1 160 clipped_count = PLANE_CLIP_POLYGON_GENERIC( 161 0,temp_points,clipped_count,temp_points1, 162 DISTANCE_EDGE(tripoints[1],tripoints[2],i0,i1)); 163 164 if(clipped_count == 0) return 0; 165 166 // edge 2 167 clipped_count = PLANE_CLIP_POLYGON_GENERIC( 168 0,temp_points1,clipped_count,clipped_points, 169 DISTANCE_EDGE(tripoints[2],tripoints[0],i0,i1)); 170 171 return clipped_count;*/ 172 } 173 174 SIMD_FORCE_INLINE void sort_isect( 175 GREAL & isect0,GREAL & isect1,GUINT &e0,GUINT &e1,btVector3 & vec0,btVector3 & vec1) 176 { 177 if(isect1<isect0) 178 { 179 //swap 180 GIM_SWAP_NUMBERS(isect0,isect1); 181 GIM_SWAP_NUMBERS(e0,e1); 182 btVector3 tmp = vec0; 183 vec0 = vec1; 184 vec1 = tmp; 185 } 186 } 187 188 //! Test verifying interval intersection with the direction between planes 189 /*! 190 \pre tv_plane and tu_plane must be set 191 \post 192 distances[2] is set with the distance 193 closest_point_u, closest_point_v, edge_edge_dir are set too 194 \return 195 - 0: faces are paralele 196 - 1: face U casts face V 197 - 2: face V casts face U 198 - 3: nearest edges 199 */ 200 SIMD_FORCE_INLINE GUINT cross_line_intersection_test() 201 { 202 // Compute direction of intersection line 203 edge_edge_dir = tu_plane.cross(tv_plane); 204 GREAL Dlen; 205 VEC_LENGTH(edge_edge_dir,Dlen); 206 207 if(Dlen<0.0001) 208 { 209 return 0; //faces near paralele 210 } 211 212 edge_edge_dir*= 1/Dlen;//normalize 213 214 215 // Compute interval for triangle 1 216 GUINT tu_e0,tu_e1;//edge indices 217 GREAL tu_scale_e0,tu_scale_e1;//edge scale 218 if(!compute_intervals(du[0],du[1],du[2], 219 du0du1,du0du2,tu_scale_e0,tu_scale_e1,tu_e0,tu_e1)) return 0; 220 221 // Compute interval for triangle 2 222 GUINT tv_e0,tv_e1;//edge indices 223 GREAL tv_scale_e0,tv_scale_e1;//edge scale 224 225 if(!compute_intervals(dv[0],dv[1],dv[2], 226 dv0dv1,dv0dv2,tv_scale_e0,tv_scale_e1,tv_e0,tv_e1)) return 0; 227 228 //proyected vertices 229 btVector3 up_e0 = tu_vertices[tu_e0].lerp(tu_vertices[(tu_e0+1)%3],tu_scale_e0); 230 btVector3 up_e1 = tu_vertices[tu_e1].lerp(tu_vertices[(tu_e1+1)%3],tu_scale_e1); 231 232 btVector3 vp_e0 = tv_vertices[tv_e0].lerp(tv_vertices[(tv_e0+1)%3],tv_scale_e0); 233 btVector3 vp_e1 = tv_vertices[tv_e1].lerp(tv_vertices[(tv_e1+1)%3],tv_scale_e1); 234 235 //proyected intervals 236 GREAL isect_u[] = {up_e0.dot(edge_edge_dir),up_e1.dot(edge_edge_dir)}; 237 GREAL isect_v[] = {vp_e0.dot(edge_edge_dir),vp_e1.dot(edge_edge_dir)}; 238 239 sort_isect(isect_u[0],isect_u[1],tu_e0,tu_e1,up_e0,up_e1); 240 sort_isect(isect_v[0],isect_v[1],tv_e0,tv_e1,vp_e0,vp_e1); 241 242 const GREAL midpoint_u = 0.5f*(isect_u[0]+isect_u[1]); // midpoint 243 const GREAL midpoint_v = 0.5f*(isect_v[0]+isect_v[1]); // midpoint 244 245 if(midpoint_u<midpoint_v) 246 { 247 if(isect_u[1]>=isect_v[1]) // face U casts face V 248 { 249 return 1; 250 } 251 else if(isect_v[0]<=isect_u[0]) // face V casts face U 252 { 253 return 2; 254 } 255 // closest points 256 closest_point_u = up_e1; 257 closest_point_v = vp_e0; 258 // calc edges and separation 259 260 if(isect_u[1]+ MIN_EDGE_EDGE_DIS<isect_v[0]) //calc distance between two lines instead 261 { 262 SEGMENT_COLLISION( 263 tu_vertices[tu_e1],tu_vertices[(tu_e1+1)%3], 264 tv_vertices[tv_e0],tv_vertices[(tv_e0+1)%3], 265 closest_point_u, 266 closest_point_v); 267 268 edge_edge_dir = closest_point_u-closest_point_v; 269 VEC_LENGTH(edge_edge_dir,distances[2]); 270 edge_edge_dir *= 1.0f/distances[2];// normalize 271 } 272 else 273 { 274 distances[2] = isect_v[0]-isect_u[1];//distance negative 275 //edge_edge_dir *= -1.0f; //normal pointing from V to U 276 } 277 278 } 279 else 280 { 281 if(isect_v[1]>=isect_u[1]) // face V casts face U 282 { 283 return 2; 284 } 285 else if(isect_u[0]<=isect_v[0]) // face U casts face V 286 { 287 return 1; 288 } 289 // closest points 290 closest_point_u = up_e0; 291 closest_point_v = vp_e1; 292 // calc edges and separation 293 294 if(isect_v[1]+MIN_EDGE_EDGE_DIS<isect_u[0]) //calc distance between two lines instead 295 { 296 SEGMENT_COLLISION( 297 tu_vertices[tu_e0],tu_vertices[(tu_e0+1)%3], 298 tv_vertices[tv_e1],tv_vertices[(tv_e1+1)%3], 299 closest_point_u, 300 closest_point_v); 301 302 edge_edge_dir = closest_point_u-closest_point_v; 303 VEC_LENGTH(edge_edge_dir,distances[2]); 304 edge_edge_dir *= 1.0f/distances[2];// normalize 305 } 306 else 307 { 308 distances[2] = isect_u[0]-isect_v[1];//distance negative 309 //edge_edge_dir *= -1.0f; //normal pointing from V to U 310 } 311 } 312 return 3; 313 } 314 315 316 //! collides by two sides 317 SIMD_FORCE_INLINE bool triangle_collision( 318 const btVector3 & u0, 319 const btVector3 & u1, 320 const btVector3 & u2, 321 GREAL margin_u, 322 const btVector3 & v0, 323 const btVector3 & v1, 324 const btVector3 & v2, 325 GREAL margin_v, 326 GIM_TRIANGLE_CONTACT_DATA & contacts) 327 { 328 329 margin = margin_u + margin_v; 330 331 tu_vertices[0] = u0; 332 tu_vertices[1] = u1; 333 tu_vertices[2] = u2; 334 335 tv_vertices[0] = v0; 336 tv_vertices[1] = v1; 337 tv_vertices[2] = v2; 338 339 //create planes 340 // plane v vs U points 341 342 TRIANGLE_PLANE(tv_vertices[0],tv_vertices[1],tv_vertices[2],tv_plane); 343 344 du[0] = DISTANCE_PLANE_POINT(tv_plane,tu_vertices[0]); 345 du[1] = DISTANCE_PLANE_POINT(tv_plane,tu_vertices[1]); 346 du[2] = DISTANCE_PLANE_POINT(tv_plane,tu_vertices[2]); 347 348 349 du0du1 = du[0] * du[1]; 350 du0du2 = du[0] * du[2]; 351 352 353 if(du0du1>0.0f && du0du2>0.0f) // same sign on all of them + not equal 0 ? 354 { 355 if(du[0]<0) //we need test behind the triangle plane 356 { 357 distances[0] = GIM_MAX3(du[0],du[1],du[2]); 358 distances[0] = -distances[0]; 359 if(distances[0]>margin) return false; //never intersect 360 361 //reorder triangle v 362 VEC_SWAP(tv_vertices[0],tv_vertices[1]); 363 VEC_SCALE_4(tv_plane,-1.0f,tv_plane); 364 } 365 else 366 { 367 distances[0] = GIM_MIN3(du[0],du[1],du[2]); 368 if(distances[0]>margin) return false; //never intersect 369 } 370 } 371 else 372 { 373 //Look if we need to invert the triangle 374 distances[0] = (du[0]+du[1]+du[2])/3.0f; //centroid 375 376 if(distances[0]<0.0f) 377 { 378 //reorder triangle v 379 VEC_SWAP(tv_vertices[0],tv_vertices[1]); 380 VEC_SCALE_4(tv_plane,-1.0f,tv_plane); 381 382 distances[0] = GIM_MAX3(du[0],du[1],du[2]); 383 distances[0] = -distances[0]; 384 } 385 else 386 { 387 distances[0] = GIM_MIN3(du[0],du[1],du[2]); 388 } 389 } 390 391 392 // plane U vs V points 393 394 TRIANGLE_PLANE(tu_vertices[0],tu_vertices[1],tu_vertices[2],tu_plane); 395 396 dv[0] = DISTANCE_PLANE_POINT(tu_plane,tv_vertices[0]); 397 dv[1] = DISTANCE_PLANE_POINT(tu_plane,tv_vertices[1]); 398 dv[2] = DISTANCE_PLANE_POINT(tu_plane,tv_vertices[2]); 399 400 dv0dv1 = dv[0] * dv[1]; 401 dv0dv2 = dv[0] * dv[2]; 402 403 404 if(dv0dv1>0.0f && dv0dv2>0.0f) // same sign on all of them + not equal 0 ? 405 { 406 if(dv[0]<0) //we need test behind the triangle plane 407 { 408 distances[1] = GIM_MAX3(dv[0],dv[1],dv[2]); 409 distances[1] = -distances[1]; 410 if(distances[1]>margin) return false; //never intersect 411 412 //reorder triangle u 413 VEC_SWAP(tu_vertices[0],tu_vertices[1]); 414 VEC_SCALE_4(tu_plane,-1.0f,tu_plane); 415 } 416 else 417 { 418 distances[1] = GIM_MIN3(dv[0],dv[1],dv[2]); 419 if(distances[1]>margin) return false; //never intersect 420 } 421 } 422 else 423 { 424 //Look if we need to invert the triangle 425 distances[1] = (dv[0]+dv[1]+dv[2])/3.0f; //centroid 426 427 if(distances[1]<0.0f) 428 { 429 //reorder triangle v 430 VEC_SWAP(tu_vertices[0],tu_vertices[1]); 431 VEC_SCALE_4(tu_plane,-1.0f,tu_plane); 432 433 distances[1] = GIM_MAX3(dv[0],dv[1],dv[2]); 434 distances[1] = -distances[1]; 435 } 436 else 437 { 438 distances[1] = GIM_MIN3(dv[0],dv[1],dv[2]); 439 } 440 } 441 442 GUINT bl; 443 /* bl = cross_line_intersection_test(); 444 if(bl==3) 445 { 446 //take edge direction too 447 bl = distances.maxAxis(); 448 } 449 else 450 {*/ 451 bl = 0; 452 if(distances[0]<distances[1]) bl = 1; 453 //} 454 455 if(bl==2) //edge edge separation 456 { 457 if(distances[2]>margin) return false; 458 459 contacts.m_penetration_depth = -distances[2] + margin; 460 contacts.m_points[0] = closest_point_v; 461 contacts.m_point_count = 1; 462 VEC_COPY(contacts.m_separating_normal,edge_edge_dir); 463 464 return true; 465 } 466 467 //clip face against other 468 469 470 GUINT point_count; 471 //TODO 472 if(bl == 0) //clip U points against V 473 { 474 point_count = clip_triangle(tv_plane,tv_vertices,tu_vertices,contact_points); 475 if(point_count == 0) return false; 476 contacts.merge_points(tv_plane,margin,contact_points,point_count); 477 } 478 else //clip V points against U 479 { 480 point_count = clip_triangle(tu_plane,tu_vertices,tv_vertices,contact_points); 481 if(point_count == 0) return false; 482 contacts.merge_points(tu_plane,margin,contact_points,point_count); 483 contacts.m_separating_normal *= -1.f; 484 } 485 if(contacts.m_point_count == 0) return false; 486 return true; 487 } 488 489 }; 490 491 492 /*class GIM_TRIANGLE_CALCULATION_CACHE 493 { 494 public: 495 GREAL margin; 496 GUINT clipped_count; 497 btVector3 tu_vertices[3]; 498 btVector3 tv_vertices[3]; 499 btVector3 temp_points[MAX_TRI_CLIPPING]; 500 btVector3 temp_points1[MAX_TRI_CLIPPING]; 501 btVector3 clipped_points[MAX_TRI_CLIPPING]; 502 GIM_TRIANGLE_CONTACT_DATA contacts1; 503 GIM_TRIANGLE_CONTACT_DATA contacts2; 504 505 506 //! clip triangle 507 GUINT clip_triangle( 508 const btVector4 & tri_plane, 509 const btVector3 * tripoints, 510 const btVector3 * srcpoints, 511 btVector3 * clipped_points) 512 { 513 // edge 0 514 515 btVector4 edgeplane; 516 517 EDGE_PLANE(tripoints[0],tripoints[1],tri_plane,edgeplane); 518 519 GUINT clipped_count = PLANE_CLIP_TRIANGLE3D( 520 edgeplane,srcpoints[0],srcpoints[1],srcpoints[2],temp_points); 521 522 if(clipped_count == 0) return 0; 523 524 // edge 1 525 526 EDGE_PLANE(tripoints[1],tripoints[2],tri_plane,edgeplane); 527 528 clipped_count = PLANE_CLIP_POLYGON3D( 529 edgeplane,temp_points,clipped_count,temp_points1); 530 531 if(clipped_count == 0) return 0; 532 533 // edge 2 534 535 EDGE_PLANE(tripoints[2],tripoints[0],tri_plane,edgeplane); 536 537 clipped_count = PLANE_CLIP_POLYGON3D( 538 edgeplane,temp_points1,clipped_count,clipped_points); 539 540 return clipped_count; 541 } 542 543 544 545 546 //! collides only on one side 547 bool triangle_collision( 548 const btVector3 & u0, 549 const btVector3 & u1, 550 const btVector3 & u2, 551 GREAL margin_u, 552 const btVector3 & v0, 553 const btVector3 & v1, 554 const btVector3 & v2, 555 GREAL margin_v, 556 GIM_TRIANGLE_CONTACT_DATA & contacts) 557 { 558 559 margin = margin_u + margin_v; 560 561 562 tu_vertices[0] = u0; 563 tu_vertices[1] = u1; 564 tu_vertices[2] = u2; 565 566 tv_vertices[0] = v0; 567 tv_vertices[1] = v1; 568 tv_vertices[2] = v2; 569 570 //create planes 571 // plane v vs U points 572 573 574 TRIANGLE_PLANE(tv_vertices[0],tv_vertices[1],tv_vertices[2],contacts1.m_separating_normal); 575 576 clipped_count = clip_triangle( 577 contacts1.m_separating_normal,tv_vertices,tu_vertices,clipped_points); 578 579 if(clipped_count == 0 ) 580 { 581 return false;//Reject 582 } 583 584 //find most deep interval face1 585 contacts1.merge_points(contacts1.m_separating_normal,margin,clipped_points,clipped_count); 586 if(contacts1.m_point_count == 0) return false; // too far 587 588 //Normal pointing to triangle1 589 //contacts1.m_separating_normal *= -1.f; 590 591 //Clip tri1 by tri2 edges 592 593 TRIANGLE_PLANE(tu_vertices[0],tu_vertices[1],tu_vertices[2],contacts2.m_separating_normal); 594 595 clipped_count = clip_triangle( 596 contacts2.m_separating_normal,tu_vertices,tv_vertices,clipped_points); 597 598 if(clipped_count == 0 ) 599 { 600 return false;//Reject 601 } 602 603 //find most deep interval face1 604 contacts2.merge_points(contacts2.m_separating_normal,margin,clipped_points,clipped_count); 605 if(contacts2.m_point_count == 0) return false; // too far 606 607 contacts2.m_separating_normal *= -1.f; 608 609 ////check most dir for contacts 610 if(contacts2.m_penetration_depth<contacts1.m_penetration_depth) 611 { 612 contacts.copy_from(contacts2); 613 } 614 else 615 { 616 contacts.copy_from(contacts1); 617 } 618 return true; 619 } 620 621 622 };*/ 623 624 625 626 bool GIM_TRIANGLE::collide_triangle_hard_test( 627 const GIM_TRIANGLE & other, 628 GIM_TRIANGLE_CONTACT_DATA & contact_data) const 629 { 630 GIM_TRIANGLE_CALCULATION_CACHE calc_cache; 631 return calc_cache.triangle_collision( 632 m_vertices[0],m_vertices[1],m_vertices[2],m_margin, 633 other.m_vertices[0],other.m_vertices[1],other.m_vertices[2],other.m_margin, 634 contact_data); 635 636 } 637 638 639 640 641