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/OBBCollisionModel>
00026
00027 #include <physics/Box>
00028 #include <gfx/TriangleContainer>
00029 #include <gfx/TriangleIterator>
00030 #include <gfx/Triangle3>
00031 #include <gfx/Color4>
00032
00033 #include <osg/Node>
00034 #include <osg/Group>
00035 #include <osg/MatrixTransform>
00036 #include <osg/StateSet>
00037 #include <osg/Material>
00038 #include <osg/Vec4>
00039 #include <osg/PolygonMode>
00040
00041
00042
00043 using physics::OBBCollisionModel;
00044 using physics::Box;
00045
00046 using gfx::Triangle3;
00047 using gfx::Color4;
00048 using gfx::TriangleContainer;
00049 using gfx::TriangleIterator;
00050
00051 using base::Matrix3;
00052 using base::transpose;
00053 using base::cross;
00054 using base::array;
00055
00056 using osg::Vec4;
00057 using osg::StateSet;
00058
00059
00060 OBBCollisionModel::OBBCollisionModel(const gfx::TriangleContainer& triangles)
00061 : b(*new base::array<OBB>()), tris(*new base::array<Triangle3>())
00062 {
00063
00064 Int id=0;
00065
00066 TriangleContainer::const_iterator t = triangles.begin();
00067 TriangleContainer::const_iterator end = triangles.end();
00068 while (t != end) {
00069 tris.at(id++) = (*t);
00070 ++t;
00071 }
00072 tris.trim();
00073
00074 if (!tris.empty()) {
00075 buildHierarchy();
00076 }
00077
00078 }
00079
00080 OBBCollisionModel::OBBCollisionModel(const OBBCollisionModel& cm)
00081 : b(*new base::array<OBB>(cm.b)),
00082 tris(*new base::array<Triangle3>(cm.tris))
00083 {
00084 }
00085
00086 OBBCollisionModel::~OBBCollisionModel()
00087 {
00088 delete &tris;
00089 delete &b;
00090 }
00091
00092
00093 void OBBCollisionModel::buildHierarchy()
00094 {
00095 array<Moment> moment(tris.size());
00096 array<OBB>& boxes(b);
00097 Int OBBsInited = 1;
00098 boxes.resize(tris.size()*2);
00099
00100
00101 Moment M;
00102 Matrix3 C;
00103
00104 Moment::computeMoment(moment, tris, 0, tris.size());
00105
00106 M.clear();
00107 for(Int i=0; i<tris.size(); i++) {
00108 M.accumulate(moment[i]);
00109 }
00110
00111 b[0].pT = M.meanFromAccum();
00112 C = M.covariance();
00113
00114 eigenAndSort1(b[0].pR, C);
00115
00116
00117 Int* t = new Int[tris.size()];
00118 for(Int i=0; i<tris.size(); i++) t[i]=i;
00119
00120
00121 OBBsInited = b[0].splitRecurse(tris,moment,boxes,OBBsInited,t,0,tris.size());
00122
00123 delete[] t;
00124 }
00125
00126
00127 Int OBBCollisionModel::eigenAndSort1(Matrix3& evecs, const Matrix3& cov, Int maxIterations)
00128 {
00129 Vector3 evals;
00130
00131 Int n = cov.eigenJacobi(evecs, evals, maxIterations);
00132
00133
00134 if (evals.z > evals.x) {
00135 if (evals.z > evals.y) {
00136
00137 evecs.swapColumns(3,1);
00138 }
00139 else {
00140
00141 evecs.swapColumns(2,1);
00142 }
00143 }
00144 else {
00145 if (evals.x > evals.y) {
00146
00147 }
00148 else {
00149
00150 evecs.swapColumns(1,2);
00151 }
00152 }
00153
00154
00155
00156 return n;
00157 }
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169 void OBBCollisionModel::OBB::reaccumMoments(Moment& A, base::array<Moment>& moment,
00170 Int t[], Int f, Int n)
00171 {
00172 A.clear();
00173 for(Int i=0;i<n;i++)
00174 A.accumulate(moment[t[f+i]]);
00175 }
00176
00177
00178 Int OBBCollisionModel::OBB::splitRecurse(base::array<gfx::Triangle3>& tri,
00179 base::array<Moment>& moment,
00180 base::array<OBB>& boxes,
00181 Int OBBsInited, Int t[], Int f, Int n)
00182 {
00183
00184
00185
00186
00187
00188
00189
00190
00191 if (n == 1)
00192 return splitRecurse(tri,moment,boxes,OBBsInited,t,f);
00193
00194
00195
00196
00197
00198
00199
00200 Moment M1, M2;
00201 Matrix3 C;
00202 Vector3 c;
00203 Vector3 minval, maxval;
00204
00205 Int in;
00206 Int i;
00207 Real axdmp;
00208 Int n1 = 0;
00209
00210
00211
00212 axdmp = (pR.e(1,1) * pT.x + pR.e(2,1) * pT.y + pR.e(3,1) * pT.z);
00213
00214 M1.clear();
00215 M2.clear();
00216
00217 Matrix3 pRT = transpose(pR);
00218
00219 c = pRT * tri[t[f]].p1();
00220
00221 minval = c;
00222 maxval = c;
00223
00224 for(i=0; i<n; i++) {
00225 in = t[f+i];
00226 Triangle3& ptr(tri[in]);
00227
00228 c = pRT*ptr.p1();
00229 minmax(minval, maxval, c);
00230
00231 c = pRT*ptr.p2();
00232 minmax(minval, maxval, c);
00233
00234 c = pRT*ptr.p3();
00235 minmax(minval, maxval, c);
00236
00237
00238
00239
00240 c = moment[in].meanFromMoment();
00241
00242 if ( (((pR.e(1,1)*c.x + pR.e(2,1)*c.y + pR.e(3,1)*c.z) < axdmp)
00243 && (n!=2)) || ((n==2) && (i==0)) ) {
00244
00245 M1.accumulate(moment[in]);
00246
00247
00248 Int temp = t[f+i];
00249 t[f+i] = t[f+n1];
00250 t[f+n1] = temp;
00251 n1++;
00252 }
00253 else {
00254
00255 M2.accumulate(moment[in]);
00256
00257
00258
00259 }
00260 }
00261
00262
00263
00264
00265 if ((n1 == 0) || (n1 == n)) {
00266
00267
00268
00269
00270 n1 = n/2;
00271
00272
00273 reaccumMoments(M1, moment, t, f, n1);
00274 reaccumMoments(M2, moment, t, f + n1, n - n1);
00275 }
00276
00277
00278
00279
00280 c = (minval+maxval)/2.0;
00281
00282 pT = pR*c;
00283 d = (maxval-minval)/2.0;
00284
00285
00286 P = &boxes[OBBsInited++];
00287 N = &boxes[OBBsInited++];
00288
00289
00290
00291
00292
00293 Matrix3 tR;
00294
00295
00296 if (n1 > 1) {
00297 P->pT = M1.meanFromAccum();
00298 C = M1.covariance();
00299
00300 if (OBBCollisionModel::eigenAndSort1(tR, C, 30) >= 30) {
00301
00302 tR.setIdentity();
00303 }
00304
00305 P->pR = tR;
00306 OBBsInited = P->splitRecurse(tri, moment, boxes, OBBsInited, t, f, n1);
00307 }
00308 else {
00309 OBBsInited = P->splitRecurse(tri, moment, boxes, OBBsInited, t, f);
00310 }
00311 C = P->pR; P->pR = transpose(pR)*C;
00312 c = P->pT - pT; P->pT = transpose(pR)*c;
00313
00314
00315 if ((n-n1) > 1) {
00316 N->pT = M2.meanFromAccum();
00317 C = M2.covariance();
00318
00319 if (OBBCollisionModel::eigenAndSort1(tR, C) > 30) {
00320
00321 tR.setIdentity();
00322 }
00323
00324 N->pR = tR;
00325 OBBsInited = N->splitRecurse(tri, moment, boxes, OBBsInited, t, f + n1, n - n1);
00326 }
00327 else {
00328 OBBsInited = N->splitRecurse(tri, moment, boxes, OBBsInited, t, f+n1);
00329 }
00330 C = N->pR; N->pR = transpose(pR)*C;
00331 c = N->pT-pT; N->pT = transpose(pR)*c;
00332
00333 return OBBsInited;
00334 }
00335
00336
00337
00338 Int OBBCollisionModel::OBB::splitRecurse(base::array<gfx::Triangle3>& tri,
00339 base::array<Moment>& moment,
00340 base::array<OBB>& boxes,
00341 Int OBBsInited, Int t[], Int f)
00342 {
00343
00344
00345
00346
00347
00348
00349
00350 P = N = 0;
00351 Triangle3& ptr(tri[t[f]]);
00352
00353
00354 Vector3 u12, u23, u31;
00355
00356
00357 u12 = ptr.p1()-ptr.p2();
00358 Real d12 = u12.norm();
00359 u23 = ptr.p2()-ptr.p3();
00360 Real d23 = u23.norm();
00361 u31 = ptr.p3()-ptr.p1();
00362 Real d31 = u31.norm();
00363
00364
00365
00366 Vector3 a0;
00367 if (d12 > d23) {
00368 if (d12 > d31)
00369 a0 = u12 / base::sqrt(d12);
00370 else
00371 a0 = u31 / base::sqrt(d31);
00372 }
00373 else {
00374 if (d23 > d31)
00375 a0 = u23 / base::sqrt(d23);
00376 else
00377 a0 = u31 / base::sqrt(d31);
00378 }
00379
00380
00381 Vector3 a2;
00382 a2 = cross(u12,u23);
00383 a2.normalize();
00384
00385
00386 Vector3 a1;
00387 a1 = cross(a2,a0);
00388
00389
00390 pR.e(1,1) = a0.x; pR.e(1,2) = a1.x; pR.e(1,3) = a2.x;
00391 pR.e(2,1) = a0.y; pR.e(2,2) = a1.y; pR.e(2,3) = a2.y;
00392 pR.e(3,1) = a0.z; pR.e(3,2) = a1.z; pR.e(3,3) = a2.z;
00393
00394
00395
00396
00397 Vector3 minval, maxval;
00398 Vector3 c;
00399
00400 c = transpose(pR)*ptr.p1();
00401 minval=c; maxval=c;
00402
00403 c = transpose(pR)*ptr.p2();
00404 minmax(minval, maxval, c);
00405
00406 c = transpose(pR)*ptr.p3();
00407 minmax(minval, maxval, c);
00408
00409
00410
00411 c = (minval+maxval)/2.0;
00412
00413 pT = pR*c;
00414 d = (maxval-minval)/2.0;
00415
00416
00417 tr = ptr;
00418
00419 return OBBsInited;
00420 }
00421
00422
00423 void OBBCollisionModel::OBB::minmax(gfx::Vector3& min, gfx::Vector3& max,
00424 const gfx::Vector3& v)
00425 {
00426 if (v.x < min.x)
00427 min.x = v.x;
00428 else
00429 if (v.x > max.x)
00430 max.x = v.x;
00431 if (v.y < min.y)
00432 min.y = v.y;
00433 else
00434 if (v.y > max.y)
00435 max.y = v.y;
00436 if (v.z < min.z)
00437 min.z = v.z;
00438 else
00439 if (v.z > max.z)
00440 max.z = v.z;
00441 }
00442
00443
00444
00445
00446
00447 void OBBCollisionModel::Moment::clear()
00448 {
00449 A = 0;
00450 m.setZero();
00451 s.setZero();
00452 }
00453
00454
00455 void OBBCollisionModel::Moment::accumulate(const Moment& b)
00456 {
00457 m += b.m*b.A;
00458 s += b.s;
00459 A += b.A;
00460 }
00461
00462
00463 base::Matrix3 OBBCollisionModel::Moment::covariance() const
00464 {
00465 base::Matrix3 C = s;
00466 C.e(1,1) -= m.x*m.x/A;
00467 C.e(1,2) -= m.x*m.y/A;
00468 C.e(1,3) -= m.x*m.z/A;
00469 C.e(2,1) -= m.y*m.x/A;
00470 C.e(2,2) -= m.y*m.y/A;
00471 C.e(2,3) -= m.y*m.z/A;
00472 C.e(3,1) -= m.z*m.x/A;
00473 C.e(3,2) -= m.z*m.y/A;
00474 C.e(3,3) -= m.z*m.z/A;
00475 return C;
00476 }
00477
00478
00479 void OBBCollisionModel::Moment::computeMoment(Moment& M, const base::Vector3& p,
00480 const base::Vector3& q, const base::Vector3& r)
00481 {
00482 Vector3 u,v,w;
00483
00484
00485 u = q-p;
00486 v = r-p;
00487 w = cross(u,v);
00488 M.A = 0.5*w.length();
00489
00490 if (M.A == 0.0) {
00491
00492
00493
00494
00495
00496
00497 M.m = (p+q+r)/3.0;
00498
00499
00500 M.s.e(1,1) = (p.x*p.x + q.x*q.x + r.x*r.x);
00501 M.s.e(1,2) = (p.x*p.y + q.x*q.y + r.x*r.y);
00502 M.s.e(1,3) = (p.x*p.z + q.x*q.z + r.x*r.z);
00503 M.s.e(2,2) = (p.y*p.y + q.y*q.y + r.y*r.y);
00504 M.s.e(2,3) = (p.y*p.z + q.y*q.z + r.y*r.z);
00505 M.s.e(3,3) = (p.z*p.z + q.z*q.z + r.z*r.z);
00506 M.s.e(3,2) = M.s.e(2,3);
00507 M.s.e(2,1) = M.s.e(1,2);
00508 M.s.e(3,1) = M.s.e(1,3);
00509
00510 return;
00511 }
00512
00513
00514 M.m = (p+q+r)/3.0;
00515
00516
00517 M.s.e(1,1) = M.A*(9.0*M.m.x*M.m.x+p.x*p.x+q.x*q.x+r.x*r.x)/12.0;
00518 M.s.e(1,2) = M.A*(9.0*M.m.x*M.m.y+p.x*p.y+q.x*q.y+r.x*r.y)/12.0;
00519 M.s.e(1,3) = M.A*(9.0*M.m.x*M.m.z+p.x*p.z+q.x*q.z+r.x*r.z)/12.0;
00520 M.s.e(2,2) = M.A*(9.0*M.m.y*M.m.y+p.y*p.y+q.y*q.y+r.y*r.y)/12.0;
00521 M.s.e(2,3) = M.A*(9.0*M.m.y*M.m.z+p.y*p.z+q.y*q.z+r.y*r.z)/12.0;
00522 M.s.e(3,3) = M.A*(9.0*M.m.z*M.m.z+p.z*p.z+q.z*q.z+r.z*r.z)/12.0;
00523 M.s.e(3,2) = M.s.e(2,3);
00524 M.s.e(2,1) = M.s.e(1,2);
00525 M.s.e(3,1) = M.s.e(1,3);
00526 }
00527
00528
00529 void OBBCollisionModel::Moment::computeMoment(base::array<Moment>& M,
00530 base::array<gfx::Triangle3>& tris,
00531 Int firstTri, Int numTris)
00532 {
00533
00534
00535
00536
00537 Real Amin = 0.0;
00538 bool zero=false;
00539
00540 Triangle3 tri;
00541 Moment m;
00542 for(Int i=firstTri; i<firstTri+numTris; i++) {
00543 Moment& m(M[i]);
00544 tri = tris[i];
00545 computeMoment(m, tri.p1(), tri.p2(), tri.p3());
00546
00547 if (m.A == 0.0)
00548 zero=true;
00549 else {
00550 if (Amin == 0.0)
00551 Amin = m.A;
00552 else
00553 if (m.A < Amin)
00554 Amin = m.A;
00555 }
00556
00557 }
00558
00559 if (zero) {
00560 Logfln("Warning: Some triangles have zero area.");
00561
00562
00563
00564
00565 if (Amin == 0.0) Amin = 1.0;
00566
00567 for(Int i=firstTri; i<firstTri+numTris; i++) {
00568 Moment& m(M[i]);
00569 if ( m.A == 0.0)
00570 m.A = Amin;
00571 }
00572 }
00573 }
00574
00575
00576
00577 osg::Node* OBBCollisionModel::createOSGVisual(Visual::Attributes visualAttributes) const
00578 {
00579 if (!(visualAttributes & ShowCollisionModel)
00580 || tris.empty() )
00581 return new osg::Node();
00582
00583 osg::Node* node = createOBBVisualRecurse(b[0], 0);
00584 node->setName("debug");
00585
00586
00587 StateSet* state = new osg::StateSet();
00588 osg::Material* mat = new osg::Material();
00589 Vec4 col( Math::random(), Math::random(), Math::random(), 1.0);
00590 mat->setEmission( osg::Material::FRONT_AND_BACK, Vec4(0,0,0,0) );
00591 mat->setAmbient( osg::Material::FRONT_AND_BACK, col );
00592 mat->setDiffuse( osg::Material::FRONT_AND_BACK, col );
00593 mat->setSpecular( osg::Material::FRONT_AND_BACK, Vec4(1,1,1,0) );
00594 mat->setShininess( osg::Material::FRONT_AND_BACK, 0.3);
00595 state->setAttribute( mat );
00596 state->setMode(GL_CULL_FACE,osg::StateAttribute::OFF);
00597
00598 osg::PolygonMode* polyMode = new osg::PolygonMode;
00599 polyMode->setMode( osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::LINE );
00600 state->setAttributeAndModes(polyMode,osg::StateAttribute::ON);
00601
00602 node->setStateSet(state);
00603
00604 return node;
00605 }
00606
00607 osg::Node* OBBCollisionModel::createOBBVisualRecurse(OBB& obb, Int level) const
00608 {
00609 const Real epsOffset = 0.01;
00610
00611 osg::MatrixTransform* tn = new osg::MatrixTransform();
00612 tn->setName("OBB");
00613
00614 Matrix4 m(obb.pR);
00615 m.setTranslationComponent(obb.pT);
00616 tn->setMatrix(m);
00617
00618 if (!onlyOneLevel || (onlyLevel==level)) {
00619 ref<Box> box(NewObj Box(2*obb.d.x+epsOffset,2*obb.d.y+epsOffset,2*obb.d.z+epsOffset));
00620 Debugln(Physics,"box leaf " << level);
00621 StateSet* state = new osg::StateSet();
00622 osg::Material* mat = new osg::Material();
00623 Vec4 col( Math::random(), Math::random(), Math::random(), 1.0);
00624 mat->setAmbient( osg::Material::FRONT_AND_BACK, col );
00625 mat->setDiffuse( osg::Material::FRONT_AND_BACK, col );
00626 state->setAttribute( mat );
00627
00628 osg::PolygonMode* polyMode = new osg::PolygonMode;
00629 polyMode->setMode( osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::LINE );
00630 state->setAttributeAndModes(polyMode,osg::StateAttribute::ON);
00631
00632 osg::Node* boxNode = box->createOSGVisual();
00633 boxNode->setStateSet(state);
00634 tn->addChild(boxNode);
00635 }
00636
00637 if (level < maxLevels) {
00638 if (obb.N != 0) {
00639 tn->addChild( createOBBVisualRecurse(*obb.N, level+1) );
00640 }
00641 if (obb.P != 0) {
00642 tn->addChild( createOBBVisualRecurse(*obb.P, level+1) );
00643 }
00644 }
00645
00646 return tn;
00647 }