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 }