diff options
Diffstat (limited to '')
-rw-r--r-- | libraries/ode-0.9/ode/src/collision_trimesh_trimesh.cpp | 2033 |
1 files changed, 0 insertions, 2033 deletions
diff --git a/libraries/ode-0.9/ode/src/collision_trimesh_trimesh.cpp b/libraries/ode-0.9/ode/src/collision_trimesh_trimesh.cpp deleted file mode 100644 index c9f209e..0000000 --- a/libraries/ode-0.9/ode/src/collision_trimesh_trimesh.cpp +++ /dev/null | |||
@@ -1,2033 +0,0 @@ | |||
1 | /************************************************************************* | ||
2 | * * | ||
3 | * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. * | ||
4 | * All rights reserved. Email: russ@q12.org Web: www.q12.org * | ||
5 | * * | ||
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 * | ||
12 | * file LICENSE.TXT. * | ||
13 | * (2) The BSD-style license that is included with this library in * | ||
14 | * the file LICENSE-BSD.TXT. * | ||
15 | * * | ||
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. * | ||
20 | * * | ||
21 | *************************************************************************/ | ||
22 | |||
23 | // OPCODE TriMesh/TriMesh collision code by Jeff Smith (c) 2004 | ||
24 | |||
25 | #ifdef _MSC_VER | ||
26 | #pragma warning(disable:4244 4305) // for VC++, no precision loss complaints | ||
27 | #endif | ||
28 | |||
29 | #include <ode/collision.h> | ||
30 | #include <ode/matrix.h> | ||
31 | #include <ode/rotation.h> | ||
32 | #include <ode/odemath.h> | ||
33 | |||
34 | // Classic Implementation | ||
35 | #if !dTRIMESH_OPCODE_USE_NEW_TRIMESH_TRIMESH_COLLIDER | ||
36 | |||
37 | #if dTRIMESH_ENABLED | ||
38 | |||
39 | #include "collision_util.h" | ||
40 | #define TRIMESH_INTERNAL | ||
41 | #include "collision_trimesh_internal.h" | ||
42 | |||
43 | #if dTRIMESH_OPCODE | ||
44 | |||
45 | #define SMALL_ELT REAL(2.5e-4) | ||
46 | #define EXPANDED_ELT_THRESH REAL(1.0e-3) | ||
47 | #define DISTANCE_EPSILON REAL(1.0e-8) | ||
48 | #define VELOCITY_EPSILON REAL(1.0e-5) | ||
49 | #define TINY_PENETRATION REAL(5.0e-6) | ||
50 | |||
51 | struct LineContactSet | ||
52 | { | ||
53 | enum | ||
54 | { | ||
55 | MAX_POINTS = 8 | ||
56 | }; | ||
57 | |||
58 | dVector3 Points[MAX_POINTS]; | ||
59 | int Count; | ||
60 | }; | ||
61 | |||
62 | |||
63 | static void GetTriangleGeometryCallback(udword, VertexPointers&, udword); | ||
64 | static void GenerateContact(int, dContactGeom*, int, dxTriMesh*, dxTriMesh*, | ||
65 | const dVector3, const dVector3, dReal, int&); | ||
66 | static int TriTriIntersectWithIsectLine(dReal V0[3],dReal V1[3],dReal V2[3], | ||
67 | dReal U0[3],dReal U1[3],dReal U2[3],int *coplanar, | ||
68 | dReal isectpt1[3],dReal isectpt2[3]); | ||
69 | inline void dMakeMatrix4(const dVector3 Position, const dMatrix3 Rotation, dMatrix4 &B); | ||
70 | static void dInvertMatrix4( dMatrix4& B, dMatrix4& Binv ); | ||
71 | static int IntersectLineSegmentRay(dVector3, dVector3, dVector3, dVector3, dVector3); | ||
72 | static bool FindTriSolidIntrsection(const dVector3 Tri[3], | ||
73 | const dVector4 Planes[6], int numSides, | ||
74 | LineContactSet& ClippedPolygon ); | ||
75 | static void ClipConvexPolygonAgainstPlane( const dVector3, dReal, LineContactSet& ); | ||
76 | static bool SimpleUnclippedTest(dVector3 in_CoplanarPt, dVector3 in_v, dVector3 in_elt, | ||
77 | dVector3 in_n, dVector3* in_col_v, dReal &out_depth); | ||
78 | static int ExamineContactPoint(dVector3* v_col, dVector3 in_n, dVector3 in_point); | ||
79 | static int RayTriangleIntersect(const dVector3 orig, const dVector3 dir, | ||
80 | const dVector3 vert0, const dVector3 vert1,const dVector3 vert2, | ||
81 | dReal *t,dReal *u,dReal *v); | ||
82 | |||
83 | |||
84 | |||
85 | |||
86 | /* some math macros */ | ||
87 | #define CROSS(dest,v1,v2) { dest[0]=v1[1]*v2[2]-v1[2]*v2[1]; \ | ||
88 | dest[1]=v1[2]*v2[0]-v1[0]*v2[2]; \ | ||
89 | dest[2]=v1[0]*v2[1]-v1[1]*v2[0]; } | ||
90 | |||
91 | #define DOT(v1,v2) (v1[0]*v2[0]+v1[1]*v2[1]+v1[2]*v2[2]) | ||
92 | |||
93 | #define SUB(dest,v1,v2) { dest[0]=v1[0]-v2[0]; dest[1]=v1[1]-v2[1]; dest[2]=v1[2]-v2[2]; } | ||
94 | |||
95 | #define ADD(dest,v1,v2) { dest[0]=v1[0]+v2[0]; dest[1]=v1[1]+v2[1]; dest[2]=v1[2]+v2[2]; } | ||
96 | |||
97 | #define MULT(dest,v,factor) { dest[0]=factor*v[0]; dest[1]=factor*v[1]; dest[2]=factor*v[2]; } | ||
98 | |||
99 | #define SET(dest,src) { dest[0]=src[0]; dest[1]=src[1]; dest[2]=src[2]; } | ||
100 | |||
101 | #define SMULT(p,q,s) { p[0]=q[0]*s; p[1]=q[1]*s; p[2]=q[2]*s; } | ||
102 | |||
103 | #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]; } | ||
104 | |||
105 | #define LENGTH(x) ((dReal) dSqrt(dDOT(x, x))) | ||
106 | |||
107 | #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]; | ||
108 | |||
109 | inline const dReal dMin(const dReal x, const dReal y) | ||
110 | { | ||
111 | return x < y ? x : y; | ||
112 | } | ||
113 | |||
114 | |||
115 | inline void | ||
116 | SwapNormals(dVector3 *&pen_v, dVector3 *&col_v, dVector3* v1, dVector3* v2, | ||
117 | dVector3 *&pen_elt, dVector3 *elt_f1, dVector3 *elt_f2, | ||
118 | dVector3 n, dVector3 n1, dVector3 n2) | ||
119 | { | ||
120 | if (pen_v == v1) { | ||
121 | pen_v = v2; | ||
122 | pen_elt = elt_f2; | ||
123 | col_v = v1; | ||
124 | SET(n, n1); | ||
125 | } | ||
126 | else { | ||
127 | pen_v = v1; | ||
128 | pen_elt = elt_f1; | ||
129 | col_v = v2; | ||
130 | SET(n, n2); | ||
131 | } | ||
132 | } | ||
133 | |||
134 | |||
135 | |||
136 | |||
137 | int | ||
138 | dCollideTTL(dxGeom* g1, dxGeom* g2, int Flags, dContactGeom* Contacts, int Stride) | ||
139 | { | ||
140 | dIASSERT (Stride >= (int)sizeof(dContactGeom)); | ||
141 | dIASSERT (g1->type == dTriMeshClass); | ||
142 | dIASSERT (g2->type == dTriMeshClass); | ||
143 | dIASSERT ((Flags & NUMC_MASK) >= 1); | ||
144 | |||
145 | dxTriMesh* TriMesh1 = (dxTriMesh*) g1; | ||
146 | dxTriMesh* TriMesh2 = (dxTriMesh*) g2; | ||
147 | |||
148 | dReal * TriNormals1 = (dReal *) TriMesh1->Data->Normals; | ||
149 | dReal * TriNormals2 = (dReal *) TriMesh2->Data->Normals; | ||
150 | |||
151 | const dVector3& TLPosition1 = *(const dVector3*) dGeomGetPosition(TriMesh1); | ||
152 | // TLRotation1 = column-major order | ||
153 | const dMatrix3& TLRotation1 = *(const dMatrix3*) dGeomGetRotation(TriMesh1); | ||
154 | |||
155 | const dVector3& TLPosition2 = *(const dVector3*) dGeomGetPosition(TriMesh2); | ||
156 | // TLRotation2 = column-major order | ||
157 | const dMatrix3& TLRotation2 = *(const dMatrix3*) dGeomGetRotation(TriMesh2); | ||
158 | |||
159 | AABBTreeCollider& Collider = TriMesh1->_AABBTreeCollider; | ||
160 | |||
161 | static BVTCache ColCache; | ||
162 | ColCache.Model0 = &TriMesh1->Data->BVTree; | ||
163 | ColCache.Model1 = &TriMesh2->Data->BVTree; | ||
164 | |||
165 | // Collision query | ||
166 | Matrix4x4 amatrix, bmatrix; | ||
167 | BOOL IsOk = Collider.Collide(ColCache, | ||
168 | &MakeMatrix(TLPosition1, TLRotation1, amatrix), | ||
169 | &MakeMatrix(TLPosition2, TLRotation2, bmatrix) ); | ||
170 | |||
171 | |||
172 | // Make "double" versions of these matrices, if appropriate | ||
173 | dMatrix4 A, B; | ||
174 | dMakeMatrix4(TLPosition1, TLRotation1, A); | ||
175 | dMakeMatrix4(TLPosition2, TLRotation2, B); | ||
176 | |||
177 | |||
178 | if (IsOk) { | ||
179 | // Get collision status => if true, objects overlap | ||
180 | if ( Collider.GetContactStatus() ) { | ||
181 | // Number of colliding pairs and list of pairs | ||
182 | int TriCount = Collider.GetNbPairs(); | ||
183 | const Pair* CollidingPairs = Collider.GetPairs(); | ||
184 | |||
185 | if (TriCount > 0) { | ||
186 | // step through the pairs, adding contacts | ||
187 | int id1, id2; | ||
188 | int OutTriCount = 0; | ||
189 | dVector3 v1[3], v2[3], CoplanarPt; | ||
190 | dVector3 e1, e2, e3, n1, n2, n, ContactNormal; | ||
191 | dReal depth; | ||
192 | dVector3 orig_pos, old_pos1, old_pos2, elt1, elt2, elt_sum; | ||
193 | dVector3 elt_f1[3], elt_f2[3]; | ||
194 | dReal contact_elt_length = SMALL_ELT; | ||
195 | LineContactSet firstClippedTri, secondClippedTri; | ||
196 | dVector3 *firstClippedElt = new dVector3[LineContactSet::MAX_POINTS]; | ||
197 | dVector3 *secondClippedElt = new dVector3[LineContactSet::MAX_POINTS]; | ||
198 | |||
199 | |||
200 | // only do these expensive inversions once | ||
201 | dMatrix4 InvMatrix1, InvMatrix2; | ||
202 | dInvertMatrix4(A, InvMatrix1); | ||
203 | dInvertMatrix4(B, InvMatrix2); | ||
204 | |||
205 | |||
206 | for (int i = 0; i < TriCount; i++) { | ||
207 | |||
208 | id1 = CollidingPairs[i].id0; | ||
209 | id2 = CollidingPairs[i].id1; | ||
210 | |||
211 | // grab the colliding triangles | ||
212 | FetchTriangle((dxTriMesh*) g1, id1, TLPosition1, TLRotation1, v1); | ||
213 | FetchTriangle((dxTriMesh*) g2, id2, TLPosition2, TLRotation2, v2); | ||
214 | // Since we'll be doing matrix transfomrations, we need to | ||
215 | // make sure that all vertices have four elements | ||
216 | for (int j=0; j<3; j++) { | ||
217 | v1[j][3] = 1.0; | ||
218 | v2[j][3] = 1.0; | ||
219 | } | ||
220 | |||
221 | |||
222 | int IsCoplanar = 0; | ||
223 | dReal IsectPt1[3], IsectPt2[3]; | ||
224 | |||
225 | // Sometimes OPCODE makes mistakes, so we look at the return | ||
226 | // value for TriTriIntersectWithIsectLine. A retcode of "0" | ||
227 | // means no intersection took place | ||
228 | if ( TriTriIntersectWithIsectLine( v1[0], v1[1], v1[2], v2[0], v2[1], v2[2], | ||
229 | &IsCoplanar, | ||
230 | IsectPt1, IsectPt2) ) { | ||
231 | |||
232 | // Compute the normals of the colliding faces | ||
233 | // | ||
234 | if (TriNormals1 == NULL) { | ||
235 | SUB( e1, v1[1], v1[0] ); | ||
236 | SUB( e2, v1[2], v1[0] ); | ||
237 | CROSS( n1, e1, e2 ); | ||
238 | dNormalize3(n1); | ||
239 | } | ||
240 | else { | ||
241 | // If we were passed normals, we need to adjust them to take into | ||
242 | // account the objects' current rotations | ||
243 | e1[0] = TriNormals1[id1*3]; | ||
244 | e1[1] = TriNormals1[id1*3 + 1]; | ||
245 | e1[2] = TriNormals1[id1*3 + 2]; | ||
246 | e1[3] = 0.0; | ||
247 | |||
248 | //dMultiply1(n1, TLRotation1, e1, 3, 3, 1); | ||
249 | dMultiply0(n1, TLRotation1, e1, 3, 3, 1); | ||
250 | n1[3] = 1.0; | ||
251 | } | ||
252 | |||
253 | if (TriNormals2 == NULL) { | ||
254 | SUB( e1, v2[1], v2[0] ); | ||
255 | SUB( e2, v2[2], v2[0] ); | ||
256 | CROSS( n2, e1, e2); | ||
257 | dNormalize3(n2); | ||
258 | } | ||
259 | else { | ||
260 | // If we were passed normals, we need to adjust them to take into | ||
261 | // account the objects' current rotations | ||
262 | e2[0] = TriNormals2[id2*3]; | ||
263 | e2[1] = TriNormals2[id2*3 + 1]; | ||
264 | e2[2] = TriNormals2[id2*3 + 2]; | ||
265 | e2[3] = 0.0; | ||
266 | |||
267 | //dMultiply1(n2, TLRotation2, e2, 3, 3, 1); | ||
268 | dMultiply0(n2, TLRotation2, e2, 3, 3, 1); | ||
269 | n2[3] = 1.0; | ||
270 | } | ||
271 | |||
272 | |||
273 | if (IsCoplanar) { | ||
274 | // We can reach this case if the faces are coplanar, OR | ||
275 | // if they don't actually intersect. (OPCODE can make | ||
276 | // mistakes) | ||
277 | if (dFabs(dDOT(n1, n2)) > REAL(0.999)) { | ||
278 | // If the faces are coplanar, we declare that the point of | ||
279 | // contact is at the average location of the vertices of | ||
280 | // both faces | ||
281 | dVector3 ContactPt; | ||
282 | for (int j=0; j<3; j++) { | ||
283 | ContactPt[j] = 0.0; | ||
284 | for (int k=0; k<3; k++) | ||
285 | ContactPt[j] += v1[k][j] + v2[k][j]; | ||
286 | ContactPt[j] /= 6.0; | ||
287 | } | ||
288 | ContactPt[3] = 1.0; | ||
289 | |||
290 | // and the contact normal is the normal of face 2 | ||
291 | // (could be face 1, because they are the same) | ||
292 | SET(n, n2); | ||
293 | |||
294 | // and the penetration depth is the co-normal | ||
295 | // distance between any two vertices A and B, | ||
296 | // i.e. d = DOT(n, (A-B)) | ||
297 | DEPTH(depth, v1[1], v2[1], n); | ||
298 | if (depth < 0) | ||
299 | depth *= -1.0; | ||
300 | |||
301 | GenerateContact(Flags, Contacts, Stride, TriMesh1, TriMesh2, | ||
302 | ContactPt, n, depth, OutTriCount); | ||
303 | } | ||
304 | } | ||
305 | else { | ||
306 | // Otherwise (in non-co-planar cases), we create a coplanar | ||
307 | // point -- the middle of the line of intersection -- that | ||
308 | // will be used for various computations down the road | ||
309 | for (int j=0; j<3; j++) | ||
310 | CoplanarPt[j] = ( (IsectPt1[j] + IsectPt2[j]) / REAL(2.0) ); | ||
311 | CoplanarPt[3] = 1.0; | ||
312 | |||
313 | // Find the ELT of the coplanar point | ||
314 | // | ||
315 | dMultiply1(orig_pos, InvMatrix1, CoplanarPt, 4, 4, 1); | ||
316 | dMultiply1(old_pos1, ((dxTriMesh*)g1)->last_trans, orig_pos, 4, 4, 1); | ||
317 | SUB(elt1, CoplanarPt, old_pos1); | ||
318 | |||
319 | dMultiply1(orig_pos, InvMatrix2, CoplanarPt, 4, 4, 1); | ||
320 | dMultiply1(old_pos2, ((dxTriMesh*)g2)->last_trans, orig_pos, 4, 4, 1); | ||
321 | SUB(elt2, CoplanarPt, old_pos2); | ||
322 | |||
323 | SUB(elt_sum, elt1, elt2); // net motion of the coplanar point | ||
324 | |||
325 | |||
326 | // Calculate how much the vertices of each face moved in the | ||
327 | // direction of the opposite face's normal | ||
328 | // | ||
329 | dReal total_dp1, total_dp2; | ||
330 | total_dp1 = 0.0; | ||
331 | total_dp2 = 0.0; | ||
332 | |||
333 | for (int ii=0; ii<3; ii++) { | ||
334 | // find the estimated linear translation (ELT) of the vertices | ||
335 | // on face 1, wrt to the center of face 2. | ||
336 | |||
337 | // un-transform this vertex by the current transform | ||
338 | dMultiply1(orig_pos, InvMatrix1, v1[ii], 4, 4, 1 ); | ||
339 | |||
340 | // re-transform this vertex by last_trans (to get its old | ||
341 | // position) | ||
342 | dMultiply1(old_pos1, ((dxTriMesh*)g1)->last_trans, orig_pos, 4, 4, 1); | ||
343 | |||
344 | // Then subtract this position from our current one to find | ||
345 | // the elapsed linear translation (ELT) | ||
346 | for (int k=0; k<3; k++) { | ||
347 | elt_f1[ii][k] = (v1[ii][k] - old_pos1[k]) - elt2[k]; | ||
348 | } | ||
349 | |||
350 | // Take the dot product of the ELT for each vertex (wrt the | ||
351 | // center of face2) | ||
352 | total_dp1 += dFabs( dDOT(elt_f1[ii], n2) ); | ||
353 | } | ||
354 | |||
355 | for (int ii=0; ii<3; ii++) { | ||
356 | // find the estimated linear translation (ELT) of the vertices | ||
357 | // on face 2, wrt to the center of face 1. | ||
358 | dMultiply1(orig_pos, InvMatrix2, v2[ii], 4, 4, 1); | ||
359 | dMultiply1(old_pos2, ((dxTriMesh*)g2)->last_trans, orig_pos, 4, 4, 1); | ||
360 | for (int k=0; k<3; k++) { | ||
361 | elt_f2[ii][k] = (v2[ii][k] - old_pos2[k]) - elt1[k]; | ||
362 | } | ||
363 | |||
364 | // Take the dot product of the ELT for each vertex (wrt the | ||
365 | // center of face2) and add them | ||
366 | total_dp2 += dFabs( dDOT(elt_f2[ii], n1) ); | ||
367 | } | ||
368 | |||
369 | |||
370 | //////// | ||
371 | // Estimate the penetration depth. | ||
372 | // | ||
373 | dReal dp; | ||
374 | BOOL badPen = true; | ||
375 | dVector3 *pen_v; // the "penetrating vertices" | ||
376 | dVector3 *pen_elt; // the elt_f of the penetrating face | ||
377 | dVector3 *col_v; // the "collision vertices" (the penetrated face) | ||
378 | |||
379 | SMULT(n2, n2, -1.0); // SF PATCH #1335183 | ||
380 | depth = 0.0; | ||
381 | if ((total_dp1 > DISTANCE_EPSILON) || (total_dp2 > DISTANCE_EPSILON)) { | ||
382 | //////// | ||
383 | // Find the collision normal, by finding the face | ||
384 | // that is pointed "most" in the direction of travel | ||
385 | // of the two triangles | ||
386 | // | ||
387 | if (total_dp2 > total_dp1) { | ||
388 | pen_v = v2; | ||
389 | pen_elt = elt_f2; | ||
390 | col_v = v1; | ||
391 | SET(n, n1); | ||
392 | } | ||
393 | else { | ||
394 | pen_v = v1; | ||
395 | pen_elt = elt_f1; | ||
396 | col_v = v2; | ||
397 | SET(n, n2); | ||
398 | } | ||
399 | } | ||
400 | else { | ||
401 | // the total_dp is very small, so let's fall back | ||
402 | // to a different test | ||
403 | if (LENGTH(elt2) > LENGTH(elt1)) { | ||
404 | pen_v = v2; | ||
405 | pen_elt = elt_f2; | ||
406 | col_v = v1; | ||
407 | SET(n, n1); | ||
408 | } | ||
409 | else { | ||
410 | pen_v = v1; | ||
411 | pen_elt = elt_f1; | ||
412 | col_v = v2; | ||
413 | SET(n, n2); | ||
414 | } | ||
415 | } | ||
416 | |||
417 | |||
418 | for (int j=0; j<3; j++) | ||
419 | if (SimpleUnclippedTest(CoplanarPt, pen_v[j], pen_elt[j], n, col_v, depth)) { | ||
420 | GenerateContact(Flags, Contacts, Stride, TriMesh1, TriMesh2, | ||
421 | pen_v[j], n, depth, OutTriCount); | ||
422 | badPen = false; | ||
423 | |||
424 | if ((OutTriCount | CONTACTS_UNIMPORTANT) == (Flags & (NUMC_MASK | CONTACTS_UNIMPORTANT))) { | ||
425 | break; | ||
426 | } | ||
427 | } | ||
428 | |||
429 | |||
430 | if (badPen) { | ||
431 | // try the other normal | ||
432 | SwapNormals(pen_v, col_v, v1, v2, pen_elt, elt_f1, elt_f2, n, n1, n2); | ||
433 | |||
434 | for (int j=0; j<3; j++) | ||
435 | if (SimpleUnclippedTest(CoplanarPt, pen_v[j], pen_elt[j], n, col_v, depth)) { | ||
436 | GenerateContact(Flags, Contacts, Stride, TriMesh1, TriMesh2, | ||
437 | pen_v[j], n, depth, OutTriCount); | ||
438 | badPen = false; | ||
439 | |||
440 | if ((OutTriCount | CONTACTS_UNIMPORTANT) == (Flags & (NUMC_MASK | CONTACTS_UNIMPORTANT))) { | ||
441 | break; | ||
442 | } | ||
443 | } | ||
444 | } | ||
445 | |||
446 | |||
447 | |||
448 | //////////////////////////////////////// | ||
449 | // | ||
450 | // If we haven't found a good penetration, then we're probably straddling | ||
451 | // the edge of one of the objects, or the penetraing face is big | ||
452 | // enough that all of its vertices are outside the bounds of the | ||
453 | // penetrated face. | ||
454 | // In these cases, we do a more expensive test. We clip the penetrating | ||
455 | // triangle with a solid defined by the penetrated triangle, and repeat | ||
456 | // the tests above on this new polygon | ||
457 | if (badPen) { | ||
458 | |||
459 | // Switch pen_v and n back again | ||
460 | SwapNormals(pen_v, col_v, v1, v2, pen_elt, elt_f1, elt_f2, n, n1, n2); | ||
461 | |||
462 | |||
463 | // Find the three sides (no top or bottom) of the solid defined by | ||
464 | // the edges of the penetrated triangle. | ||
465 | |||
466 | // The dVector4 "plane" structures contain the following information: | ||
467 | // [0]-[2]: The normal of the face, pointing INWARDS (i.e. | ||
468 | // the inverse normal | ||
469 | // [3]: The distance between the face and the center of the | ||
470 | // solid, along the normal | ||
471 | dVector4 SolidPlanes[3]; | ||
472 | dVector3 tmp1; | ||
473 | dVector3 sn; | ||
474 | |||
475 | for (int j=0; j<3; j++) { | ||
476 | e1[j] = col_v[1][j] - col_v[0][j]; | ||
477 | e2[j] = col_v[0][j] - col_v[2][j]; | ||
478 | e3[j] = col_v[2][j] - col_v[1][j]; | ||
479 | } | ||
480 | |||
481 | // side 1 | ||
482 | CROSS(sn, e1, n); | ||
483 | dNormalize3(sn); | ||
484 | SMULT( SolidPlanes[0], sn, -1.0 ); | ||
485 | |||
486 | ADD(tmp1, col_v[0], col_v[1]); | ||
487 | SMULT(tmp1, tmp1, 0.5); // center of edge | ||
488 | // distance from center to edge along normal | ||
489 | SolidPlanes[0][3] = dDOT(tmp1, SolidPlanes[0]); | ||
490 | |||
491 | |||
492 | // side 2 | ||
493 | CROSS(sn, e2, n); | ||
494 | dNormalize3(sn); | ||
495 | SMULT( SolidPlanes[1], sn, -1.0 ); | ||
496 | |||
497 | ADD(tmp1, col_v[0], col_v[2]); | ||
498 | SMULT(tmp1, tmp1, 0.5); // center of edge | ||
499 | // distance from center to edge along normal | ||
500 | SolidPlanes[1][3] = dDOT(tmp1, SolidPlanes[1]); | ||
501 | |||
502 | |||
503 | // side 3 | ||
504 | CROSS(sn, e3, n); | ||
505 | dNormalize3(sn); | ||
506 | SMULT( SolidPlanes[2], sn, -1.0 ); | ||
507 | |||
508 | ADD(tmp1, col_v[2], col_v[1]); | ||
509 | SMULT(tmp1, tmp1, 0.5); // center of edge | ||
510 | // distance from center to edge along normal | ||
511 | SolidPlanes[2][3] = dDOT(tmp1, SolidPlanes[2]); | ||
512 | |||
513 | |||
514 | FindTriSolidIntrsection(pen_v, SolidPlanes, 3, firstClippedTri); | ||
515 | |||
516 | for (int j=0; j<firstClippedTri.Count; j++) { | ||
517 | firstClippedTri.Points[j][3] = 1.0; // because we will be doing matrix mults | ||
518 | |||
519 | DEPTH(dp, CoplanarPt, firstClippedTri.Points[j], n); | ||
520 | |||
521 | // if the penetration depth (calculated above) is more than the contact | ||
522 | // point's ELT, then we've chosen the wrong face and should switch faces | ||
523 | if (pen_v == v1) { | ||
524 | dMultiply1(orig_pos, InvMatrix1, firstClippedTri.Points[j], 4, 4, 1); | ||
525 | dMultiply1(old_pos1, ((dxTriMesh*)g1)->last_trans, orig_pos, 4, 4, 1); | ||
526 | for (int k=0; k<3; k++) { | ||
527 | firstClippedElt[j][k] = (firstClippedTri.Points[j][k] - old_pos1[k]) - elt2[k]; | ||
528 | } | ||
529 | } | ||
530 | else { | ||
531 | dMultiply1(orig_pos, InvMatrix2, firstClippedTri.Points[j], 4, 4, 1); | ||
532 | dMultiply1(old_pos2, ((dxTriMesh*)g2)->last_trans, orig_pos, 4, 4, 1); | ||
533 | for (int k=0; k<3; k++) { | ||
534 | firstClippedElt[j][k] = (firstClippedTri.Points[j][k] - old_pos2[k]) - elt1[k]; | ||
535 | } | ||
536 | } | ||
537 | |||
538 | if (dp >= 0.0) { | ||
539 | contact_elt_length = dFabs(dDOT(firstClippedElt[j], n)); | ||
540 | |||
541 | depth = dp; | ||
542 | if (depth == 0.0) | ||
543 | depth = dMin(DISTANCE_EPSILON, contact_elt_length); | ||
544 | |||
545 | if ((contact_elt_length < SMALL_ELT) && (depth < EXPANDED_ELT_THRESH)) | ||
546 | depth = contact_elt_length; | ||
547 | |||
548 | if (depth <= contact_elt_length) { | ||
549 | // Add a contact | ||
550 | GenerateContact(Flags, Contacts, Stride, TriMesh1, TriMesh2, | ||
551 | firstClippedTri.Points[j], n, depth, OutTriCount); | ||
552 | badPen = false; | ||
553 | |||
554 | if ((OutTriCount | CONTACTS_UNIMPORTANT) == (Flags & (NUMC_MASK | CONTACTS_UNIMPORTANT))) { | ||
555 | break; | ||
556 | } | ||
557 | } | ||
558 | } | ||
559 | |||
560 | } | ||
561 | } | ||
562 | |||
563 | if (badPen) { | ||
564 | // Switch pen_v and n (again!) | ||
565 | SwapNormals(pen_v, col_v, v1, v2, pen_elt, elt_f1, elt_f2, n, n1, n2); | ||
566 | |||
567 | |||
568 | // Find the three sides (no top or bottom) of the solid created by | ||
569 | // the penetrated triangle. | ||
570 | // The dVector4 "plane" structures contain the following information: | ||
571 | // [0]-[2]: The normal of the face, pointing INWARDS (i.e. | ||
572 | // the inverse normal | ||
573 | // [3]: The distance between the face and the center of the | ||
574 | // solid, along the normal | ||
575 | dVector4 SolidPlanes[3]; | ||
576 | dVector3 tmp1; | ||
577 | |||
578 | dVector3 sn; | ||
579 | for (int j=0; j<3; j++) { | ||
580 | e1[j] = col_v[1][j] - col_v[0][j]; | ||
581 | e2[j] = col_v[0][j] - col_v[2][j]; | ||
582 | e3[j] = col_v[2][j] - col_v[1][j]; | ||
583 | } | ||
584 | |||
585 | // side 1 | ||
586 | CROSS(sn, e1, n); | ||
587 | dNormalize3(sn); | ||
588 | SMULT( SolidPlanes[0], sn, -1.0 ); | ||
589 | |||
590 | ADD(tmp1, col_v[0], col_v[1]); | ||
591 | SMULT(tmp1, tmp1, 0.5); // center of edge | ||
592 | // distance from center to edge along normal | ||
593 | SolidPlanes[0][3] = dDOT(tmp1, SolidPlanes[0]); | ||
594 | |||
595 | |||
596 | // side 2 | ||
597 | CROSS(sn, e2, n); | ||
598 | dNormalize3(sn); | ||
599 | SMULT( SolidPlanes[1], sn, -1.0 ); | ||
600 | |||
601 | ADD(tmp1, col_v[0], col_v[2]); | ||
602 | SMULT(tmp1, tmp1, 0.5); // center of edge | ||
603 | // distance from center to edge along normal | ||
604 | SolidPlanes[1][3] = dDOT(tmp1, SolidPlanes[1]); | ||
605 | |||
606 | |||
607 | // side 3 | ||
608 | CROSS(sn, e3, n); | ||
609 | dNormalize3(sn); | ||
610 | SMULT( SolidPlanes[2], sn, -1.0 ); | ||
611 | |||
612 | ADD(tmp1, col_v[2], col_v[1]); | ||
613 | SMULT(tmp1, tmp1, 0.5); // center of edge | ||
614 | // distance from center to edge along normal | ||
615 | SolidPlanes[2][3] = dDOT(tmp1, SolidPlanes[2]); | ||
616 | |||
617 | FindTriSolidIntrsection(pen_v, SolidPlanes, 3, secondClippedTri); | ||
618 | |||
619 | for (int j=0; j<secondClippedTri.Count; j++) { | ||
620 | secondClippedTri.Points[j][3] = 1.0; // because we will be doing matrix mults | ||
621 | |||
622 | DEPTH(dp, CoplanarPt, secondClippedTri.Points[j], n); | ||
623 | |||
624 | if (pen_v == v1) { | ||
625 | dMultiply1(orig_pos, InvMatrix1, secondClippedTri.Points[j], 4, 4, 1); | ||
626 | dMultiply1(old_pos1, ((dxTriMesh*)g1)->last_trans, orig_pos, 4, 4, 1); | ||
627 | for (int k=0; k<3; k++) { | ||
628 | secondClippedElt[j][k] = (secondClippedTri.Points[j][k] - old_pos1[k]) - elt2[k]; | ||
629 | } | ||
630 | } | ||
631 | else { | ||
632 | dMultiply1(orig_pos, InvMatrix2, secondClippedTri.Points[j], 4, 4, 1); | ||
633 | dMultiply1(old_pos2, ((dxTriMesh*)g2)->last_trans, orig_pos, 4, 4, 1); | ||
634 | for (int k=0; k<3; k++) { | ||
635 | secondClippedElt[j][k] = (secondClippedTri.Points[j][k] - old_pos2[k]) - elt1[k]; | ||
636 | } | ||
637 | } | ||
638 | |||
639 | |||
640 | if (dp >= 0.0) { | ||
641 | contact_elt_length = dFabs(dDOT(secondClippedElt[j],n)); | ||
642 | |||
643 | depth = dp; | ||
644 | if (depth == 0.0) | ||
645 | depth = dMin(DISTANCE_EPSILON, contact_elt_length); | ||
646 | |||
647 | if ((contact_elt_length < SMALL_ELT) && (depth < EXPANDED_ELT_THRESH)) | ||
648 | depth = contact_elt_length; | ||
649 | |||
650 | if (depth <= contact_elt_length) { | ||
651 | // Add a contact | ||
652 | GenerateContact(Flags, Contacts, Stride, TriMesh1, TriMesh2, | ||
653 | secondClippedTri.Points[j], n, depth, OutTriCount); | ||
654 | badPen = false; | ||
655 | |||
656 | if ((OutTriCount | CONTACTS_UNIMPORTANT) == (Flags & (NUMC_MASK | CONTACTS_UNIMPORTANT))) { | ||
657 | break; | ||
658 | } | ||
659 | } | ||
660 | } | ||
661 | |||
662 | |||
663 | } | ||
664 | } | ||
665 | |||
666 | |||
667 | |||
668 | ///////////////// | ||
669 | // All conventional tests have failed at this point, so now we deal with | ||
670 | // cases on a more "heuristic" basis | ||
671 | // | ||
672 | |||
673 | if (badPen) { | ||
674 | // Switch pen_v and n (for the fourth time, so they're | ||
675 | // what my original guess said they were) | ||
676 | SwapNormals(pen_v, col_v, v1, v2, pen_elt, elt_f1, elt_f2, n, n1, n2); | ||
677 | |||
678 | if (dFabs(dDOT(n1, n2)) < REAL(0.01)) { | ||
679 | // If we reach this point, we have (close to) perpindicular | ||
680 | // faces, either resting on each other or sliding in a | ||
681 | // direction orthogonal to both surface normals. | ||
682 | if (LENGTH(elt_sum) < DISTANCE_EPSILON) { | ||
683 | depth = dFabs(dDOT(n, elt_sum)); | ||
684 | |||
685 | if (depth > REAL(1e-12)) { | ||
686 | dNormalize3(n); | ||
687 | GenerateContact(Flags, Contacts, Stride, TriMesh1, TriMesh2, | ||
688 | CoplanarPt, n, depth, OutTriCount); | ||
689 | badPen = false; | ||
690 | } | ||
691 | else { | ||
692 | // If the two faces are (nearly) perfectly at rest with | ||
693 | // respect to each other, then we ignore the contact, | ||
694 | // allowing the objects to slip a little in the hopes | ||
695 | // that next frame, they'll give us something to work | ||
696 | // with. | ||
697 | badPen = false; | ||
698 | } | ||
699 | } | ||
700 | else { | ||
701 | // The faces are perpindicular, but moving significantly | ||
702 | // This can be sliding, or an unusual edge-straddling | ||
703 | // penetration. | ||
704 | dVector3 cn; | ||
705 | |||
706 | CROSS(cn, n1, n2); | ||
707 | dNormalize3(cn); | ||
708 | SET(n, cn); | ||
709 | |||
710 | // The shallowest ineterpenetration of the faces | ||
711 | // is the depth | ||
712 | dVector3 ContactPt; | ||
713 | dVector3 dvTmp; | ||
714 | dReal rTmp; | ||
715 | depth = dInfinity; | ||
716 | for (int j=0; j<3; j++) { | ||
717 | for (int k=0; k<3; k++) { | ||
718 | SUB(dvTmp, col_v[k], pen_v[j]); | ||
719 | |||
720 | rTmp = dDOT(dvTmp, n); | ||
721 | if ( dFabs(rTmp) < dFabs(depth) ) { | ||
722 | depth = rTmp; | ||
723 | SET( ContactPt, pen_v[j] ); | ||
724 | contact_elt_length = dFabs(dDOT(pen_elt[j], n)); | ||
725 | } | ||
726 | } | ||
727 | } | ||
728 | if (depth < 0.0) { | ||
729 | SMULT(n, n, -1.0); | ||
730 | depth *= -1.0; | ||
731 | } | ||
732 | |||
733 | if ((depth > 0.0) && (depth <= contact_elt_length)) { | ||
734 | GenerateContact(Flags, Contacts, Stride, TriMesh1, TriMesh2, | ||
735 | ContactPt, n, depth, OutTriCount); | ||
736 | badPen = false; | ||
737 | } | ||
738 | |||
739 | } | ||
740 | } | ||
741 | } | ||
742 | |||
743 | |||
744 | if (badPen) { | ||
745 | // Use as the normal the direction of travel, rather than any particular | ||
746 | // face normal | ||
747 | // | ||
748 | dVector3 esn; | ||
749 | |||
750 | if (pen_v == v1) { | ||
751 | SMULT(esn, elt_sum, -1.0); | ||
752 | } | ||
753 | else { | ||
754 | SET(esn, elt_sum); | ||
755 | } | ||
756 | dNormalize3(esn); | ||
757 | |||
758 | |||
759 | // The shallowest ineterpenetration of the faces | ||
760 | // is the depth | ||
761 | dVector3 ContactPt; | ||
762 | depth = dInfinity; | ||
763 | for (int j=0; j<3; j++) { | ||
764 | for (int k=0; k<3; k++) { | ||
765 | DEPTH(dp, col_v[k], pen_v[j], esn); | ||
766 | if ( (ExamineContactPoint(col_v, esn, pen_v[j])) && | ||
767 | ( dFabs(dp) < dFabs(depth)) ) { | ||
768 | depth = dp; | ||
769 | SET( ContactPt, pen_v[j] ); | ||
770 | contact_elt_length = dFabs(dDOT(pen_elt[j], esn)); | ||
771 | } | ||
772 | } | ||
773 | } | ||
774 | |||
775 | if ((depth > 0.0) && (depth <= contact_elt_length)) { | ||
776 | GenerateContact(Flags, Contacts, Stride, TriMesh1, TriMesh2, | ||
777 | ContactPt, esn, depth, OutTriCount); | ||
778 | badPen = false; | ||
779 | } | ||
780 | } | ||
781 | |||
782 | |||
783 | if (badPen) { | ||
784 | // If the direction of motion is perpindicular to both normals | ||
785 | if ( (dFabs(dDOT(n1, elt_sum)) < REAL(0.01)) && (dFabs(dDOT(n2, elt_sum)) < REAL(0.01)) ) { | ||
786 | dVector3 esn; | ||
787 | if (pen_v == v1) { | ||
788 | SMULT(esn, elt_sum, -1.0); | ||
789 | } | ||
790 | else { | ||
791 | SET(esn, elt_sum); | ||
792 | } | ||
793 | |||
794 | dNormalize3(esn); | ||
795 | |||
796 | |||
797 | // Look at the clipped points again, checking them against this | ||
798 | // new normal | ||
799 | for (int j=0; j<firstClippedTri.Count; j++) { | ||
800 | DEPTH(dp, CoplanarPt, firstClippedTri.Points[j], esn); | ||
801 | |||
802 | if (dp >= 0.0) { | ||
803 | contact_elt_length = dFabs(dDOT(firstClippedElt[j], esn)); | ||
804 | |||
805 | depth = dp; | ||
806 | //if (depth == 0.0) | ||
807 | //depth = dMin(DISTANCE_EPSILON, contact_elt_length); | ||
808 | |||
809 | if ((contact_elt_length < SMALL_ELT) && (depth < EXPANDED_ELT_THRESH)) | ||
810 | depth = contact_elt_length; | ||
811 | |||
812 | if (depth <= contact_elt_length) { | ||
813 | // Add a contact | ||
814 | GenerateContact(Flags, Contacts, Stride, TriMesh1, TriMesh2, | ||
815 | firstClippedTri.Points[j], esn, depth, OutTriCount); | ||
816 | badPen = false; | ||
817 | |||
818 | if ((OutTriCount | CONTACTS_UNIMPORTANT) == (Flags & (NUMC_MASK | CONTACTS_UNIMPORTANT))) { | ||
819 | break; | ||
820 | } | ||
821 | } | ||
822 | } | ||
823 | } | ||
824 | |||
825 | if (badPen) { | ||
826 | // If this test failed, try it with the second set of clipped faces | ||
827 | for (int j=0; j<secondClippedTri.Count; j++) { | ||
828 | DEPTH(dp, CoplanarPt, secondClippedTri.Points[j], esn); | ||
829 | |||
830 | if (dp >= 0.0) { | ||
831 | contact_elt_length = dFabs(dDOT(secondClippedElt[j], esn)); | ||
832 | |||
833 | depth = dp; | ||
834 | //if (depth == 0.0) | ||
835 | //depth = dMin(DISTANCE_EPSILON, contact_elt_length); | ||
836 | |||
837 | if ((contact_elt_length < SMALL_ELT) && (depth < EXPANDED_ELT_THRESH)) | ||
838 | depth = contact_elt_length; | ||
839 | |||
840 | if (depth <= contact_elt_length) { | ||
841 | // Add a contact | ||
842 | GenerateContact(Flags, Contacts, Stride, TriMesh1, TriMesh2, | ||
843 | secondClippedTri.Points[j], esn, depth, OutTriCount); | ||
844 | badPen = false; | ||
845 | |||
846 | if ((OutTriCount | CONTACTS_UNIMPORTANT) == (Flags & (NUMC_MASK | CONTACTS_UNIMPORTANT))) { | ||
847 | break; | ||
848 | } | ||
849 | } | ||
850 | } | ||
851 | } | ||
852 | } | ||
853 | } | ||
854 | } | ||
855 | |||
856 | |||
857 | |||
858 | if (badPen) { | ||
859 | // if we have very little motion, we're dealing with resting contact | ||
860 | // and shouldn't reference the ELTs at all | ||
861 | // | ||
862 | if (LENGTH(elt_sum) < VELOCITY_EPSILON) { | ||
863 | |||
864 | // instead of a "contact_elt_length" threshhold, we'll use an | ||
865 | // arbitrary, small one | ||
866 | for (int j=0; j<3; j++) { | ||
867 | DEPTH(dp, CoplanarPt, pen_v[j], n); | ||
868 | |||
869 | if (dp == 0.0) | ||
870 | dp = TINY_PENETRATION; | ||
871 | |||
872 | if ( (dp > 0.0) && (dp <= SMALL_ELT)) { | ||
873 | // Add a contact | ||
874 | GenerateContact(Flags, Contacts, Stride, TriMesh1, TriMesh2, | ||
875 | pen_v[j], n, dp, OutTriCount); | ||
876 | badPen = false; | ||
877 | |||
878 | if ((OutTriCount | CONTACTS_UNIMPORTANT) == (Flags & (NUMC_MASK | CONTACTS_UNIMPORTANT))) { | ||
879 | break; | ||
880 | } | ||
881 | } | ||
882 | } | ||
883 | |||
884 | |||
885 | if (badPen) { | ||
886 | // try the other normal | ||
887 | SwapNormals(pen_v, col_v, v1, v2, pen_elt, elt_f1, elt_f2, n, n1, n2); | ||
888 | |||
889 | for (int j=0; j<3; j++) { | ||
890 | DEPTH(dp, CoplanarPt, pen_v[j], n); | ||
891 | |||
892 | if (dp == 0.0) | ||
893 | dp = TINY_PENETRATION; | ||
894 | |||
895 | if ( (dp > 0.0) && (dp <= SMALL_ELT)) { | ||
896 | GenerateContact(Flags, Contacts, Stride, TriMesh1, TriMesh2, | ||
897 | pen_v[j], n, dp, OutTriCount); | ||
898 | badPen = false; | ||
899 | |||
900 | if ((OutTriCount | CONTACTS_UNIMPORTANT) == (Flags & (NUMC_MASK | CONTACTS_UNIMPORTANT))) { | ||
901 | break; | ||
902 | } | ||
903 | } | ||
904 | } | ||
905 | } | ||
906 | |||
907 | |||
908 | |||
909 | } | ||
910 | } | ||
911 | |||
912 | if (badPen) { | ||
913 | // find the nearest existing contact, and replicate it's | ||
914 | // normal and depth | ||
915 | // | ||
916 | dContactGeom* Contact; | ||
917 | dVector3 pos_diff; | ||
918 | dReal min_dist, dist; | ||
919 | |||
920 | min_dist = dInfinity; | ||
921 | depth = 0.0; | ||
922 | for (int j=0; j<OutTriCount; j++) { | ||
923 | Contact = SAFECONTACT(Flags, Contacts, j, Stride); | ||
924 | |||
925 | SUB(pos_diff, Contact->pos, CoplanarPt); | ||
926 | |||
927 | dist = dDOT(pos_diff, pos_diff); | ||
928 | if (dist < min_dist) { | ||
929 | min_dist = dist; | ||
930 | depth = Contact->depth; | ||
931 | SMULT(ContactNormal, Contact->normal, -1.0); | ||
932 | } | ||
933 | } | ||
934 | |||
935 | if (depth > 0.0) { | ||
936 | // Add a tiny contact at the coplanar point | ||
937 | GenerateContact(Flags, Contacts, Stride, TriMesh1, TriMesh2, | ||
938 | CoplanarPt, ContactNormal, depth, OutTriCount); | ||
939 | badPen = false; | ||
940 | } | ||
941 | } | ||
942 | |||
943 | |||
944 | if (badPen) { | ||
945 | // Add a tiny contact at the coplanar point | ||
946 | if (-dDOT(elt_sum, n1) > -dDOT(elt_sum, n2)) { | ||
947 | SET(ContactNormal, n1); | ||
948 | } | ||
949 | else { | ||
950 | SET(ContactNormal, n2); | ||
951 | } | ||
952 | |||
953 | GenerateContact(Flags, Contacts, Stride, TriMesh1, TriMesh2, | ||
954 | CoplanarPt, ContactNormal, TINY_PENETRATION, OutTriCount); | ||
955 | badPen = false; | ||
956 | } | ||
957 | |||
958 | |||
959 | } // not coplanar (main loop) | ||
960 | } // TriTriIntersectWithIsectLine | ||
961 | |||
962 | if ((OutTriCount | CONTACTS_UNIMPORTANT) == (Flags & (NUMC_MASK | CONTACTS_UNIMPORTANT))) { | ||
963 | break; | ||
964 | } | ||
965 | } | ||
966 | |||
967 | // Free memory | ||
968 | delete[] firstClippedElt; | ||
969 | delete[] secondClippedElt; | ||
970 | |||
971 | // Return the number of contacts | ||
972 | return OutTriCount; | ||
973 | } | ||
974 | } | ||
975 | } | ||
976 | |||
977 | |||
978 | // There was some kind of failure during the Collide call or | ||
979 | // there are no faces overlapping | ||
980 | return 0; | ||
981 | } | ||
982 | |||
983 | |||
984 | |||
985 | static void | ||
986 | GetTriangleGeometryCallback(udword triangleindex, VertexPointers& triangle, udword user_data) | ||
987 | { | ||
988 | dVector3 Out[3]; | ||
989 | |||
990 | FetchTriangle((dxTriMesh*) user_data, (int) triangleindex, Out); | ||
991 | |||
992 | for (int i = 0; i < 3; i++) | ||
993 | triangle.Vertex[i] = (const Point*) ((dReal*) Out[i]); | ||
994 | } | ||
995 | |||
996 | |||
997 | // | ||
998 | // | ||
999 | // | ||
1000 | #define B11 B[0] | ||
1001 | #define B12 B[1] | ||
1002 | #define B13 B[2] | ||
1003 | #define B14 B[3] | ||
1004 | #define B21 B[4] | ||
1005 | #define B22 B[5] | ||
1006 | #define B23 B[6] | ||
1007 | #define B24 B[7] | ||
1008 | #define B31 B[8] | ||
1009 | #define B32 B[9] | ||
1010 | #define B33 B[10] | ||
1011 | #define B34 B[11] | ||
1012 | #define B41 B[12] | ||
1013 | #define B42 B[13] | ||
1014 | #define B43 B[14] | ||
1015 | #define B44 B[15] | ||
1016 | |||
1017 | #define Binv11 Binv[0] | ||
1018 | #define Binv12 Binv[1] | ||
1019 | #define Binv13 Binv[2] | ||
1020 | #define Binv14 Binv[3] | ||
1021 | #define Binv21 Binv[4] | ||
1022 | #define Binv22 Binv[5] | ||
1023 | #define Binv23 Binv[6] | ||
1024 | #define Binv24 Binv[7] | ||
1025 | #define Binv31 Binv[8] | ||
1026 | #define Binv32 Binv[9] | ||
1027 | #define Binv33 Binv[10] | ||
1028 | #define Binv34 Binv[11] | ||
1029 | #define Binv41 Binv[12] | ||
1030 | #define Binv42 Binv[13] | ||
1031 | #define Binv43 Binv[14] | ||
1032 | #define Binv44 Binv[15] | ||
1033 | |||
1034 | inline void | ||
1035 | dMakeMatrix4(const dVector3 Position, const dMatrix3 Rotation, dMatrix4 &B) | ||
1036 | { | ||
1037 | B11 = Rotation[0]; B21 = Rotation[1]; B31 = Rotation[2]; B41 = Position[0]; | ||
1038 | B12 = Rotation[4]; B22 = Rotation[5]; B32 = Rotation[6]; B42 = Position[1]; | ||
1039 | B13 = Rotation[8]; B23 = Rotation[9]; B33 = Rotation[10]; B43 = Position[2]; | ||
1040 | |||
1041 | B14 = 0.0; B24 = 0.0; B34 = 0.0; B44 = 1.0; | ||
1042 | } | ||
1043 | |||
1044 | |||
1045 | static void | ||
1046 | dInvertMatrix4( dMatrix4& B, dMatrix4& Binv ) | ||
1047 | { | ||
1048 | dReal det = (B11 * B22 - B12 * B21) * (B33 * B44 - B34 * B43) | ||
1049 | -(B11 * B23 - B13 * B21) * (B32 * B44 - B34 * B42) | ||
1050 | +(B11 * B24 - B14 * B21) * (B32 * B43 - B33 * B42) | ||
1051 | +(B12 * B23 - B13 * B22) * (B31 * B44 - B34 * B41) | ||
1052 | -(B12 * B24 - B14 * B22) * (B31 * B43 - B33 * B41) | ||
1053 | +(B13 * B24 - B14 * B23) * (B31 * B42 - B32 * B41); | ||
1054 | |||
1055 | dAASSERT (det != 0.0); | ||
1056 | |||
1057 | det = 1.0 / det; | ||
1058 | |||
1059 | Binv11 = (dReal) (det * ((B22 * B33) - (B23 * B32))); | ||
1060 | Binv12 = (dReal) (det * ((B32 * B13) - (B33 * B12))); | ||
1061 | Binv13 = (dReal) (det * ((B12 * B23) - (B13 * B22))); | ||
1062 | Binv14 = 0.0f; | ||
1063 | Binv21 = (dReal) (det * ((B23 * B31) - (B21 * B33))); | ||
1064 | Binv22 = (dReal) (det * ((B33 * B11) - (B31 * B13))); | ||
1065 | Binv23 = (dReal) (det * ((B13 * B21) - (B11 * B23))); | ||
1066 | Binv24 = 0.0f; | ||
1067 | Binv31 = (dReal) (det * ((B21 * B32) - (B22 * B31))); | ||
1068 | Binv32 = (dReal) (det * ((B31 * B12) - (B32 * B11))); | ||
1069 | Binv33 = (dReal) (det * ((B11 * B22) - (B12 * B21))); | ||
1070 | Binv34 = 0.0f; | ||
1071 | Binv41 = (dReal) (det * (B21*(B33*B42 - B32*B43) + B22*(B31*B43 - B33*B41) + B23*(B32*B41 - B31*B42))); | ||
1072 | Binv42 = (dReal) (det * (B31*(B13*B42 - B12*B43) + B32*(B11*B43 - B13*B41) + B33*(B12*B41 - B11*B42))); | ||
1073 | Binv43 = (dReal) (det * (B41*(B13*B22 - B12*B23) + B42*(B11*B23 - B13*B21) + B43*(B12*B21 - B11*B22))); | ||
1074 | Binv44 = 1.0f; | ||
1075 | } | ||
1076 | |||
1077 | |||
1078 | |||
1079 | ///////////////////////////////////////////////// | ||
1080 | // | ||
1081 | // Triangle/Triangle intersection utilities | ||
1082 | // | ||
1083 | // From the article "A Fast Triangle-Triangle Intersection Test", | ||
1084 | // Journal of Graphics Tools, 2(2), 1997 | ||
1085 | // | ||
1086 | // Some of this functionality is duplicated in OPCODE (see | ||
1087 | // OPC_TriTriOverlap.h) but we have replicated it here so we don't | ||
1088 | // have to mess with the internals of OPCODE, as well as so we can | ||
1089 | // further optimize some of the functions. | ||
1090 | // | ||
1091 | // This version computes the line of intersection as well (if they | ||
1092 | // are not coplanar): | ||
1093 | // int TriTriIntersectWithIsectLine(dReal V0[3],dReal V1[3],dReal V2[3], | ||
1094 | // dReal U0[3],dReal U1[3],dReal U2[3], | ||
1095 | // int *coplanar, | ||
1096 | // dReal isectpt1[3],dReal isectpt2[3]); | ||
1097 | // | ||
1098 | // parameters: vertices of triangle 1: V0,V1,V2 | ||
1099 | // vertices of triangle 2: U0,U1,U2 | ||
1100 | // | ||
1101 | // result : returns 1 if the triangles intersect, otherwise 0 | ||
1102 | // "coplanar" returns whether the tris are coplanar | ||
1103 | // isectpt1, isectpt2 are the endpoints of the line of | ||
1104 | // intersection | ||
1105 | // | ||
1106 | |||
1107 | |||
1108 | |||
1109 | /* if USE_EPSILON_TEST is true then we do a check: | ||
1110 | if |dv|<EPSILON then dv=0.0; | ||
1111 | else no check is done (which is less robust) | ||
1112 | */ | ||
1113 | #define USE_EPSILON_TEST TRUE | ||
1114 | #define EPSILON REAL(0.000001) | ||
1115 | |||
1116 | |||
1117 | /* sort so that a<=b */ | ||
1118 | #define SORT(a,b) \ | ||
1119 | if(a>b) \ | ||
1120 | { \ | ||
1121 | dReal c; \ | ||
1122 | c=a; \ | ||
1123 | a=b; \ | ||
1124 | b=c; \ | ||
1125 | } | ||
1126 | |||
1127 | #define ISECT(VV0,VV1,VV2,D0,D1,D2,isect0,isect1) \ | ||
1128 | isect0=VV0+(VV1-VV0)*D0/(D0-D1); \ | ||
1129 | isect1=VV0+(VV2-VV0)*D0/(D0-D2); | ||
1130 | |||
1131 | |||
1132 | #define COMPUTE_INTERVALS(VV0,VV1,VV2,D0,D1,D2,D0D1,D0D2,isect0,isect1) \ | ||
1133 | if(D0D1>0.0f) \ | ||
1134 | { \ | ||
1135 | /* here we know that D0D2<=0.0 */ \ | ||
1136 | /* that is D0, D1 are on the same side, D2 on the other or on the plane */ \ | ||
1137 | ISECT(VV2,VV0,VV1,D2,D0,D1,isect0,isect1); \ | ||
1138 | } \ | ||
1139 | else if(D0D2>0.0f) \ | ||
1140 | { \ | ||
1141 | /* here we know that d0d1<=0.0 */ \ | ||
1142 | ISECT(VV1,VV0,VV2,D1,D0,D2,isect0,isect1); \ | ||
1143 | } \ | ||
1144 | else if(D1*D2>0.0f || D0!=0.0f) \ | ||
1145 | { \ | ||
1146 | /* here we know that d0d1<=0.0 or that D0!=0.0 */ \ | ||
1147 | ISECT(VV0,VV1,VV2,D0,D1,D2,isect0,isect1); \ | ||
1148 | } \ | ||
1149 | else if(D1!=0.0f) \ | ||
1150 | { \ | ||
1151 | ISECT(VV1,VV0,VV2,D1,D0,D2,isect0,isect1); \ | ||
1152 | } \ | ||
1153 | else if(D2!=0.0f) \ | ||
1154 | { \ | ||
1155 | ISECT(VV2,VV0,VV1,D2,D0,D1,isect0,isect1); \ | ||
1156 | } \ | ||
1157 | else \ | ||
1158 | { \ | ||
1159 | /* triangles are coplanar */ \ | ||
1160 | return coplanar_tri_tri(N1,V0,V1,V2,U0,U1,U2); \ | ||
1161 | } | ||
1162 | |||
1163 | |||
1164 | |||
1165 | /* this edge to edge test is based on Franlin Antonio's gem: | ||
1166 | "Faster Line Segment Intersection", in Graphics Gems III, | ||
1167 | pp. 199-202 */ | ||
1168 | #define EDGE_EDGE_TEST(V0,U0,U1) \ | ||
1169 | Bx=U0[i0]-U1[i0]; \ | ||
1170 | By=U0[i1]-U1[i1]; \ | ||
1171 | Cx=V0[i0]-U0[i0]; \ | ||
1172 | Cy=V0[i1]-U0[i1]; \ | ||
1173 | f=Ay*Bx-Ax*By; \ | ||
1174 | d=By*Cx-Bx*Cy; \ | ||
1175 | if((f>0 && d>=0 && d<=f) || (f<0 && d<=0 && d>=f)) \ | ||
1176 | { \ | ||
1177 | e=Ax*Cy-Ay*Cx; \ | ||
1178 | if(f>0) \ | ||
1179 | { \ | ||
1180 | if(e>=0 && e<=f) return 1; \ | ||
1181 | } \ | ||
1182 | else \ | ||
1183 | { \ | ||
1184 | if(e<=0 && e>=f) return 1; \ | ||
1185 | } \ | ||
1186 | } | ||
1187 | |||
1188 | #define EDGE_AGAINST_TRI_EDGES(V0,V1,U0,U1,U2) \ | ||
1189 | { \ | ||
1190 | dReal Ax,Ay,Bx,By,Cx,Cy,e,d,f; \ | ||
1191 | Ax=V1[i0]-V0[i0]; \ | ||
1192 | Ay=V1[i1]-V0[i1]; \ | ||
1193 | /* test edge U0,U1 against V0,V1 */ \ | ||
1194 | EDGE_EDGE_TEST(V0,U0,U1); \ | ||
1195 | /* test edge U1,U2 against V0,V1 */ \ | ||
1196 | EDGE_EDGE_TEST(V0,U1,U2); \ | ||
1197 | /* test edge U2,U1 against V0,V1 */ \ | ||
1198 | EDGE_EDGE_TEST(V0,U2,U0); \ | ||
1199 | } | ||
1200 | |||
1201 | #define POINT_IN_TRI(V0,U0,U1,U2) \ | ||
1202 | { \ | ||
1203 | dReal a,b,c,d0,d1,d2; \ | ||
1204 | /* is T1 completly inside T2? */ \ | ||
1205 | /* check if V0 is inside tri(U0,U1,U2) */ \ | ||
1206 | a=U1[i1]-U0[i1]; \ | ||
1207 | b=-(U1[i0]-U0[i0]); \ | ||
1208 | c=-a*U0[i0]-b*U0[i1]; \ | ||
1209 | d0=a*V0[i0]+b*V0[i1]+c; \ | ||
1210 | \ | ||
1211 | a=U2[i1]-U1[i1]; \ | ||
1212 | b=-(U2[i0]-U1[i0]); \ | ||
1213 | c=-a*U1[i0]-b*U1[i1]; \ | ||
1214 | d1=a*V0[i0]+b*V0[i1]+c; \ | ||
1215 | \ | ||
1216 | a=U0[i1]-U2[i1]; \ | ||
1217 | b=-(U0[i0]-U2[i0]); \ | ||
1218 | c=-a*U2[i0]-b*U2[i1]; \ | ||
1219 | d2=a*V0[i0]+b*V0[i1]+c; \ | ||
1220 | if(d0*d1>0.0) \ | ||
1221 | { \ | ||
1222 | if(d0*d2>0.0) return 1; \ | ||
1223 | } \ | ||
1224 | } | ||
1225 | |||
1226 | int coplanar_tri_tri(dReal N[3],dReal V0[3],dReal V1[3],dReal V2[3], | ||
1227 | dReal U0[3],dReal U1[3],dReal U2[3]) | ||
1228 | { | ||
1229 | dReal A[3]; | ||
1230 | short i0,i1; | ||
1231 | /* first project onto an axis-aligned plane, that maximizes the area */ | ||
1232 | /* of the triangles, compute indices: i0,i1. */ | ||
1233 | A[0]= dFabs(N[0]); | ||
1234 | A[1]= dFabs(N[1]); | ||
1235 | A[2]= dFabs(N[2]); | ||
1236 | if(A[0]>A[1]) | ||
1237 | { | ||
1238 | if(A[0]>A[2]) | ||
1239 | { | ||
1240 | i0=1; /* A[0] is greatest */ | ||
1241 | i1=2; | ||
1242 | } | ||
1243 | else | ||
1244 | { | ||
1245 | i0=0; /* A[2] is greatest */ | ||
1246 | i1=1; | ||
1247 | } | ||
1248 | } | ||
1249 | else /* A[0]<=A[1] */ | ||
1250 | { | ||
1251 | if(A[2]>A[1]) | ||
1252 | { | ||
1253 | i0=0; /* A[2] is greatest */ | ||
1254 | i1=1; | ||
1255 | } | ||
1256 | else | ||
1257 | { | ||
1258 | i0=0; /* A[1] is greatest */ | ||
1259 | i1=2; | ||
1260 | } | ||
1261 | } | ||
1262 | |||
1263 | /* test all edges of triangle 1 against the edges of triangle 2 */ | ||
1264 | EDGE_AGAINST_TRI_EDGES(V0,V1,U0,U1,U2); | ||
1265 | EDGE_AGAINST_TRI_EDGES(V1,V2,U0,U1,U2); | ||
1266 | EDGE_AGAINST_TRI_EDGES(V2,V0,U0,U1,U2); | ||
1267 | |||
1268 | /* finally, test if tri1 is totally contained in tri2 or vice versa */ | ||
1269 | POINT_IN_TRI(V0,U0,U1,U2); | ||
1270 | POINT_IN_TRI(U0,V0,V1,V2); | ||
1271 | |||
1272 | return 0; | ||
1273 | } | ||
1274 | |||
1275 | |||
1276 | |||
1277 | #define NEWCOMPUTE_INTERVALS(VV0,VV1,VV2,D0,D1,D2,D0D1,D0D2,A,B,C,X0,X1) \ | ||
1278 | { \ | ||
1279 | if(D0D1>0.0f) \ | ||
1280 | { \ | ||
1281 | /* here we know that D0D2<=0.0 */ \ | ||
1282 | /* that is D0, D1 are on the same side, D2 on the other or on the plane */ \ | ||
1283 | A=VV2; B=(VV0-VV2)*D2; C=(VV1-VV2)*D2; X0=D2-D0; X1=D2-D1; \ | ||
1284 | } \ | ||
1285 | else if(D0D2>0.0f)\ | ||
1286 | { \ | ||
1287 | /* here we know that d0d1<=0.0 */ \ | ||
1288 | A=VV1; B=(VV0-VV1)*D1; C=(VV2-VV1)*D1; X0=D1-D0; X1=D1-D2; \ | ||
1289 | } \ | ||
1290 | else if(D1*D2>0.0f || D0!=0.0f) \ | ||
1291 | { \ | ||
1292 | /* here we know that d0d1<=0.0 or that D0!=0.0 */ \ | ||
1293 | A=VV0; B=(VV1-VV0)*D0; C=(VV2-VV0)*D0; X0=D0-D1; X1=D0-D2; \ | ||
1294 | } \ | ||
1295 | else if(D1!=0.0f) \ | ||
1296 | { \ | ||
1297 | A=VV1; B=(VV0-VV1)*D1; C=(VV2-VV1)*D1; X0=D1-D0; X1=D1-D2; \ | ||
1298 | } \ | ||
1299 | else if(D2!=0.0f) \ | ||
1300 | { \ | ||
1301 | A=VV2; B=(VV0-VV2)*D2; C=(VV1-VV2)*D2; X0=D2-D0; X1=D2-D1; \ | ||
1302 | } \ | ||
1303 | else \ | ||
1304 | { \ | ||
1305 | /* triangles are coplanar */ \ | ||
1306 | return coplanar_tri_tri(N1,V0,V1,V2,U0,U1,U2); \ | ||
1307 | } \ | ||
1308 | } | ||
1309 | |||
1310 | |||
1311 | |||
1312 | |||
1313 | /* sort so that a<=b */ | ||
1314 | #define SORT2(a,b,smallest) \ | ||
1315 | if(a>b) \ | ||
1316 | { \ | ||
1317 | dReal c; \ | ||
1318 | c=a; \ | ||
1319 | a=b; \ | ||
1320 | b=c; \ | ||
1321 | smallest=1; \ | ||
1322 | } \ | ||
1323 | else smallest=0; | ||
1324 | |||
1325 | |||
1326 | inline void isect2(dReal VTX0[3],dReal VTX1[3],dReal VTX2[3],dReal VV0,dReal VV1,dReal VV2, | ||
1327 | dReal D0,dReal D1,dReal D2,dReal *isect0,dReal *isect1,dReal isectpoint0[3],dReal isectpoint1[3]) | ||
1328 | { | ||
1329 | dReal tmp=D0/(D0-D1); | ||
1330 | dReal diff[3]; | ||
1331 | *isect0=VV0+(VV1-VV0)*tmp; | ||
1332 | SUB(diff,VTX1,VTX0); | ||
1333 | MULT(diff,diff,tmp); | ||
1334 | ADD(isectpoint0,diff,VTX0); | ||
1335 | tmp=D0/(D0-D2); | ||
1336 | *isect1=VV0+(VV2-VV0)*tmp; | ||
1337 | SUB(diff,VTX2,VTX0); | ||
1338 | MULT(diff,diff,tmp); | ||
1339 | ADD(isectpoint1,VTX0,diff); | ||
1340 | } | ||
1341 | |||
1342 | |||
1343 | #if 0 | ||
1344 | #define ISECT2(VTX0,VTX1,VTX2,VV0,VV1,VV2,D0,D1,D2,isect0,isect1,isectpoint0,isectpoint1) \ | ||
1345 | tmp=D0/(D0-D1); \ | ||
1346 | isect0=VV0+(VV1-VV0)*tmp; \ | ||
1347 | SUB(diff,VTX1,VTX0); \ | ||
1348 | MULT(diff,diff,tmp); \ | ||
1349 | ADD(isectpoint0,diff,VTX0); \ | ||
1350 | tmp=D0/(D0-D2); | ||
1351 | /* isect1=VV0+(VV2-VV0)*tmp; \ */ | ||
1352 | /* SUB(diff,VTX2,VTX0); \ */ | ||
1353 | /* MULT(diff,diff,tmp); \ */ | ||
1354 | /* ADD(isectpoint1,VTX0,diff); */ | ||
1355 | #endif | ||
1356 | |||
1357 | inline int compute_intervals_isectline(dReal VERT0[3],dReal VERT1[3],dReal VERT2[3], | ||
1358 | dReal VV0,dReal VV1,dReal VV2,dReal D0,dReal D1,dReal D2, | ||
1359 | dReal D0D1,dReal D0D2,dReal *isect0,dReal *isect1, | ||
1360 | dReal isectpoint0[3],dReal isectpoint1[3]) | ||
1361 | { | ||
1362 | if(D0D1>0.0f) | ||
1363 | { | ||
1364 | /* here we know that D0D2<=0.0 */ | ||
1365 | /* that is D0, D1 are on the same side, D2 on the other or on the plane */ | ||
1366 | isect2(VERT2,VERT0,VERT1,VV2,VV0,VV1,D2,D0,D1,isect0,isect1,isectpoint0,isectpoint1); | ||
1367 | } | ||
1368 | else if(D0D2>0.0f) | ||
1369 | { | ||
1370 | /* here we know that d0d1<=0.0 */ | ||
1371 | isect2(VERT1,VERT0,VERT2,VV1,VV0,VV2,D1,D0,D2,isect0,isect1,isectpoint0,isectpoint1); | ||
1372 | } | ||
1373 | else if(D1*D2>0.0f || D0!=0.0f) | ||
1374 | { | ||
1375 | /* here we know that d0d1<=0.0 or that D0!=0.0 */ | ||
1376 | isect2(VERT0,VERT1,VERT2,VV0,VV1,VV2,D0,D1,D2,isect0,isect1,isectpoint0,isectpoint1); | ||
1377 | } | ||
1378 | else if(D1!=0.0f) | ||
1379 | { | ||
1380 | isect2(VERT1,VERT0,VERT2,VV1,VV0,VV2,D1,D0,D2,isect0,isect1,isectpoint0,isectpoint1); | ||
1381 | } | ||
1382 | else if(D2!=0.0f) | ||
1383 | { | ||
1384 | isect2(VERT2,VERT0,VERT1,VV2,VV0,VV1,D2,D0,D1,isect0,isect1,isectpoint0,isectpoint1); | ||
1385 | } | ||
1386 | else | ||
1387 | { | ||
1388 | /* triangles are coplanar */ | ||
1389 | return 1; | ||
1390 | } | ||
1391 | return 0; | ||
1392 | } | ||
1393 | |||
1394 | #define COMPUTE_INTERVALS_ISECTLINE(VERT0,VERT1,VERT2,VV0,VV1,VV2,D0,D1,D2,D0D1,D0D2,isect0,isect1,isectpoint0,isectpoint1) \ | ||
1395 | if(D0D1>0.0f) \ | ||
1396 | { \ | ||
1397 | /* here we know that D0D2<=0.0 */ \ | ||
1398 | /* that is D0, D1 are on the same side, D2 on the other or on the plane */ \ | ||
1399 | isect2(VERT2,VERT0,VERT1,VV2,VV0,VV1,D2,D0,D1,&isect0,&isect1,isectpoint0,isectpoint1); \ | ||
1400 | } | ||
1401 | #if 0 | ||
1402 | else if(D0D2>0.0f) \ | ||
1403 | { \ | ||
1404 | /* here we know that d0d1<=0.0 */ \ | ||
1405 | isect2(VERT1,VERT0,VERT2,VV1,VV0,VV2,D1,D0,D2,&isect0,&isect1,isectpoint0,isectpoint1); \ | ||
1406 | } \ | ||
1407 | else if(D1*D2>0.0f || D0!=0.0f) \ | ||
1408 | { \ | ||
1409 | /* here we know that d0d1<=0.0 or that D0!=0.0 */ \ | ||
1410 | isect2(VERT0,VERT1,VERT2,VV0,VV1,VV2,D0,D1,D2,&isect0,&isect1,isectpoint0,isectpoint1); \ | ||
1411 | } \ | ||
1412 | else if(D1!=0.0f) \ | ||
1413 | { \ | ||
1414 | isect2(VERT1,VERT0,VERT2,VV1,VV0,VV2,D1,D0,D2,&isect0,&isect1,isectpoint0,isectpoint1); \ | ||
1415 | } \ | ||
1416 | else if(D2!=0.0f) \ | ||
1417 | { \ | ||
1418 | isect2(VERT2,VERT0,VERT1,VV2,VV0,VV1,D2,D0,D1,&isect0,&isect1,isectpoint0,isectpoint1); \ | ||
1419 | } \ | ||
1420 | else \ | ||
1421 | { \ | ||
1422 | /* triangles are coplanar */ \ | ||
1423 | coplanar=1; \ | ||
1424 | return coplanar_tri_tri(N1,V0,V1,V2,U0,U1,U2); \ | ||
1425 | } | ||
1426 | #endif | ||
1427 | |||
1428 | |||
1429 | |||
1430 | static int TriTriIntersectWithIsectLine(dReal V0[3],dReal V1[3],dReal V2[3], | ||
1431 | dReal U0[3],dReal U1[3],dReal U2[3],int *coplanar, | ||
1432 | dReal isectpt1[3],dReal isectpt2[3]) | ||
1433 | { | ||
1434 | dReal E1[3],E2[3]; | ||
1435 | dReal N1[3],N2[3],d1,d2; | ||
1436 | dReal du0,du1,du2,dv0,dv1,dv2; | ||
1437 | dReal D[3]; | ||
1438 | dReal isect1[2], isect2[2]; | ||
1439 | dReal isectpointA1[3],isectpointA2[3]; | ||
1440 | dReal isectpointB1[3],isectpointB2[3]; | ||
1441 | dReal du0du1,du0du2,dv0dv1,dv0dv2; | ||
1442 | short index; | ||
1443 | dReal vp0,vp1,vp2; | ||
1444 | dReal up0,up1,up2; | ||
1445 | dReal b,c,max; | ||
1446 | int smallest1,smallest2; | ||
1447 | |||
1448 | /* compute plane equation of triangle(V0,V1,V2) */ | ||
1449 | SUB(E1,V1,V0); | ||
1450 | SUB(E2,V2,V0); | ||
1451 | CROSS(N1,E1,E2); | ||
1452 | d1=-DOT(N1,V0); | ||
1453 | /* plane equation 1: N1.X+d1=0 */ | ||
1454 | |||
1455 | /* put U0,U1,U2 into plane equation 1 to compute signed distances to the plane*/ | ||
1456 | du0=DOT(N1,U0)+d1; | ||
1457 | du1=DOT(N1,U1)+d1; | ||
1458 | du2=DOT(N1,U2)+d1; | ||
1459 | |||
1460 | /* coplanarity robustness check */ | ||
1461 | #if USE_EPSILON_TEST==TRUE | ||
1462 | if(dFabs(du0)<EPSILON) du0=0.0; | ||
1463 | if(dFabs(du1)<EPSILON) du1=0.0; | ||
1464 | if(dFabs(du2)<EPSILON) du2=0.0; | ||
1465 | #endif | ||
1466 | du0du1=du0*du1; | ||
1467 | du0du2=du0*du2; | ||
1468 | |||
1469 | if(du0du1>0.0f && du0du2>0.0f) /* same sign on all of them + not equal 0 ? */ | ||
1470 | return 0; /* no intersection occurs */ | ||
1471 | |||
1472 | /* compute plane of triangle (U0,U1,U2) */ | ||
1473 | SUB(E1,U1,U0); | ||
1474 | SUB(E2,U2,U0); | ||
1475 | CROSS(N2,E1,E2); | ||
1476 | d2=-DOT(N2,U0); | ||
1477 | /* plane equation 2: N2.X+d2=0 */ | ||
1478 | |||
1479 | /* put V0,V1,V2 into plane equation 2 */ | ||
1480 | dv0=DOT(N2,V0)+d2; | ||
1481 | dv1=DOT(N2,V1)+d2; | ||
1482 | dv2=DOT(N2,V2)+d2; | ||
1483 | |||
1484 | #if USE_EPSILON_TEST==TRUE | ||
1485 | if(dFabs(dv0)<EPSILON) dv0=0.0; | ||
1486 | if(dFabs(dv1)<EPSILON) dv1=0.0; | ||
1487 | if(dFabs(dv2)<EPSILON) dv2=0.0; | ||
1488 | #endif | ||
1489 | |||
1490 | dv0dv1=dv0*dv1; | ||
1491 | dv0dv2=dv0*dv2; | ||
1492 | |||
1493 | if(dv0dv1>0.0f && dv0dv2>0.0f) /* same sign on all of them + not equal 0 ? */ | ||
1494 | return 0; /* no intersection occurs */ | ||
1495 | |||
1496 | /* compute direction of intersection line */ | ||
1497 | CROSS(D,N1,N2); | ||
1498 | |||
1499 | /* compute and index to the largest component of D */ | ||
1500 | max= dFabs(D[0]); | ||
1501 | index=0; | ||
1502 | b= dFabs(D[1]); | ||
1503 | c= dFabs(D[2]); | ||
1504 | if(b>max) max=b,index=1; | ||
1505 | if(c>max) max=c,index=2; | ||
1506 | |||
1507 | /* this is the simplified projection onto L*/ | ||
1508 | vp0=V0[index]; | ||
1509 | vp1=V1[index]; | ||
1510 | vp2=V2[index]; | ||
1511 | |||
1512 | up0=U0[index]; | ||
1513 | up1=U1[index]; | ||
1514 | up2=U2[index]; | ||
1515 | |||
1516 | /* compute interval for triangle 1 */ | ||
1517 | *coplanar=compute_intervals_isectline(V0,V1,V2,vp0,vp1,vp2,dv0,dv1,dv2, | ||
1518 | dv0dv1,dv0dv2,&isect1[0],&isect1[1],isectpointA1,isectpointA2); | ||
1519 | if(*coplanar) return coplanar_tri_tri(N1,V0,V1,V2,U0,U1,U2); | ||
1520 | |||
1521 | |||
1522 | /* compute interval for triangle 2 */ | ||
1523 | compute_intervals_isectline(U0,U1,U2,up0,up1,up2,du0,du1,du2, | ||
1524 | du0du1,du0du2,&isect2[0],&isect2[1],isectpointB1,isectpointB2); | ||
1525 | |||
1526 | SORT2(isect1[0],isect1[1],smallest1); | ||
1527 | SORT2(isect2[0],isect2[1],smallest2); | ||
1528 | |||
1529 | if(isect1[1]<isect2[0] || isect2[1]<isect1[0]) return 0; | ||
1530 | |||
1531 | /* at this point, we know that the triangles intersect */ | ||
1532 | |||
1533 | if(isect2[0]<isect1[0]) | ||
1534 | { | ||
1535 | if(smallest1==0) { SET(isectpt1,isectpointA1); } | ||
1536 | else { SET(isectpt1,isectpointA2); } | ||
1537 | |||
1538 | if(isect2[1]<isect1[1]) | ||
1539 | { | ||
1540 | if(smallest2==0) { SET(isectpt2,isectpointB2); } | ||
1541 | else { SET(isectpt2,isectpointB1); } | ||
1542 | } | ||
1543 | else | ||
1544 | { | ||
1545 | if(smallest1==0) { SET(isectpt2,isectpointA2); } | ||
1546 | else { SET(isectpt2,isectpointA1); } | ||
1547 | } | ||
1548 | } | ||
1549 | else | ||
1550 | { | ||
1551 | if(smallest2==0) { SET(isectpt1,isectpointB1); } | ||
1552 | else { SET(isectpt1,isectpointB2); } | ||
1553 | |||
1554 | if(isect2[1]>isect1[1]) | ||
1555 | { | ||
1556 | if(smallest1==0) { SET(isectpt2,isectpointA2); } | ||
1557 | else { SET(isectpt2,isectpointA1); } | ||
1558 | } | ||
1559 | else | ||
1560 | { | ||
1561 | if(smallest2==0) { SET(isectpt2,isectpointB2); } | ||
1562 | else { SET(isectpt2,isectpointB1); } | ||
1563 | } | ||
1564 | } | ||
1565 | return 1; | ||
1566 | } | ||
1567 | |||
1568 | |||
1569 | |||
1570 | |||
1571 | |||
1572 | // Find the intersectiojn point between a coplanar line segement, | ||
1573 | // defined by X1 and X2, and a ray defined by X3 and direction N. | ||
1574 | // | ||
1575 | // This forumla for this calculation is: | ||
1576 | // (c x b) . (a x b) | ||
1577 | // Q = x1 + a ------------------- | ||
1578 | // | a x b | ^2 | ||
1579 | // | ||
1580 | // where a = x2 - x1 | ||
1581 | // b = x4 - x3 | ||
1582 | // c = x3 - x1 | ||
1583 | // x1 and x2 are the edges of the triangle, and x3 is CoplanarPt | ||
1584 | // and x4 is (CoplanarPt - n) | ||
1585 | static int | ||
1586 | IntersectLineSegmentRay(dVector3 x1, dVector3 x2, dVector3 x3, dVector3 n, | ||
1587 | dVector3 out_pt) | ||
1588 | { | ||
1589 | dVector3 a, b, c, x4; | ||
1590 | |||
1591 | ADD(x4, x3, n); // x4 = x3 + n | ||
1592 | |||
1593 | SUB(a, x2, x1); // a = x2 - x1 | ||
1594 | SUB(b, x4, x3); | ||
1595 | SUB(c, x3, x1); | ||
1596 | |||
1597 | dVector3 tmp1, tmp2; | ||
1598 | CROSS(tmp1, c, b); | ||
1599 | CROSS(tmp2, a, b); | ||
1600 | |||
1601 | dReal num, denom; | ||
1602 | num = dDOT(tmp1, tmp2); | ||
1603 | denom = LENGTH( tmp2 ); | ||
1604 | |||
1605 | dReal s; | ||
1606 | s = num /(denom*denom); | ||
1607 | |||
1608 | for (int i=0; i<3; i++) | ||
1609 | out_pt[i] = x1[i] + a[i]*s; | ||
1610 | |||
1611 | // Test if this intersection is "behind" x3, w.r.t. n | ||
1612 | SUB(a, x3, out_pt); | ||
1613 | if (dDOT(a, n) > 0.0) | ||
1614 | return 0; | ||
1615 | |||
1616 | // Test if this intersection point is outside the edge limits, | ||
1617 | // if (dot( (out_pt-x1), (out_pt-x2) ) < 0) it's inside | ||
1618 | // else outside | ||
1619 | SUB(a, out_pt, x1); | ||
1620 | SUB(b, out_pt, x2); | ||
1621 | if (dDOT(a,b) < 0.0) | ||
1622 | return 1; | ||
1623 | else | ||
1624 | return 0; | ||
1625 | } | ||
1626 | |||
1627 | |||
1628 | // FindTriSolidIntersection - Clips the input trinagle TRI with the | ||
1629 | // sides of a convex bounding solid, described by PLANES, returning | ||
1630 | // the (convex) clipped polygon in CLIPPEDPOLYGON | ||
1631 | // | ||
1632 | static bool | ||
1633 | FindTriSolidIntrsection(const dVector3 Tri[3], | ||
1634 | const dVector4 Planes[6], int numSides, | ||
1635 | LineContactSet& ClippedPolygon ) | ||
1636 | { | ||
1637 | // Set up the LineContactSet structure | ||
1638 | for (int k=0; k<3; k++) { | ||
1639 | SET(ClippedPolygon.Points[k], Tri[k]); | ||
1640 | } | ||
1641 | ClippedPolygon.Count = 3; | ||
1642 | |||
1643 | // Clip wrt the sides | ||
1644 | for ( int i = 0; i < numSides; i++ ) | ||
1645 | ClipConvexPolygonAgainstPlane( Planes[i], Planes[i][3], ClippedPolygon ); | ||
1646 | |||
1647 | return (ClippedPolygon.Count > 0); | ||
1648 | } | ||
1649 | |||
1650 | |||
1651 | |||
1652 | |||
1653 | // ClipConvexPolygonAgainstPlane - Clip a a convex polygon, described by | ||
1654 | // CONTACTS, with a plane (described by N and C). Note: the input | ||
1655 | // vertices are assumed to be in counterclockwise order. | ||
1656 | // | ||
1657 | // This code is taken from The Nebula Device: | ||
1658 | // http://nebuladevice.sourceforge.net/cgi-bin/twiki/view/Nebula/WebHome | ||
1659 | // and is licensed under the following license: | ||
1660 | // http://nebuladevice.sourceforge.net/doc/source/license.txt | ||
1661 | // | ||
1662 | static void | ||
1663 | ClipConvexPolygonAgainstPlane( const dVector3 N, dReal C, | ||
1664 | LineContactSet& Contacts ) | ||
1665 | { | ||
1666 | // test on which side of line are the vertices | ||
1667 | int Positive = 0, Negative = 0, PIndex = -1; | ||
1668 | int Quantity = Contacts.Count; | ||
1669 | |||
1670 | dReal Test[8]; | ||
1671 | for ( int i = 0; i < Contacts.Count; i++ ) { | ||
1672 | // An epsilon is used here because it is possible for the dot product | ||
1673 | // and C to be exactly equal to each other (in theory), but differ | ||
1674 | // slightly because of floating point problems. Thus, add a little | ||
1675 | // to the test number to push actually equal numbers over the edge | ||
1676 | // towards the positive. This should probably be somehow a relative | ||
1677 | // tolerance, and I don't think multiplying by the constant is the best | ||
1678 | // way to do this. | ||
1679 | Test[i] = dDOT(N, Contacts.Points[i]) - C + dFabs(C)*REAL(1e-08); | ||
1680 | |||
1681 | if (Test[i] >= REAL(0.0)) { | ||
1682 | Positive++; | ||
1683 | if (PIndex < 0) { | ||
1684 | PIndex = i; | ||
1685 | } | ||
1686 | } | ||
1687 | else Negative++; | ||
1688 | } | ||
1689 | |||
1690 | if (Positive > 0) { | ||
1691 | if (Negative > 0) { | ||
1692 | // plane transversely intersects polygon | ||
1693 | dVector3 CV[8]; | ||
1694 | int CQuantity = 0, Cur, Prv; | ||
1695 | dReal T; | ||
1696 | |||
1697 | if (PIndex > 0) { | ||
1698 | // first clip vertex on line | ||
1699 | Cur = PIndex; | ||
1700 | Prv = Cur - 1; | ||
1701 | T = Test[Cur] / (Test[Cur] - Test[Prv]); | ||
1702 | CV[CQuantity][0] = Contacts.Points[Cur][0] | ||
1703 | + T * (Contacts.Points[Prv][0] - Contacts.Points[Cur][0]); | ||
1704 | CV[CQuantity][1] = Contacts.Points[Cur][1] | ||
1705 | + T * (Contacts.Points[Prv][1] - Contacts.Points[Cur][1]); | ||
1706 | CV[CQuantity][2] = Contacts.Points[Cur][2] | ||
1707 | + T * (Contacts.Points[Prv][2] - Contacts.Points[Cur][2]); | ||
1708 | CV[CQuantity][3] = Contacts.Points[Cur][3] | ||
1709 | + T * (Contacts.Points[Prv][3] - Contacts.Points[Cur][3]); | ||
1710 | CQuantity++; | ||
1711 | |||
1712 | // vertices on positive side of line | ||
1713 | while (Cur < Quantity && Test[Cur] >= REAL(0.0)) { | ||
1714 | CV[CQuantity][0] = Contacts.Points[Cur][0]; | ||
1715 | CV[CQuantity][1] = Contacts.Points[Cur][1]; | ||
1716 | CV[CQuantity][2] = Contacts.Points[Cur][2]; | ||
1717 | CV[CQuantity][3] = Contacts.Points[Cur][3]; | ||
1718 | CQuantity++; | ||
1719 | Cur++; | ||
1720 | } | ||
1721 | |||
1722 | // last clip vertex on line | ||
1723 | if (Cur < Quantity) { | ||
1724 | Prv = Cur - 1; | ||
1725 | } | ||
1726 | else { | ||
1727 | Cur = 0; | ||
1728 | Prv = Quantity - 1; | ||
1729 | } | ||
1730 | |||
1731 | T = Test[Cur] / (Test[Cur] - Test[Prv]); | ||
1732 | CV[CQuantity][0] = Contacts.Points[Cur][0] | ||
1733 | + T * (Contacts.Points[Prv][0] - Contacts.Points[Cur][0]); | ||
1734 | CV[CQuantity][1] = Contacts.Points[Cur][1] | ||
1735 | + T * (Contacts.Points[Prv][1] - Contacts.Points[Cur][1]); | ||
1736 | CV[CQuantity][2] = Contacts.Points[Cur][2] | ||
1737 | + T * (Contacts.Points[Prv][2] - Contacts.Points[Cur][2]); | ||
1738 | CV[CQuantity][3] = Contacts.Points[Cur][3] | ||
1739 | + T * (Contacts.Points[Prv][3] - Contacts.Points[Cur][3]); | ||
1740 | CQuantity++; | ||
1741 | } | ||
1742 | else { | ||
1743 | // iPIndex is 0 | ||
1744 | // vertices on positive side of line | ||
1745 | Cur = 0; | ||
1746 | while (Cur < Quantity && Test[Cur] >= REAL(0.0)) { | ||
1747 | CV[CQuantity][0] = Contacts.Points[Cur][0]; | ||
1748 | CV[CQuantity][1] = Contacts.Points[Cur][1]; | ||
1749 | CV[CQuantity][2] = Contacts.Points[Cur][2]; | ||
1750 | CV[CQuantity][3] = Contacts.Points[Cur][3]; | ||
1751 | CQuantity++; | ||
1752 | Cur++; | ||
1753 | } | ||
1754 | |||
1755 | // last clip vertex on line | ||
1756 | Prv = Cur - 1; | ||
1757 | T = Test[Cur] / (Test[Cur] - Test[Prv]); | ||
1758 | CV[CQuantity][0] = Contacts.Points[Cur][0] | ||
1759 | + T * (Contacts.Points[Prv][0] - Contacts.Points[Cur][0]); | ||
1760 | CV[CQuantity][1] = Contacts.Points[Cur][1] | ||
1761 | + T * (Contacts.Points[Prv][1] - Contacts.Points[Cur][1]); | ||
1762 | CV[CQuantity][2] = Contacts.Points[Cur][2] | ||
1763 | + T * (Contacts.Points[Prv][2] - Contacts.Points[Cur][2]); | ||
1764 | CV[CQuantity][3] = Contacts.Points[Cur][3] | ||
1765 | + T * (Contacts.Points[Prv][3] - Contacts.Points[Cur][3]); | ||
1766 | CQuantity++; | ||
1767 | |||
1768 | // skip vertices on negative side | ||
1769 | while (Cur < Quantity && Test[Cur] < REAL(0.0)) { | ||
1770 | Cur++; | ||
1771 | } | ||
1772 | |||
1773 | // first clip vertex on line | ||
1774 | if (Cur < Quantity) { | ||
1775 | Prv = Cur - 1; | ||
1776 | T = Test[Cur] / (Test[Cur] - Test[Prv]); | ||
1777 | CV[CQuantity][0] = Contacts.Points[Cur][0] | ||
1778 | + T * (Contacts.Points[Prv][0] - Contacts.Points[Cur][0]); | ||
1779 | CV[CQuantity][1] = Contacts.Points[Cur][1] | ||
1780 | + T * (Contacts.Points[Prv][1] - Contacts.Points[Cur][1]); | ||
1781 | CV[CQuantity][2] = Contacts.Points[Cur][2] | ||
1782 | + T * (Contacts.Points[Prv][2] - Contacts.Points[Cur][2]); | ||
1783 | CV[CQuantity][3] = Contacts.Points[Cur][3] | ||
1784 | + T * (Contacts.Points[Prv][3] - Contacts.Points[Cur][3]); | ||
1785 | CQuantity++; | ||
1786 | |||
1787 | // vertices on positive side of line | ||
1788 | while (Cur < Quantity && Test[Cur] >= REAL(0.0)) { | ||
1789 | CV[CQuantity][0] = Contacts.Points[Cur][0]; | ||
1790 | CV[CQuantity][1] = Contacts.Points[Cur][1]; | ||
1791 | CV[CQuantity][2] = Contacts.Points[Cur][2]; | ||
1792 | CV[CQuantity][3] = Contacts.Points[Cur][3]; | ||
1793 | CQuantity++; | ||
1794 | Cur++; | ||
1795 | } | ||
1796 | } | ||
1797 | else { | ||
1798 | // iCur = 0 | ||
1799 | Prv = Quantity - 1; | ||
1800 | T = Test[0] / (Test[0] - Test[Prv]); | ||
1801 | CV[CQuantity][0] = Contacts.Points[0][0] | ||
1802 | + T * (Contacts.Points[Prv][0] - Contacts.Points[0][0]); | ||
1803 | CV[CQuantity][1] = Contacts.Points[0][1] | ||
1804 | + T * (Contacts.Points[Prv][1] - Contacts.Points[0][1]); | ||
1805 | CV[CQuantity][2] = Contacts.Points[0][2] | ||
1806 | + T * (Contacts.Points[Prv][2] - Contacts.Points[0][2]); | ||
1807 | CV[CQuantity][3] = Contacts.Points[0][3] | ||
1808 | + T * (Contacts.Points[Prv][3] - Contacts.Points[0][3]); | ||
1809 | CQuantity++; | ||
1810 | } | ||
1811 | } | ||
1812 | Quantity = CQuantity; | ||
1813 | memcpy( Contacts.Points, CV, CQuantity * sizeof(dVector3) ); | ||
1814 | } | ||
1815 | // else polygon fully on positive side of plane, nothing to do | ||
1816 | Contacts.Count = Quantity; | ||
1817 | } | ||
1818 | else { | ||
1819 | Contacts.Count = 0; // This should not happen, but for safety | ||
1820 | } | ||
1821 | |||
1822 | } | ||
1823 | |||
1824 | |||
1825 | |||
1826 | // Determine if a potential collision point is | ||
1827 | // | ||
1828 | // | ||
1829 | static int | ||
1830 | ExamineContactPoint(dVector3* v_col, dVector3 in_n, dVector3 in_point) | ||
1831 | { | ||
1832 | // Cast a ray from in_point, along the collison normal. Does it intersect the | ||
1833 | // collision face. | ||
1834 | dReal t, u, v; | ||
1835 | |||
1836 | if (!RayTriangleIntersect(in_point, in_n, v_col[0], v_col[1], v_col[2], | ||
1837 | &t, &u, &v)) | ||
1838 | return 0; | ||
1839 | else | ||
1840 | return 1; | ||
1841 | } | ||
1842 | |||
1843 | |||
1844 | |||
1845 | // RayTriangleIntersect - If an intersection is found, t contains the | ||
1846 | // distance along the ray (dir) and u/v contain u/v coordinates into | ||
1847 | // the triangle. Returns 0 if no hit is found | ||
1848 | // From "Real-Time Rendering," page 305 | ||
1849 | // | ||
1850 | static int | ||
1851 | RayTriangleIntersect(const dVector3 orig, const dVector3 dir, | ||
1852 | const dVector3 vert0, const dVector3 vert1,const dVector3 vert2, | ||
1853 | dReal *t,dReal *u,dReal *v) | ||
1854 | |||
1855 | { | ||
1856 | dReal edge1[3], edge2[3], tvec[3], pvec[3], qvec[3]; | ||
1857 | dReal det,inv_det; | ||
1858 | |||
1859 | // find vectors for two edges sharing vert0 | ||
1860 | SUB(edge1, vert1, vert0); | ||
1861 | SUB(edge2, vert2, vert0); | ||
1862 | |||
1863 | // begin calculating determinant - also used to calculate U parameter | ||
1864 | CROSS(pvec, dir, edge2); | ||
1865 | |||
1866 | // if determinant is near zero, ray lies in plane of triangle | ||
1867 | det = DOT(edge1, pvec); | ||
1868 | |||
1869 | if ((det > REAL(-0.001)) && (det < REAL(0.001))) | ||
1870 | return 0; | ||
1871 | inv_det = 1.0 / det; | ||
1872 | |||
1873 | // calculate distance from vert0 to ray origin | ||
1874 | SUB(tvec, orig, vert0); | ||
1875 | |||
1876 | // calculate U parameter and test bounds | ||
1877 | *u = DOT(tvec, pvec) * inv_det; | ||
1878 | if ((*u < 0.0) || (*u > 1.0)) | ||
1879 | return 0; | ||
1880 | |||
1881 | // prepare to test V parameter | ||
1882 | CROSS(qvec, tvec, edge1); | ||
1883 | |||
1884 | // calculate V parameter and test bounds | ||
1885 | *v = DOT(dir, qvec) * inv_det; | ||
1886 | if ((*v < 0.0) || ((*u + *v) > 1.0)) | ||
1887 | return 0; | ||
1888 | |||
1889 | // calculate t, ray intersects triangle | ||
1890 | *t = DOT(edge2, qvec) * inv_det; | ||
1891 | |||
1892 | return 1; | ||
1893 | } | ||
1894 | |||
1895 | |||
1896 | |||
1897 | static bool | ||
1898 | SimpleUnclippedTest(dVector3 in_CoplanarPt, dVector3 in_v, dVector3 in_elt, | ||
1899 | dVector3 in_n, dVector3* in_col_v, dReal &out_depth) | ||
1900 | { | ||
1901 | dReal dp = 0.0; | ||
1902 | dReal contact_elt_length; | ||
1903 | |||
1904 | DEPTH(dp, in_CoplanarPt, in_v, in_n); | ||
1905 | |||
1906 | if (dp >= 0.0) { | ||
1907 | // if the penetration depth (calculated above) is more than | ||
1908 | // the contact point's ELT, then we've chosen the wrong face | ||
1909 | // and should switch faces | ||
1910 | contact_elt_length = dFabs(dDOT(in_elt, in_n)); | ||
1911 | |||
1912 | if (dp == 0.0) | ||
1913 | dp = dMin(DISTANCE_EPSILON, contact_elt_length); | ||
1914 | |||
1915 | if ((contact_elt_length < SMALL_ELT) && (dp < EXPANDED_ELT_THRESH)) | ||
1916 | dp = contact_elt_length; | ||
1917 | |||
1918 | if ( (dp > 0.0) && (dp <= contact_elt_length)) { | ||
1919 | // Add a contact | ||
1920 | |||
1921 | if ( ExamineContactPoint(in_col_v, in_n, in_v) ) { | ||
1922 | out_depth = dp; | ||
1923 | return true; | ||
1924 | } | ||
1925 | } | ||
1926 | } | ||
1927 | |||
1928 | return false; | ||
1929 | } | ||
1930 | |||
1931 | |||
1932 | |||
1933 | |||
1934 | // Generate a "unique" contact. A unique contact has a unique | ||
1935 | // position or normal. If the potential contact has the same | ||
1936 | // position and normal as an existing contact, but a larger | ||
1937 | // penetration depth, this new depth is used instead | ||
1938 | // | ||
1939 | static void | ||
1940 | GenerateContact(int in_Flags, dContactGeom* in_Contacts, int in_Stride, | ||
1941 | dxTriMesh* in_TriMesh1, dxTriMesh* in_TriMesh2, | ||
1942 | const dVector3 in_ContactPos, const dVector3 in_Normal, dReal in_Depth, | ||
1943 | int& OutTriCount) | ||
1944 | { | ||
1945 | /* | ||
1946 | NOTE by Oleh_Derevenko: | ||
1947 | This function is called after maximal number of contacts has already been | ||
1948 | collected because it has a side effect of replacing penetration depth of | ||
1949 | existing contact with larger penetration depth of another matching normal contact. | ||
1950 | If this logic is not necessary any more, you can bail out on reach of contact | ||
1951 | number maximum immediately in dCollideTTL(). You will also need to correct | ||
1952 | conditional statements after invocations of GenerateContact() in dCollideTTL(). | ||
1953 | */ | ||
1954 | dIASSERT(in_Depth >= 0.0); | ||
1955 | //if (in_Depth < 0.0) -- the function is always called with depth >= 0 | ||
1956 | // return; | ||
1957 | |||
1958 | do | ||
1959 | { | ||
1960 | dContactGeom* Contact; | ||
1961 | dVector3 diff; | ||
1962 | |||
1963 | if (!(in_Flags & CONTACTS_UNIMPORTANT)) | ||
1964 | { | ||
1965 | bool duplicate = false; | ||
1966 | |||
1967 | for (int i=0; i<OutTriCount; i++) | ||
1968 | { | ||
1969 | Contact = SAFECONTACT(in_Flags, in_Contacts, i, in_Stride); | ||
1970 | |||
1971 | // same position? | ||
1972 | SUB(diff, in_ContactPos, Contact->pos); | ||
1973 | if (dDOT(diff, diff) < dEpsilon) | ||
1974 | { | ||
1975 | // same normal? | ||
1976 | if (dFabs(dDOT(in_Normal, Contact->normal)) > (REAL(1.0)-dEpsilon)) | ||
1977 | { | ||
1978 | if (in_Depth > Contact->depth) { | ||
1979 | Contact->depth = in_Depth; | ||
1980 | SMULT( Contact->normal, in_Normal, -1.0); | ||
1981 | Contact->normal[3] = 0.0; | ||
1982 | } | ||
1983 | duplicate = true; | ||
1984 | /* | ||
1985 | NOTE by Oleh_Derevenko: | ||
1986 | There may be a case when two normals are close to each other but no duplicate | ||
1987 | while third normal is detected to be duplicate for both of them. | ||
1988 | This is the only reason I can think of, there is no "break" statement. | ||
1989 | Perhaps author considered it to be logical that the third normal would | ||
1990 | replace the depth in both of initial contacts. | ||
1991 | However, I consider it a questionable practice which should not | ||
1992 | be applied without deep understanding of underlaying physics. | ||
1993 | Even more, is this situation with close normal triplet acceptable at all? | ||
1994 | Should not be two initial contacts reduced to one (replaced with the latter)? | ||
1995 | If you know the answers for these questions, you may want to change this code. | ||
1996 | See the same statement in GenerateContact() of collision_trimesh_box.cpp | ||
1997 | */ | ||
1998 | } | ||
1999 | } | ||
2000 | } | ||
2001 | |||
2002 | if (duplicate || OutTriCount == (in_Flags & NUMC_MASK)) | ||
2003 | { | ||
2004 | break; | ||
2005 | } | ||
2006 | } | ||
2007 | else | ||
2008 | { | ||
2009 | dIASSERT(OutTriCount < (in_Flags & NUMC_MASK)); | ||
2010 | } | ||
2011 | |||
2012 | // Add a new contact | ||
2013 | Contact = SAFECONTACT(in_Flags, in_Contacts, OutTriCount, in_Stride); | ||
2014 | |||
2015 | SET( Contact->pos, in_ContactPos ); | ||
2016 | Contact->pos[3] = 0.0; | ||
2017 | |||
2018 | SMULT( Contact->normal, in_Normal, -1.0); | ||
2019 | Contact->normal[3] = 0.0; | ||
2020 | |||
2021 | Contact->depth = in_Depth; | ||
2022 | |||
2023 | Contact->g1 = in_TriMesh1; | ||
2024 | Contact->g2 = in_TriMesh2; | ||
2025 | |||
2026 | OutTriCount++; | ||
2027 | } | ||
2028 | while (false); | ||
2029 | } | ||
2030 | |||
2031 | #endif // dTRIMESH_OPCODE | ||
2032 | #endif // !dTRIMESH_USE_NEW_TRIMESH_TRIMESH_COLLIDER | ||
2033 | #endif // dTRIMESH_ENABLED | ||