00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include <physics/OBBCollisionDetector>
00026 #include <base/Quat4>
00027
00028 using physics::OBBCollisionDetector;
00029 using physics::CollisionState;
00030 using physics::CollisionModelProvider;
00031 using base::Vector3;
00032 using base::Matrix3;
00033 using base::transpose;
00034 using base::inverse;
00035 using base::cross;
00036 using gfx::Triangle3;
00037
00038
00039
00040
00041 bool OBBCollisionDetector::collision(ref<const Solid> solid1, ref<const Solid> solid2, CollisionQueryType queryType)
00042 {
00043 if (!collisionDetectionEnabled) return false;
00044 if (queryType == PotentialCollision) return true;
00045
00046 ref<const OBBCollisionModel> model1
00047 = narrow_ref<const OBBCollisionModel>(solid1->getCollisionModel(getType()));
00048 ref<const OBBCollisionModel> model2
00049 = narrow_ref<const OBBCollisionModel>(solid2->getCollisionModel(getType()));
00050
00051 Matrix3 R1 = Matrix4(solid1->getOrientation());
00052 Matrix3 R2 = Matrix4(solid2->getOrientation());
00053 const Vector3& T1(solid1->getPosition());
00054 const Vector3& T2(solid2->getPosition());
00055
00056
00057 Collide(R1, T1, model1, R2, T2, model2, queryType);
00058
00059
00060
00061
00062
00063 double R1a[3][3];
00064 R1a[0][0] = R1(1,1); R1a[0][1] = R1(1,2); R1a[0][2] = R1(1,3);
00065 R1a[1][0] = R1(2,1); R1a[1][1] = R1(2,2); R1a[1][2] = R1(2,3);
00066 R1a[2][0] = R1(3,1); R1a[2][1] = R1(3,2); R1a[2][2] = R1(3,3);
00067 double R2a[3][3];
00068 R2a[0][0] = R2(1,1); R2a[0][1] = R2(1,2); R2a[0][2] = R2(1,3);
00069 R2a[1][0] = R2(2,1); R2a[1][1] = R2(2,2); R2a[1][2] = R2(2,3);
00070 R2a[2][0] = R2(3,1); R2a[2][1] = R2(3,2); R2a[2][2] = R2(3,3);
00071
00072 double T1a[3]; T1a[0] = T1[1]; T1a[1] = T1[2]; T1a[2] = T1[3];
00073 double T2a[3]; T2a[0] = T2[1]; T2a[1] = T2[2]; T2a[2] = T2[3];
00074
00075
00076 ref<CollisionState> collisionState = getCollisionState(solid1,solid2);
00077 ref<OBBCollisionState> state = narrow_ref<OBBCollisionState>(collisionState);
00078 state->contacts.clear();
00079
00080
00081 if ( ((queryType == FirstContactPoint)
00082 || (queryType == AllContactPoints))
00083 && contacts.size() > 0) {
00084
00085 Int i=0;
00086 do {
00087 Triangle3 t1 = contacts[i].first;
00088 Triangle3 t2 = contacts[i].second;
00089
00090
00091 Vector3 normal1(t1.normal());
00092
00093
00094 t1.transform(R1); t1 += T1;
00095 t2.transform(R2); t2 += T2;
00096
00097 Point3 contactPoint;
00098
00099 if (contactPoint == Point3()) {
00100
00101 contactPoint = (t2[1]+t2[2]+t2[3])/3.0;
00102 }
00103
00104 Point3 contact1(contactPoint-T1);
00105 contact1 = inverse(R1)*contact1;
00106 Point3 contact2(contactPoint-T2);
00107 contact2 = inverse(R2)*contact2;
00108
00109
00110
00111
00112
00113
00114
00115 state->contacts.push_back(CollisionState::Contact(contact1,contact2,normal1));
00116
00117 i++;
00118 } while ((i < contacts.size()) && (queryType == AllContactPoints));
00119
00120 }
00121
00122 return (contacts.size() > 0);
00123 }
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133 void OBBCollisionDetector::Collide(const base::Matrix3& R1, const gfx::Vector3& T1,
00134 ref<const OBBCollisionModel> model1,
00135 const base::Matrix3& R2, const gfx::Vector3& T2,
00136 ref<const OBBCollisionModel> model2,
00137 CollisionQueryType queryType)
00138 {
00139 Collide(R1,T1,1.0,model1,R2,T2,1.0,model2,queryType);
00140 }
00141
00142
00143 void OBBCollisionDetector::Collide(const base::Matrix3& R1, const gfx::Vector3& T1, Real s1,
00144 ref<const OBBCollisionModel> model1,
00145 const base::Matrix3& R2, const gfx::Vector3& T2, Real s2,
00146 ref<const OBBCollisionModel> model2,
00147 CollisionQueryType queryType)
00148 {
00149
00150 numBoxTests = 0;
00151 numTriTests = 0;
00152 contacts.clear();
00153
00154 if (model1->tris.empty() || model2->tris.empty()) return;
00155
00156 const OBBCollisionModel::OBB& b1(model1->b[0]);
00157 const OBBCollisionModel::OBB& b2(model2->b[0]);
00158
00159 firstContact = (queryType==DetectCollision) || (queryType==FirstContactPoint);
00160
00161 Matrix3 tR1, tR2, R;
00162 Vector3 tT1, tT2, T, U;
00163 Real s;
00164
00165
00166
00167
00168
00169
00170 tR1 = R1*b1.pR;
00171 tT1 = (s1*R1)*b1.pT+T1;
00172 tR2 = R2*b2.pR;
00173 tT2 = (s2*R2)*b2.pT+T2;
00174
00175
00176
00177
00178 R = transpose(tR1)*tR2;
00179 U = tT2-tT1;
00180 T = (transpose(tR1)*U)/s1;
00181
00182 s = s2/s1;
00183
00184
00185
00186 mR = transpose(R2)*R1;
00187 U = T1-T2;
00188 mT = (transpose(R2)*U)/s2;
00189 ms = s1/s2;
00190
00191
00192 collideRecursive(b1, b2, R, T, s);
00193
00194 }
00195
00196
00197 void OBBCollisionDetector::collideRecursive(const OBBCollisionModel::OBB& b1,
00198 const OBBCollisionModel::OBB& b2,
00199 const base::Matrix3& R, const base::Vector3& T, double s)
00200 {
00201 if ((firstContact) && (contacts.size() > 0)) return;
00202
00203
00204 numBoxTests++;
00205
00206 Vector3 d(s*b2.d);
00207 Int f1 = OBBDisjoint(R, T, b1.d, d);
00208
00209 if (f1 != 0)
00210 return;
00211
00212
00213 if (b1.leaf() && b2.leaf()) {
00214
00215
00216
00217
00218 triContact(b1, b2);
00219 return;
00220 }
00221
00222 Vector3 U;
00223 Matrix3 cR;
00224 Vector3 cT;
00225 Real cs;
00226
00227
00228
00229
00230 if (b2.leaf() || (!b1.leaf() && (b1.size() > b2.size()))) {
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241 cR = transpose(b1.N->pR)*R;
00242 U=T-b1.N->pT;
00243 cT = transpose(b1.N->pR)*U;
00244 cs = s;
00245
00246 collideRecursive(*b1.N, b2, cR, cT, cs);
00247
00248 cR = transpose(b1.P->pR)*R;
00249 U=T-b1.P->pT;
00250 cT=transpose(b1.P->pR)*U;
00251 cs = s;
00252
00253 collideRecursive(*b1.P, b2, cR, cT, cs);
00254
00255 return;
00256 }
00257 else {
00258
00259
00260
00261 cR = R*b2.N->pR;
00262 cT = (s*R)*b2.N->pT+T;
00263 cs = s;
00264
00265 collideRecursive(b1, *b2.N, cR, cT, cs);
00266
00267 cR = R*b2.P->pR;
00268 cT = (s*R)*b2.P->pT+T;
00269 cs = s;
00270
00271 collideRecursive(b1, *b2.P, cR, cT, cs);
00272
00273 return;
00274 }
00275 }
00276
00277
00278 void OBBCollisionDetector::triContact(const OBBCollisionModel::OBB& b1,
00279 const OBBCollisionModel::OBB& b2)
00280 {
00281
00282
00283
00284
00285
00286 p1 = b1.tr.p1();
00287 p2 = b1.tr.p2();
00288 p3 = b1.tr.p3();
00289
00290 Matrix3 msR(ms*mR);
00291 i1 = msR*p1+mT;
00292 i2 = msR*p2+mT;
00293 i3 = msR*p3+mT;
00294
00295 numTriTests++;
00296
00297 if (triContact(i1, i2, i3, b2.tr.p1(), b2.tr.p2(), b2.tr.p3()))
00298 contacts.push_back(std::pair<Triangle3,Triangle3>(b1.tr, b2.tr));
00299 }
00300
00301
00302 bool OBBCollisionDetector::triContact(const base::Vector3& P1, const base::Vector3& P2, const base::Vector3& P3,
00303 const base::Point3& Q1, const base::Point3& Q2, const base::Point3& Q3)
00304 {
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316 z.setZero();
00317
00318 p1 = P1-P1;
00319 p2 = P2-P1;
00320 p3 = P3-P1;
00321
00322 q1 = Q1-P1;
00323 q2 = Q2-P1;
00324 q3 = Q3-P1;
00325
00326 e1 = p2-p1;
00327 e2 = p3-p2;
00328 e3 = p1-p3;
00329
00330 f1 = q2-q1;
00331 f2 = q3-q2;
00332 f3 = q1-q3;
00333
00334 n1.cross(e1, e2);
00335 m1.cross(f1, f2);
00336
00337 g1.cross(e1, n1);
00338 g2.cross(e2, n1);
00339 g3.cross(e3, n1);
00340 h1.cross(f1, m1);
00341 h2.cross(f2, m1);
00342 h3.cross(f3, m1);
00343
00344 ef11.cross(e1, f1);
00345 ef12.cross(e1, f2);
00346 ef13.cross(e1, f3);
00347 ef21.cross(e2, f1);
00348 ef22.cross(e2, f2);
00349 ef23.cross(e2, f3);
00350 ef31.cross(e3, f1);
00351 ef32.cross(e3, f2);
00352 ef33.cross(e3, f3);
00353
00354
00355
00356 if (!project6(n1, p1, p2, p3, q1, q2, q3)) return false;
00357 if (!project6(m1, p1, p2, p3, q1, q2, q3)) return false;
00358
00359 if (!project6(ef11, p1, p2, p3, q1, q2, q3)) return false;
00360 if (!project6(ef12, p1, p2, p3, q1, q2, q3)) return false;
00361 if (!project6(ef13, p1, p2, p3, q1, q2, q3)) return false;
00362 if (!project6(ef21, p1, p2, p3, q1, q2, q3)) return false;
00363 if (!project6(ef22, p1, p2, p3, q1, q2, q3)) return false;
00364 if (!project6(ef23, p1, p2, p3, q1, q2, q3)) return false;
00365 if (!project6(ef31, p1, p2, p3, q1, q2, q3)) return false;
00366 if (!project6(ef32, p1, p2, p3, q1, q2, q3)) return false;
00367 if (!project6(ef33, p1, p2, p3, q1, q2, q3)) return false;
00368
00369 if (!project6(g1, p1, p2, p3, q1, q2, q3)) return false;
00370 if (!project6(g2, p1, p2, p3, q1, q2, q3)) return false;
00371 if (!project6(g3, p1, p2, p3, q1, q2, q3)) return false;
00372 if (!project6(h1, p1, p2, p3, q1, q2, q3)) return false;
00373 if (!project6(h2, p1, p2, p3, q1, q2, q3)) return false;
00374 if (!project6(h3, p1, p2, p3, q1, q2, q3)) return false;
00375
00376 return true;
00377 }
00378
00379
00380 bool OBBCollisionDetector::project6(const Vector3& ax,
00381 const Vector3& p1, const Vector3& p2, const Vector3& p3,
00382 const Vector3& q1, const Vector3& q2, const Vector3& q3) const
00383 {
00384 Real P1 = ax.dot(p1);
00385 Real P2 = ax.dot(p2);
00386 Real P3 = ax.dot(p3);
00387 Real Q1 = ax.dot(q1);
00388 Real Q2 = ax.dot(q2);
00389 Real Q3 = ax.dot(q3);
00390
00391 Real mx1 = Math::maximum(P1, P2, P3);
00392 Real mn1 = Math::minimum(P1, P2, P3);
00393 Real mx2 = Math::maximum(Q1, Q2, Q3);
00394 Real mn2 = Math::minimum(Q1, Q2, Q3);
00395
00396 if (mn1 > mx2) return false;
00397 if (mn2 > mx1) return false;
00398 return true;
00399 }
00400
00401
00402 Int OBBCollisionDetector::OBBDisjoint(const base::Matrix3& B, const gfx::Vector3& T,
00403 const base::Vector3& a, const gfx::Vector3& b)
00404 {
00405 Real t, s;
00406
00407
00408 const Real reps = CollisionDetector::collisionEpsilon;
00409 Bf.e(1,1) = base::abs(B.e(1,1)); Bf.e(1,1) += reps;
00410 Bf.e(1,2) = base::abs(B.e(1,2)); Bf.e(1,2) += reps;
00411 Bf.e(1,3) = base::abs(B.e(1,3)); Bf.e(1,3) += reps;
00412 Bf.e(2,1) = base::abs(B.e(2,1)); Bf.e(2,1) += reps;
00413 Bf.e(2,2) = base::abs(B.e(2,2)); Bf.e(2,2) += reps;
00414 Bf.e(2,3) = base::abs(B.e(2,3)); Bf.e(2,3) += reps;
00415 Bf.e(3,1) = base::abs(B.e(3,1)); Bf.e(3,1) += reps;
00416 Bf.e(3,2) = base::abs(B.e(3,2)); Bf.e(3,2) += reps;
00417 Bf.e(3,3) = base::abs(B.e(3,3)); Bf.e(3,3) += reps;
00418
00419
00420
00421
00422 t = base::abs(T.x);
00423
00424 if (!(t <= (a.x + b.x * Bf.e(1,1) + b.y * Bf.e(1,2) + b.z * Bf.e(1,3)))) return 1;
00425
00426
00427 s = T.x*B.e(1,1) + T.y*B.e(2,1) + T.z*B.e(3,1);
00428 t = base::abs(s);
00429
00430 if (!(t <= (b.x + a.x * Bf.e(1,1) + a.y * Bf.e(2,1) + a.z * Bf.e(3,1)))) return 2;
00431
00432
00433 t = base::abs(T.y);
00434
00435 if (!(t <= (a.y + b.x * Bf.e(2,1) + b.y * Bf.e(2,2) + b.z * Bf.e(2,3)))) return 3;
00436
00437
00438 t = base::abs(T.z);
00439
00440 if (!(t <= (a.z + b.x * Bf.e(3,1) + b.y * Bf.e(3,2) + b.z * Bf.e(3,3)))) return 4;
00441
00442
00443 s = T.x*B.e(1,2) + T.y*B.e(2,2) + T.z*B.e(3,2);
00444 t = base::abs(s);
00445
00446 if (!(t <=(b.y + a.x * Bf.e(1,2) + a.y * Bf.e(2,2) + a.z * Bf.e(3,2)))) return 5;
00447
00448
00449 s = T.x*B.e(1,3) + T.y*B.e(2,3) + T.z*B.e(3,3);
00450 t = base::abs(s);
00451
00452 if (!(t <= (b.z + a.x * Bf.e(1,3) + a.y * Bf.e(2,3) + a.z * Bf.e(3,3)))) return 6;
00453
00454
00455 s = T.z * B.e(2,1) - T.y * B.e(3,1);
00456 t = base::abs(s);
00457
00458 if (!(t <= (a.y * Bf.e(3,1) + a.z * Bf.e(2,1) + b.y * Bf.e(1,3) + b.z * Bf.e(1,2)))) return 7;
00459
00460
00461 s = T.z * B.e(2,2) - T.y * B.e(3,2);
00462 t = base::abs(s);
00463
00464 if (!(t <= (a.y * Bf.e(3,2) + a.z * Bf.e(2,2) + b.x * Bf.e(1,3) + b.z * Bf.e(1,1)))) return 8;
00465
00466
00467 s = T.z * B.e(2,3) - T.y * B.e(3,3);
00468 t = base::abs(s);
00469
00470 if (!(t <= (a.y * Bf.e(3,3) + a.z * Bf.e(2,3) + b.x * Bf.e(1,2) + b.y * Bf.e(1,1)))) return 9;
00471
00472
00473 s = T.x * B.e(3,1) - T.z * B.e(1,1);
00474 t = base::abs(s);
00475
00476 if (!(t <= (a.x * Bf.e(3,1) + a.z * Bf.e(1,1) + b.y * Bf.e(2,3) + b.z * Bf.e(2,2)))) return 10;
00477
00478
00479 s = T.x * B.e(3,2) - T.z * B.e(1,2);
00480 t = base::abs(s);
00481
00482 if (!(t <=(a.x * Bf.e(3,2) + a.z * Bf.e(1,2) + b.x * Bf.e(2,3) + b.z * Bf.e(2,1)))) return 11;
00483
00484
00485 s = T.x * B.e(3,3) - T.z * B.e(1,3);
00486 t = base::abs(s);
00487
00488 if (!(t <= (a.x * Bf.e(3,3) + a.z * Bf.e(1,3) + b.x * Bf.e(2,2) + b.y * Bf.e(2,1)))) return 12;
00489
00490
00491 s = T.y * B.e(1,1) - T.x * B.e(2,1);
00492 t = base::abs(s);
00493
00494 if (!(t <= (a.x * Bf.e(2,1) + a.y * Bf.e(1,1) + b.y * Bf.e(3,3) + b.z * Bf.e(3,2)))) return 13;
00495
00496
00497 s = T.y * B.e(1,2) - T.x * B.e(2,2);
00498 t = base::abs(s);
00499
00500 if (!(t <=(a.x * Bf.e(2,2) + a.y * Bf.e(1,2) + b.x * Bf.e(3,3) + b.z * Bf.e(3,1)))) return 14;
00501
00502
00503 s = T.y * B.e(1,3) - T.x * B.e(2,3);
00504 t = base::abs(s);
00505
00506 if (!(t <=(a.x * Bf.e(2,3) + a.y * Bf.e(1,3) + b.x * Bf.e(3,2) + b.y * Bf.e(3,1)))) return 15;
00507
00508 return 0;
00509
00510 }