1 /*************************************************************************
3 * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. *
4 * All rights reserved. Email: russ@q12.org Web: www.q12.org *
6 * This library is free software; you can redistribute it and/or *
7 * modify it under the terms of EITHER: *
8 * (1) The GNU Lesser General Public License as published by the Free *
9 * Software Foundation; either version 2.1 of the License, or (at *
10 * your option) any later version. The text of the GNU Lesser *
11 * General Public License is included with this library in the *
13 * (2) The BSD-style license that is included with this library in *
14 * the file LICENSE-BSD.TXT. *
16 * This library is distributed in the hope that it will be useful, *
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files *
19 * LICENSE.TXT and LICENSE-BSD.TXT for more details. *
21 *************************************************************************/
23 // OPCODE TriMesh/TriMesh collision code
24 // Written at 2006-10-28 by Francisco León (http://gimpact.sourceforge.net)
27 #pragma warning(disable:4244 4305) // for VC++, no precision loss complaints
30 #include <ode/collision.h>
31 #include <ode/matrix.h>
32 #include <ode/rotation.h>
33 #include <ode/odemath.h>
37 #if dTRIMESH_OPCODE_USE_NEW_TRIMESH_TRIMESH_COLLIDER
41 #include "collision_util.h"
42 #include "collision_trimesh_internal.h"
46 // Have collider cache instance unconditionally of OPCODE or GIMPACT selection
47 /*extern */TrimeshCollidersCache g_ccTrimeshCollidersCache
;
53 #define SMALL_ELT REAL(2.5e-4)
54 #define EXPANDED_ELT_THRESH REAL(1.0e-3)
55 #define DISTANCE_EPSILON REAL(1.0e-8)
56 #define VELOCITY_EPSILON REAL(1.0e-5)
57 #define TINY_PENETRATION REAL(5.0e-6)
66 dVector3 Points
[MAX_POINTS
];
71 // static void GetTriangleGeometryCallback(udword, VertexPointers&, udword); -- not used
72 inline void dMakeMatrix4(const dVector3 Position
, const dMatrix3 Rotation
, dMatrix4
&B
);
73 static void dInvertMatrix4( dMatrix4
& B
, dMatrix4
& Binv
);
74 static int IntersectLineSegmentRay(dVector3
, dVector3
, dVector3
, dVector3
, dVector3
);
75 static void ClipConvexPolygonAgainstPlane( const dVector3
, dReal
, LineContactSet
& );
76 static int RayTriangleIntersect(const dVector3 orig
, const dVector3 dir
,
77 const dVector3 vert0
, const dVector3 vert1
,const dVector3 vert2
,
78 dReal
*t
,dReal
*u
,dReal
*v
);
81 ///returns the penetration depth
82 static dReal
MostDeepPoints(
83 LineContactSet
& points
,
84 const dVector3 plane_normal
,
86 LineContactSet
& deep_points
);
87 ///returns the penetration depth
88 static dReal
FindMostDeepPointsInTetra(
89 LineContactSet contact_points
,
90 const dVector3 sourcetri
[3],///triangle which contains contact_points
91 const dVector3 tetra
[4],
92 const dVector4 tetraplanes
[4],
93 dVector3 separating_normal
,
94 LineContactSet deep_points
);
96 static bool ClipTriByTetra(const dVector3 tri
[3],
97 const dVector3 tetra
[4],
98 LineContactSet
& Contacts
);
99 static bool TriTriContacts(const dVector3 tr1
[3],
100 const dVector3 tr2
[3],
101 dxGeom
* g1
, dxGeom
* g2
, int Flags
,
102 CONTACT_KEY_HASH_TABLE
&hashcontactset
,
103 dContactGeom
* Contacts
, int Stride
,
107 /* some math macros */
108 #define CROSS(dest,v1,v2) { dest[0]=v1[1]*v2[2]-v1[2]*v2[1]; \
109 dest[1]=v1[2]*v2[0]-v1[0]*v2[2]; \
110 dest[2]=v1[0]*v2[1]-v1[1]*v2[0]; }
112 #define DOT(v1,v2) (v1[0]*v2[0]+v1[1]*v2[1]+v1[2]*v2[2])
114 #define SUB(dest,v1,v2) { dest[0]=v1[0]-v2[0]; dest[1]=v1[1]-v2[1]; dest[2]=v1[2]-v2[2]; }
116 #define ADD(dest,v1,v2) { dest[0]=v1[0]+v2[0]; dest[1]=v1[1]+v2[1]; dest[2]=v1[2]+v2[2]; }
118 #define MULT(dest,v,factor) { dest[0]=factor*v[0]; dest[1]=factor*v[1]; dest[2]=factor*v[2]; }
120 #define SET(dest,src) { dest[0]=src[0]; dest[1]=src[1]; dest[2]=src[2]; }
122 #define SMULT(p,q,s) { p[0]=q[0]*s; p[1]=q[1]*s; p[2]=q[2]*s; }
124 #define COMBO(combo,p,t,q) { combo[0]=p[0]+t*q[0]; combo[1]=p[1]+t*q[1]; combo[2]=p[2]+t*q[2]; }
126 #define LENGTH(x) ((dReal) 1.0f/InvSqrt(dDOT(x, x)))
128 #define DEPTH(d, p, q, n) d = (p[0] - q[0])*n[0] + (p[1] - q[1])*n[1] + (p[2] - q[2])*n[2];
130 inline const dReal
dMin(const dReal x
, const dReal y
)
132 return x
< y
? x
: y
;
137 SwapNormals(dVector3
*&pen_v
, dVector3
*&col_v
, dVector3
* v1
, dVector3
* v2
,
138 dVector3
*&pen_elt
, dVector3
*elt_f1
, dVector3
*elt_f2
,
139 dVector3 n
, dVector3 n1
, dVector3 n2
)
155 ///////////////////////MECHANISM FOR AVOID CONTACT REDUNDANCE///////////////////////////////
156 ////* Written by Francisco León (http://gimpact.sourceforge.net) *///
157 #define CONTACT_DIFF_EPSILON REAL(0.00001)
159 #define CONTACT_NORMAL_ZERO REAL(0.0000001)
160 #else // if defined(dSINGLE)
161 #define CONTACT_NORMAL_ZERO REAL(0.00001)
163 #define CONTACT_POS_HASH_QUOTIENT REAL(10000.0)
164 #define dSQRT3 REAL(1.7320508075688773)
168 void UpdateContactKey(CONTACT_KEY
& key
, dContactGeom
* contact
)
170 key
.m_contact
= contact
;
178 dReal coord
= contact
->pos
[i
];
179 coord
= dFloor(coord
* CONTACT_POS_HASH_QUOTIENT
);
181 unsigned int hash_input
= ((unsigned int *)&coord
)[0];
182 if (sizeof(dReal
) / sizeof(unsigned int) != 1)
184 dIASSERT(sizeof(dReal
) / sizeof(unsigned int) == 2);
185 hash_input
^= ((unsigned int *)&coord
)[1];
188 hash
= (( hash
<< 4 ) + (hash_input
>> 24)) ^ ( hash
>> 28 );
189 hash
= (( hash
<< 4 ) + ((hash_input
>> 16) & 0xFF)) ^ ( hash
>> 28 );
190 hash
= (( hash
<< 4 ) + ((hash_input
>> 8) & 0xFF)) ^ ( hash
>> 28 );
191 hash
= (( hash
<< 4 ) + (hash_input
& 0xFF)) ^ ( hash
>> 28 );
198 hash
= (hash
<< 11) | (hash
>> 21);
205 static inline unsigned int MakeContactIndex(unsigned int key
)
207 dIASSERT(CONTACTS_HASHSIZE
== 256);
209 unsigned int index
= key
^ (key
>> 16);
210 index
= (index
^ (index
>> 8)) & 0xFF;
214 dContactGeom
*AddContactToNode(const CONTACT_KEY
* contactkey
,CONTACT_KEY_HASH_NODE
* node
)
216 for(int i
=0;i
<node
->m_keycount
;i
++)
218 if(node
->m_keyarray
[i
].m_key
== contactkey
->m_key
)
220 dContactGeom
*contactfound
= node
->m_keyarray
[i
].m_contact
;
221 if (dDISTANCE(contactfound
->pos
, contactkey
->m_contact
->pos
) < REAL(1.00001) /*for comp. errors*/ * dSQRT3
/ CONTACT_POS_HASH_QUOTIENT
/*cube diagonal*/)
228 if (node
->m_keycount
< MAXCONTACT_X_NODE
)
230 node
->m_keyarray
[node
->m_keycount
].m_contact
= contactkey
->m_contact
;
231 node
->m_keyarray
[node
->m_keycount
].m_key
= contactkey
->m_key
;
236 dDEBUGMSG("Trimesh-trimesh contach hash table bucket overflow - close contacts might not be culled");
239 return contactkey
->m_contact
;
242 void RemoveNewContactFromNode(const CONTACT_KEY
* contactkey
, CONTACT_KEY_HASH_NODE
* node
)
244 dIASSERT(node
->m_keycount
> 0);
246 if (node
->m_keyarray
[node
->m_keycount
- 1].m_contact
== contactkey
->m_contact
)
248 node
->m_keycount
-= 1;
252 dIASSERT(node
->m_keycount
== MAXCONTACT_X_NODE
);
256 void RemoveArbitraryContactFromNode(const CONTACT_KEY
*contactkey
, CONTACT_KEY_HASH_NODE
*node
)
258 dIASSERT(node
->m_keycount
> 0);
260 int keyindex
, lastkeyindex
= node
->m_keycount
- 1;
262 // Do not check the last contact
263 for (keyindex
= 0; keyindex
< lastkeyindex
; keyindex
++)
265 if (node
->m_keyarray
[keyindex
].m_contact
== contactkey
->m_contact
)
267 node
->m_keyarray
[keyindex
] = node
->m_keyarray
[lastkeyindex
];
272 dIASSERT(keyindex
< lastkeyindex
||
273 node
->m_keyarray
[keyindex
].m_contact
== contactkey
->m_contact
); // It has been either the break from loop or last element should match
275 node
->m_keycount
= lastkeyindex
;
278 void UpdateArbitraryContactInNode(const CONTACT_KEY
*contactkey
, CONTACT_KEY_HASH_NODE
*node
,
279 dContactGeom
*pwithcontact
)
281 dIASSERT(node
->m_keycount
> 0);
283 int keyindex
, lastkeyindex
= node
->m_keycount
- 1;
285 // Do not check the last contact
286 for (keyindex
= 0; keyindex
< lastkeyindex
; keyindex
++)
288 if (node
->m_keyarray
[keyindex
].m_contact
== contactkey
->m_contact
)
294 dIASSERT(keyindex
< lastkeyindex
||
295 node
->m_keyarray
[keyindex
].m_contact
== contactkey
->m_contact
); // It has been either the break from loop or last element should match
297 node
->m_keyarray
[keyindex
].m_contact
= pwithcontact
;
300 void ClearContactSet(CONTACT_KEY_HASH_TABLE
&hashcontactset
)
302 memset(&hashcontactset
, 0, sizeof(CONTACT_KEY_HASH_TABLE
));
305 //return true if found
306 dContactGeom
*InsertContactInSet(CONTACT_KEY_HASH_TABLE
&hashcontactset
, const CONTACT_KEY
&newkey
)
308 unsigned int index
= MakeContactIndex(newkey
.m_key
);
310 return AddContactToNode(&newkey
, &hashcontactset
[index
]);
313 void RemoveNewContactFromSet(CONTACT_KEY_HASH_TABLE
&hashcontactset
, const CONTACT_KEY
&contactkey
)
315 unsigned int index
= MakeContactIndex(contactkey
.m_key
);
317 RemoveNewContactFromNode(&contactkey
, &hashcontactset
[index
]);
320 void RemoveArbitraryContactFromSet(CONTACT_KEY_HASH_TABLE
&hashcontactset
, const CONTACT_KEY
&contactkey
)
322 unsigned int index
= MakeContactIndex(contactkey
.m_key
);
324 RemoveArbitraryContactFromNode(&contactkey
, &hashcontactset
[index
]);
327 void UpdateArbitraryContactInSet(CONTACT_KEY_HASH_TABLE
&hashcontactset
, const CONTACT_KEY
&contactkey
,
328 dContactGeom
*pwithcontact
)
330 unsigned int index
= MakeContactIndex(contactkey
.m_key
);
332 UpdateArbitraryContactInNode(&contactkey
, &hashcontactset
[index
], pwithcontact
);
335 bool AllocNewContact(
336 const dVector3 newpoint
, dContactGeom
*& out_pcontact
,
337 int Flags
, CONTACT_KEY_HASH_TABLE
&hashcontactset
,
338 dContactGeom
* Contacts
, int Stride
, int &contactcount
)
340 bool allocated_new
= false;
342 dContactGeom dLocalContact
;
344 dContactGeom
* pcontact
= contactcount
!= (Flags
& NUMC_MASK
) ?
345 SAFECONTACT(Flags
, Contacts
, contactcount
, Stride
) : &dLocalContact
;
347 pcontact
->pos
[0] = newpoint
[0];
348 pcontact
->pos
[1] = newpoint
[1];
349 pcontact
->pos
[2] = newpoint
[2];
350 pcontact
->pos
[3] = 1.0f
;
353 UpdateContactKey(newkey
, pcontact
);
355 dContactGeom
*pcontactfound
= InsertContactInSet(hashcontactset
, newkey
);
356 if (pcontactfound
== pcontact
)
358 if (pcontactfound
!= &dLocalContact
)
364 RemoveNewContactFromSet(hashcontactset
, newkey
);
365 pcontactfound
= NULL
;
368 allocated_new
= true;
371 out_pcontact
= pcontactfound
;
372 return allocated_new
;
375 void FreeExistingContact(dContactGeom
*pcontact
,
376 int Flags
, CONTACT_KEY_HASH_TABLE
&hashcontactset
,
377 dContactGeom
*Contacts
, int Stride
, int &contactcount
)
379 CONTACT_KEY contactKey
;
380 UpdateContactKey(contactKey
, pcontact
);
382 RemoveArbitraryContactFromSet(hashcontactset
, contactKey
);
384 int lastContactIndex
= contactcount
- 1;
385 dContactGeom
*plastContact
= SAFECONTACT(Flags
, Contacts
, lastContactIndex
, Stride
);
387 if (pcontact
!= plastContact
)
389 *pcontact
= *plastContact
;
391 CONTACT_KEY lastContactKey
;
392 UpdateContactKey(lastContactKey
, plastContact
);
394 UpdateArbitraryContactInSet(hashcontactset
, lastContactKey
, pcontact
);
397 contactcount
= lastContactIndex
;
401 dContactGeom
* PushNewContact( dxGeom
* g1
, dxGeom
* g2
,
402 const dVector3 point
,
406 CONTACT_KEY_HASH_TABLE
&hashcontactset
,
407 dContactGeom
* Contacts
, int Stride
,
410 dIASSERT(dFabs(dVector3Length((const dVector3
&)(*normal
)) - REAL(1.0)) < REAL(1e-6)); // This assumption is used in the code
412 dContactGeom
* pcontact
;
414 if (!AllocNewContact(point
, pcontact
, Flags
, hashcontactset
, Contacts
, Stride
, contactcount
))
416 const dReal depthDifference
= depth
- pcontact
->depth
;
418 if (depthDifference
> CONTACT_DIFF_EPSILON
)
420 pcontact
->normal
[0] = normal
[0];
421 pcontact
->normal
[1] = normal
[1];
422 pcontact
->normal
[2] = normal
[2];
423 pcontact
->normal
[3] = REAL(1.0); // used to store length of vector sum for averaging
424 pcontact
->depth
= depth
;
429 else if (depthDifference
>= -CONTACT_DIFF_EPSILON
) ///average
431 if(pcontact
->g1
== g2
)
433 MULT(normal
,normal
, REAL(-1.0));
436 const dReal oldLen
= pcontact
->normal
[3];
437 COMBO(pcontact
->normal
, normal
, oldLen
, pcontact
->normal
);
439 const dReal len
= LENGTH(pcontact
->normal
);
440 if (len
> CONTACT_NORMAL_ZERO
)
442 MULT(pcontact
->normal
, pcontact
->normal
, REAL(1.0) / len
);
443 pcontact
->normal
[3] = len
;
447 FreeExistingContact(pcontact
, Flags
, hashcontactset
, Contacts
, Stride
, contactcount
);
451 // Contact can be not available if buffer is full
454 pcontact
->normal
[0] = normal
[0];
455 pcontact
->normal
[1] = normal
[1];
456 pcontact
->normal
[2] = normal
[2];
457 pcontact
->normal
[3] = REAL(1.0); // used to store length of vector sum for averaging
458 pcontact
->depth
= depth
;
466 ////////////////////////////////////////////////////////////////////////////////////////////
473 dCollideTTL(dxGeom
* g1
, dxGeom
* g2
, int Flags
, dContactGeom
* Contacts
, int Stride
)
475 dIASSERT (Stride
>= (int)sizeof(dContactGeom
));
476 dIASSERT (g1
->type
== dTriMeshClass
);
477 dIASSERT (g2
->type
== dTriMeshClass
);
478 dIASSERT ((Flags
& NUMC_MASK
) >= 1);
480 dxTriMesh
* TriMesh1
= (dxTriMesh
*) g1
;
481 dxTriMesh
* TriMesh2
= (dxTriMesh
*) g2
;
483 dReal
* TriNormals1
= (dReal
*) TriMesh1
->Data
->Normals
;
484 dReal
* TriNormals2
= (dReal
*) TriMesh2
->Data
->Normals
;
486 const dVector3
& TLPosition1
= *(const dVector3
*) dGeomGetPosition(TriMesh1
);
487 // TLRotation1 = column-major order
488 const dMatrix3
& TLRotation1
= *(const dMatrix3
*) dGeomGetRotation(TriMesh1
);
490 const dVector3
& TLPosition2
= *(const dVector3
*) dGeomGetPosition(TriMesh2
);
491 // TLRotation2 = column-major order
492 const dMatrix3
& TLRotation2
= *(const dMatrix3
*) dGeomGetRotation(TriMesh2
);
494 TrimeshCollidersCache
*pccColliderCache
= GetTrimeshCollidersCache();
495 AABBTreeCollider
& Collider
= pccColliderCache
->_AABBTreeCollider
;
496 BVTCache
&ColCache
= pccColliderCache
->ColCache
;
497 CONTACT_KEY_HASH_TABLE
&hashcontactset
= pccColliderCache
->_hashcontactset
;
499 ColCache
.Model0
= &TriMesh1
->Data
->BVTree
;
500 ColCache
.Model1
= &TriMesh2
->Data
->BVTree
;
502 ////Prepare contact list
503 ClearContactSet(hashcontactset
);
506 Matrix4x4 amatrix
, bmatrix
;
507 BOOL IsOk
= Collider
.Collide(ColCache
,
508 &MakeMatrix(TLPosition1
, TLRotation1
, amatrix
),
509 &MakeMatrix(TLPosition2
, TLRotation2
, bmatrix
) );
512 // Make "double" versions of these matrices, if appropriate
514 dMakeMatrix4(TLPosition1
, TLRotation1
, A
);
515 dMakeMatrix4(TLPosition2
, TLRotation2
, B
);
521 // Get collision status => if true, objects overlap
522 if ( Collider
.GetContactStatus() ) {
523 // Number of colliding pairs and list of pairs
524 int TriCount
= Collider
.GetNbPairs();
525 const Pair
* CollidingPairs
= Collider
.GetPairs();
528 // step through the pairs, adding contacts
531 dVector3 v1
[3], v2
[3];
533 // only do these expensive inversions once
534 /*dMatrix4 InvMatrix1, InvMatrix2;
535 dInvertMatrix4(A, InvMatrix1);
536 dInvertMatrix4(B, InvMatrix2);*/
539 for (int i
= 0; i
< TriCount
; i
++)
541 id1
= CollidingPairs
[i
].id0
;
542 id2
= CollidingPairs
[i
].id1
;
544 // grab the colliding triangles
545 FetchTriangle((dxTriMesh
*) g1
, id1
, TLPosition1
, TLRotation1
, v1
);
546 FetchTriangle((dxTriMesh
*) g2
, id2
, TLPosition2
, TLRotation2
, v2
);
548 // Since we'll be doing matrix transformations, we need to
549 // make sure that all vertices have four elements
550 for (int j
=0; j
<3; j
++) {
555 TriTriContacts(v1
,v2
,
556 g1
, g2
, Flags
, hashcontactset
,
557 Contacts
,Stride
,OutTriCount
);
559 // Continue loop even after contacts are full
560 // as existing contacts' normals/depths might be updated
561 // Break only if contacts are not important
562 if ((OutTriCount
| CONTACTS_UNIMPORTANT
) == (Flags
& (NUMC_MASK
| CONTACTS_UNIMPORTANT
)))
568 // Return the number of contacts
576 // There was some kind of failure during the Collide call or
577 // there are no faces overlapping
584 GetTriangleGeometryCallback(udword triangleindex, VertexPointers& triangle, udword user_data)
588 FetchTriangle((dxTriMesh*) user_data, (int) triangleindex, Out);
590 for (int i = 0; i < 3; i++)
591 triangle.Vertex[i] = (const Point*) ((dReal*) Out[i]);
615 #define Binv11 Binv[0]
616 #define Binv12 Binv[1]
617 #define Binv13 Binv[2]
618 #define Binv14 Binv[3]
619 #define Binv21 Binv[4]
620 #define Binv22 Binv[5]
621 #define Binv23 Binv[6]
622 #define Binv24 Binv[7]
623 #define Binv31 Binv[8]
624 #define Binv32 Binv[9]
625 #define Binv33 Binv[10]
626 #define Binv34 Binv[11]
627 #define Binv41 Binv[12]
628 #define Binv42 Binv[13]
629 #define Binv43 Binv[14]
630 #define Binv44 Binv[15]
633 dMakeMatrix4(const dVector3 Position
, const dMatrix3 Rotation
, dMatrix4
&B
)
635 B11
= Rotation
[0]; B21
= Rotation
[1]; B31
= Rotation
[2]; B41
= Position
[0];
636 B12
= Rotation
[4]; B22
= Rotation
[5]; B32
= Rotation
[6]; B42
= Position
[1];
637 B13
= Rotation
[8]; B23
= Rotation
[9]; B33
= Rotation
[10]; B43
= Position
[2];
639 B14
= 0.0; B24
= 0.0; B34
= 0.0; B44
= 1.0;
644 dInvertMatrix4( dMatrix4
& B
, dMatrix4
& Binv
)
646 dReal det
= (B11
* B22
- B12
* B21
) * (B33
* B44
- B34
* B43
)
647 -(B11
* B23
- B13
* B21
) * (B32
* B44
- B34
* B42
)
648 +(B11
* B24
- B14
* B21
) * (B32
* B43
- B33
* B42
)
649 +(B12
* B23
- B13
* B22
) * (B31
* B44
- B34
* B41
)
650 -(B12
* B24
- B14
* B22
) * (B31
* B43
- B33
* B41
)
651 +(B13
* B24
- B14
* B23
) * (B31
* B42
- B32
* B41
);
653 dAASSERT (det
!= 0.0);
657 Binv11
= (dReal
) (det
* ((B22
* B33
) - (B23
* B32
)));
658 Binv12
= (dReal
) (det
* ((B32
* B13
) - (B33
* B12
)));
659 Binv13
= (dReal
) (det
* ((B12
* B23
) - (B13
* B22
)));
661 Binv21
= (dReal
) (det
* ((B23
* B31
) - (B21
* B33
)));
662 Binv22
= (dReal
) (det
* ((B33
* B11
) - (B31
* B13
)));
663 Binv23
= (dReal
) (det
* ((B13
* B21
) - (B11
* B23
)));
665 Binv31
= (dReal
) (det
* ((B21
* B32
) - (B22
* B31
)));
666 Binv32
= (dReal
) (det
* ((B31
* B12
) - (B32
* B11
)));
667 Binv33
= (dReal
) (det
* ((B11
* B22
) - (B12
* B21
)));
669 Binv41
= (dReal
) (det
* (B21
*(B33
*B42
- B32
*B43
) + B22
*(B31
*B43
- B33
*B41
) + B23
*(B32
*B41
- B31
*B42
)));
670 Binv42
= (dReal
) (det
* (B31
*(B13
*B42
- B12
*B43
) + B32
*(B11
*B43
- B13
*B41
) + B33
*(B12
*B41
- B11
*B42
)));
671 Binv43
= (dReal
) (det
* (B41
*(B13
*B22
- B12
*B23
) + B42
*(B11
*B23
- B13
*B21
) + B43
*(B12
*B21
- B11
*B22
)));
677 // Find the intersectiojn point between a coplanar line segement,
678 // defined by X1 and X2, and a ray defined by X3 and direction N.
680 // This forumla for this calculation is:
682 // Q = x1 + a -------------------
688 // x1 and x2 are the edges of the triangle, and x3 is CoplanarPt
689 // and x4 is (CoplanarPt - n)
691 IntersectLineSegmentRay(dVector3 x1
, dVector3 x2
, dVector3 x3
, dVector3 n
,
694 dVector3 a
, b
, c
, x4
;
696 ADD(x4
, x3
, n
); // x4 = x3 + n
698 SUB(a
, x2
, x1
); // a = x2 - x1
707 num
= dDOT(tmp1
, tmp2
);
708 denom
= LENGTH( tmp2
);
711 s
= num
/(denom
*denom
);
713 for (int i
=0; i
<3; i
++)
714 out_pt
[i
] = x1
[i
] + a
[i
]*s
;
716 // Test if this intersection is "behind" x3, w.r.t. n
718 if (dDOT(a
, n
) > 0.0)
721 // Test if this intersection point is outside the edge limits,
722 // if (dot( (out_pt-x1), (out_pt-x2) ) < 0) it's inside
734 void PlaneClipSegment( const dVector3 s1
, const dVector3 s2
,
735 const dVector3 N
, dReal C
, dVector3 clipped
)
740 dis2
= DOT(clipped
,N
);
741 MULT(clipped
,clipped
,-dis1
/dis2
);
742 ADD(clipped
,clipped
,s1
);
746 /* ClipConvexPolygonAgainstPlane - Clip a a convex polygon, described by
747 CONTACTS, with a plane (described by N and C distance from origin).
748 Note: the input vertices are assumed to be in invcounterclockwise order.
749 changed by Francisco Leon (http://gimpact.sourceforge.net) */
751 ClipConvexPolygonAgainstPlane( const dVector3 N
, dReal C
,
752 LineContactSet
& Contacts
)
754 int i
, vi
, prevclassif
=32000, classif
;
756 classif 0 : back, 1 : front
763 if(Contacts
.Count
==0)
767 for(i
=0;i
<=Contacts
.Count
;i
++)
769 vi
= i
%Contacts
.Count
;
771 d
= DOT(N
,Contacts
.Points
[vi
]) - C
;
773 if(d
>REAL(1.0e-8)) classif
= 1;
776 if(classif
== 0)//back
780 if(prevclassif
==1)///in front
786 PlaneClipSegment(Contacts
.Points
[i
-1],Contacts
.Points
[vi
],
787 N
,C
,clipped
[clippedcount
]);
793 if(clippedcount
<8&&i
<Contacts
.Count
)
795 clipped
[clippedcount
][0] = Contacts
.Points
[vi
][0];
796 clipped
[clippedcount
][1] = Contacts
.Points
[vi
][1];
797 clipped
[clippedcount
][2] = Contacts
.Points
[vi
][2];
798 clipped
[clippedcount
][3] = 1.0f
;
812 PlaneClipSegment(Contacts
.Points
[i
-1],Contacts
.Points
[vi
],
813 N
,C
,clipped
[clippedcount
]);
820 prevclassif
= classif
;
828 Contacts
.Count
= clippedcount
;
829 memcpy( Contacts
.Points
, clipped
, clippedcount
* sizeof(dVector3
) );
834 bool BuildPlane(const dVector3 s0
, const dVector3 s1
,const dVector3 s2
,
835 dVector3 Normal
, dReal
& Dist
)
843 if (!dSafeNormalize3(Normal
))
848 Dist
= DOT(Normal
,s0
);
853 bool BuildEdgesDir(const dVector3 s0
, const dVector3 s1
,
854 const dVector3 t0
, const dVector3 t1
,
861 CROSS(crossdir
,e0
,e1
);
863 if (!dSafeNormalize3(crossdir
))
873 const dVector3 s0
, const dVector3 s1
,
874 const dVector3 normal
,
875 dVector3 plane_normal
,
881 CROSS(plane_normal
,e0
,normal
);
882 if (!dSafeNormalize3(plane_normal
))
886 plane_dist
= DOT(plane_normal
,s0
);
895 Negative number: they are separated
897 dReal
IntervalPenetration(dReal
&vmin1
,dReal
&vmax1
,
898 dReal
&vmin2
,dReal
&vmax2
)
902 return -(vmin2
-vmax1
);
908 return -(vmin1
-vmax2
);
925 const dVector3
* vertices
, int verticecount
,
926 dVector3 dir
,dReal
&vmin
,dReal
&vmax
)
931 vmin
= DOT(vertices
[0],dir
);
933 for(i
=1;i
<verticecount
;i
++)
935 dist
= DOT(vertices
[i
],dir
);
936 if(vmin
>dist
) vmin
=dist
;
937 else if(vmax
<dist
) vmax
=dist
;
941 ///returns the penetration depth
942 dReal
MostDeepPoints(
943 LineContactSet
& points
,
944 const dVector3 plane_normal
,
946 LineContactSet
& deep_points
)
949 int max_candidates
[8];
950 dReal maxdeep
=-dInfinity
;
953 deep_points
.Count
= 0;
954 for(i
=0;i
<points
.Count
;i
++)
956 dist
= DOT(plane_normal
,points
.Points
[i
]) - plane_dist
;
962 max_candidates
[deep_points
.Count
-1] = i
;
964 else if(dist
+REAL(0.000001)>=maxdeep
)
967 max_candidates
[deep_points
.Count
-1] = i
;
971 for(i
=0;i
<deep_points
.Count
;i
++)
973 SET(deep_points
.Points
[i
],points
.Points
[max_candidates
[i
]]);
979 void ClipPointsByTri(
980 const dVector3
* points
, int pointcount
,
981 const dVector3 tri
[3],
982 const dVector3 triplanenormal
,
984 LineContactSet
& clipped_points
,
987 ///build edges planes
991 clipped_points
.Count
= pointcount
;
992 memcpy(&clipped_points
.Points
[0],&points
[0],pointcount
*sizeof(dVector3
));
996 tri
[i
],tri
[(i
+1)%3],triplanenormal
,
999 ClipConvexPolygonAgainstPlane(
1008 ClipConvexPolygonAgainstPlane(
1016 ///returns the penetration depth
1017 dReal
FindTriangleTriangleCollision(
1018 const dVector3 tri1
[3],
1019 const dVector3 tri2
[3],
1020 dVector3 separating_normal
,
1021 LineContactSet
& deep_points
)
1023 dReal maxdeep
=dInfinity
;
1025 int mostdir
=0,mostface
= 0, currdir
=0;
1026 // dReal vmin1,vmax1,vmin2,vmax2;
1027 // dVector3 crossdir, pt1,pt2;
1028 dVector4 tri1plane
,tri2plane
;
1029 separating_normal
[3] = 0.0f
;
1031 LineContactSet clipped_points1
,clipped_points2
;
1032 LineContactSet deep_points1
,deep_points2
;
1033 // It is necessary to initialize the count because both conditional statements
1034 // might be skipped leading to uninitialized count being used for memcpy in if(mostdir==0)
1035 deep_points1
.Count
= 0;
1037 ////find interval face1
1039 bl
= BuildPlane(tri1
[0],tri1
[1],tri1
[2],
1040 tri1plane
,tri1plane
[3]);
1041 clipped_points1
.Count
= 0;
1050 clipped_points1
,false);
1054 maxdeep
= MostDeepPoints(
1059 SET(separating_normal
,tri1plane
);
1064 ////find interval face2
1066 bl
= BuildPlane(tri2
[0],tri2
[1],tri2
[2],
1067 tri2plane
,tri2plane
[3]);
1070 clipped_points2
.Count
= 0;
1078 clipped_points2
,false);
1082 dist
= MostDeepPoints(
1095 SET(separating_normal
,tri2plane
);
1101 ///find edge edge distances
1102 ///test each edge plane
1113 tri1[i],tri1[(i+1)%3],
1114 tri2[j],tri2[(j+1)%3],
1117 ////find plane distance
1121 FindInterval(tri1,3,crossdir,vmin1,vmax1);
1122 FindInterval(tri2,3,crossdir,vmin2,vmax2);
1124 dist = IntervalPenetration(
1133 SET(separating_normal,crossdir);
1141 ////check most dir for contacts
1144 ///find most deep points
1145 deep_points
.Count
= deep_points1
.Count
;
1147 &deep_points
.Points
[0],
1148 &deep_points1
.Points
[0],
1149 deep_points1
.Count
*sizeof(dVector3
));
1151 ///invert normal for point to tri1
1152 MULT(separating_normal
,separating_normal
,-1.0f
);
1156 deep_points
.Count
= deep_points2
.Count
;
1158 &deep_points
.Points
[0],
1159 &deep_points2
.Points
[0],
1160 deep_points2
.Count
*sizeof(dVector3
));
1172 ///find edge closest points
1173 dClosestLineSegmentPoints(
1174 tri1[i],tri1[(i+1)%3],
1175 tri2[j],tri2[(j+1)%3],
1177 ///find correct direction
1179 SUB(crossdir,pt2,pt1);
1181 vmin1 = LENGTH(crossdir);
1182 if(vmin1<REAL(0.000001))
1187 vmin1 = DOT(separating_normal,tri1plane);
1190 MULT(separating_normal,separating_normal,-1.0f);
1191 deep_points.Count = 1;
1192 SET(deep_points.Points[0],pt2);
1196 deep_points.Count = 1;
1197 SET(deep_points.Points[0],pt2);
1203 vmin1 = DOT(separating_normal,tri2plane);
1206 MULT(separating_normal,separating_normal,-1.0f);
1207 deep_points.Count = 1;
1208 SET(deep_points.Points[0],pt2);
1212 deep_points.Count = 1;
1213 SET(deep_points.Points[0],pt2);
1224 MULT(separating_normal,crossdir,1.0f/vmin1);
1226 vmin1 = DOT(separating_normal,tri1plane);
1229 MULT(separating_normal,separating_normal,-1.0f);
1230 deep_points.Count = 1;
1231 SET(deep_points.Points[0],pt2);
1235 deep_points.Count = 1;
1236 SET(deep_points.Points[0],pt2);
1249 ///SUPPORT UP TO 8 CONTACTS
1250 bool TriTriContacts(const dVector3 tr1
[3],
1251 const dVector3 tr2
[3],
1252 dxGeom
* g1
, dxGeom
* g2
, int Flags
,
1253 CONTACT_KEY_HASH_TABLE
&hashcontactset
,
1254 dContactGeom
* Contacts
, int Stride
,
1262 // dContactGeom* pcontact;
1264 LineContactSet contactpoints
;
1265 contactpoints
.Count
= 0;
1269 ///find best direction
1271 depth
= FindTriangleTriangleCollision(
1279 if(depth
<0.0f
) return false;
1282 while (ccount
<contactpoints
.Count
)
1284 PushNewContact( g1
, g2
,
1285 contactpoints
.Points
[ccount
],
1286 normal
, depth
, Flags
, hashcontactset
,
1287 Contacts
,Stride
,contactcount
);
1289 // Continue loop even after contacts are full
1290 // as existing contacts' normals/depths might be updated
1291 // Break only if contacts are not important
1292 if ((contactcount
| CONTACTS_UNIMPORTANT
) == (Flags
& (NUMC_MASK
| CONTACTS_UNIMPORTANT
)))
1302 #endif // dTRIMESH_OPCODE
1303 #endif // dTRIMESH_USE_NEW_TRIMESH_TRIMESH_COLLIDER
1304 #endif // dTRIMESH_ENABLED