00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00179 #include "../include/IPSA/SoWorldPhysics.h"
00180 #include "../include/IPSA/ipsaclasses.h"
00181
00182 #include <ode/ode.h>
00183
00184 #include <cassert>
00185
00186 SO_NODE_SOURCE(SoWorldPhysics);
00187
00188 bool SoWorldPhysics::bOdeColliderInitialised = false;
00189 bool SoWorldPhysics::bClassesInitialised = false;
00190
00191
00194 void SoWorldPhysics::initClass()
00195 {
00196
00197 SO_NODE_INIT_CLASS(SoWorldPhysics, SoSeparator, "Separator");
00198 SoWorldPhysics::Init();
00199 }
00200
00201
00205 void SoWorldPhysics::Init()
00206 {
00207 if (!bOdeColliderInitialised)
00208 {
00209 dInitODE();
00210 bOdeColliderInitialised = true;
00211 }
00212 }
00213
00214
00218 void SoWorldPhysics::DeInit()
00219 {
00220 if (bOdeColliderInitialised)
00221 {
00222 dCloseODE();
00223 bOdeColliderInitialised = false;
00224 }
00225 }
00226
00227
00235 SoWorldPhysics::SoWorldPhysics(const SbString& nodeName , int numChildren )
00236 : SoSeparator(numChildren),
00237 MAX_BODY_CONTACTS(64),
00238 DEFAULT_ODE_STEPSIZE(0.004f),
00239 connectionsSetUp(false)
00240 {
00241 SO_NODE_CONSTRUCTOR(SoWorldPhysics);
00242 isBuiltIn = TRUE;
00243
00244 SO_NODE_ADD_FIELD(gravity,(0.0f, -9.81f, 0.0f));
00245 SO_NODE_ADD_FIELD(ERP,(0.2f));
00246 SO_NODE_ADD_FIELD(CFM,(1e-8f));
00247 SO_NODE_ADD_FIELD(SoftCFM,(0.001f));
00248 SO_NODE_ADD_FIELD(SoftERP,(-1.0f));
00249 SO_NODE_ADD_FIELD(stepsize,(DEFAULT_ODE_STEPSIZE));
00250
00251 SO_NODE_ADD_FIELD(ContactApprox,(SoWorldPhysics::BOXFRICTION));
00252 SO_NODE_DEFINE_ENUM_VALUE(eContactApprox, BOXFRICTION);
00253 SO_NODE_DEFINE_ENUM_VALUE(eContactApprox, PYRAMIDFRICTION);
00254 SO_NODE_SET_SF_ENUM_TYPE(ContactApprox, eContactApprox);
00255
00256 SO_NODE_ADD_FIELD(stepping, (SoWorldPhysics::QUICKSTEP));
00257 SO_NODE_DEFINE_ENUM_VALUE(eStepping, WORLDSTEP);
00258 SO_NODE_DEFINE_ENUM_VALUE(eStepping, QUICKSTEP);
00259 SO_NODE_DEFINE_ENUM_VALUE(eStepping, STEPFAST1);
00260 SO_NODE_SET_SF_ENUM_TYPE(stepping, eStepping);
00261 SO_NODE_ADD_FIELD(sf1maxiterations, (5));
00262
00263 ownworld = dWorldCreate();
00264 ownspace = dHashSpaceCreate (0);
00265 iContactFeedback.reserve(1000);
00266
00267 printf("World (%p) created\n\r", ownworld);
00268
00269 contactgroup= dJointGroupCreate (0);
00270 dWorldSetERP(ownworld, ERP.getValue());
00271 dWorldSetCFM(ownworld, CFM.getValue());
00272
00273 updateOdeParamtersSensor.setFunction(updateOdeParamtersCB);
00274 updateOdeParamtersSensor.setData(this);
00275
00276 updateOdeParamtersTrigger.appendConnection(&gravity);
00277 updateOdeParamtersTrigger.appendConnection(&ERP);
00278 updateOdeParamtersTrigger.appendConnection(&CFM);
00279 updateOdeParamtersTrigger.appendConnection(&stepsize);
00280
00281 setUpConnections(TRUE, TRUE);
00282
00283 sens.setFunction(SoWorldPhysics::StepOde);
00284 sens.setData(this);
00285
00286 this->setName(nodeName);
00287 }
00288
00289
00292 SoWorldPhysics::~SoWorldPhysics()
00293 {
00294
00295
00296
00297 printf("World (%p) deleted\n\r", ownworld);
00298 }
00299
00300
00311 void SoWorldPhysics::NearCallback (void* data, dGeomID o1, dGeomID o2)
00312 {
00313
00314 dBodyID body1 = dGeomGetBody(o1);
00315 dBodyID body2 = dGeomGetBody(o2);
00316 if (body1 && body2 && dAreConnectedExcluding (body1,body2,dJointTypeContact))
00317 return;
00318
00319
00320
00321
00322
00323 SoCollisionShape* colShape1 = static_cast<SoCollisionShape*>(dGeomGetData(o1));
00324 SoCollisionShape* colShape2 = static_cast<SoCollisionShape*>(dGeomGetData(o2));
00325
00326 int material1 = colShape1->surfaceMaterial.getValue();
00327 int material2 = colShape2->surfaceMaterial.getValue();
00328
00329 assert(SoCollisionShape::NO_OF_SURFACEMATERIALS > material1 && "SoWorldPhysics::NearCallback() invalid surfacematerial>max for geom1.");
00330 assert(0 <= material1 && "SoWorldPhysics::NearCallback() invalid surfacematerial<0 for geom1.");
00331 assert(SoCollisionShape::NO_OF_SURFACEMATERIALS > material2 && "SoWorldPhysics::NearCallback() invalid surfacematerial for geom2. ");
00332 assert(0 <= material2 && "SoWorldPhysics::NearCallback() invalid surfacematerial<0 for geom2.");
00333
00334 double mu = frictioncoeff[material1][material2];
00335 dReal ode_mu = dInfinity;
00336 if (mu < 1.0)
00337 ode_mu = static_cast<dReal>(mu/(1.0-mu));
00338
00339
00340 SoWorldPhysics* world = static_cast<SoWorldPhysics*> (data);
00341
00342 dContact* contact = new dContact[world->MAX_BODY_CONTACTS];
00343 int no_of_contacts = dCollide (o1, o2, world->MAX_BODY_CONTACTS, &contact[0].geom, sizeof(dContact));
00344 if (0 == no_of_contacts)
00345 return;
00346
00347 bool useFB = false;
00348 if (NULL != body1)
00349 {
00350 SoPhysics* pb1 = static_cast<SoPhysics*>(dBodyGetData(body1));
00351 useFB |= pb1->measureContactForces.getValue() == TRUE;
00352 }
00353 if (NULL != body2)
00354 {
00355 SoPhysics* pb2 = static_cast<SoPhysics*>(dBodyGetData(body2));
00356 useFB |= pb2->measureContactForces.getValue() == TRUE;
00357 }
00358
00359 for (int i = 0; i < no_of_contacts; i++)
00360 {
00361
00362 contact[i].surface.mode = dContactBounce | dContactSoftCFM | world->ContactApprox.getValue();
00363 if (world->SoftERP.getValue() >= 0.0)
00364 contact[i].surface.mode |= dContactSoftERP;
00365
00366 contact[i].surface.mu = ode_mu;
00367 contact[i].surface.mu2 = 0;
00368 contact[i].surface.bounce = 0.2f;
00369 contact[i].surface.bounce_vel = 0.1f;
00370 contact[i].surface.soft_cfm = world->SoftCFM.getValue();
00371 contact[i].surface.soft_erp = world->SoftERP.getValue();
00372
00373 dJointID c = dJointCreateContact (world->ownworld, world->contactgroup, contact + i);
00374 dJointAttach (c, body1, body2);
00375
00376
00377
00378
00379 if (useFB)
00380 {
00381 dJointFeedback dummy;
00382 world->iContactFeedback.push_back(dummy);
00383 dJointSetFeedback(c, &(world->iContactFeedback.back()) );
00384
00385
00386
00387
00388
00389 if (0.0f >= ode_mu || dInfinity <= ode_mu )
00390 continue;
00391
00392 dJointFeedback& jointFeedback = world->iContactFeedback.back();
00393 dVector3& forceVector = jointFeedback.f1;
00394 dVector3& normalVector = contact[i].geom.normal;
00395
00396 double normalForce = ( normalVector[0] * forceVector[0]
00397 + normalVector[2] * forceVector[2]
00398 + normalVector[2] * forceVector[2]);
00399 double radius = normalForce * ode_mu;
00400
00401 if(0 == normalForce || SoWorldPhysics::IsNaN(normalForce))
00402 continue;
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415 }
00416
00417
00418
00419 }
00420
00421 delete[] contact;
00422 }
00423
00424
00431 void SoWorldPhysics::updateOdeParamtersCB(void* data, SoSensor*)
00432 {
00433 SoWorldPhysics* world = static_cast<SoWorldPhysics*> (data);
00434
00435 if (NULL == world)
00436 return;
00437
00438 printf("updating world parameters\n");
00439 SbVec3f grav = world->gravity.getValue();
00440 dWorldSetGravity (world->ownworld, grav[0], grav[1], grav[2]);
00441
00442 float erp = world->ERP.getValue();
00443 dWorldSetERP(world->ownworld, erp);
00444
00445 float cfm = world->CFM.getValue();
00446 dWorldSetCFM(world->ownworld, cfm);
00447
00448 world->sens.setInterval(SbTime(world->getStepsize()));
00449 }
00450
00451
00460 SbBool SoWorldPhysics::setUpConnections(SbBool onOff, SbBool doItAlways)
00461 {
00462 if (!doItAlways && connectionsSetUp == onOff)
00463 return onOff;
00464 if (onOff)
00465 {
00466
00467 SoWorldPhysics::updateOdeParamtersCB(this, NULL);
00468
00469 if (&updateOdeParamtersTrigger != updateOdeParamtersSensor.getAttachedField())
00470 updateOdeParamtersSensor.attach(&updateOdeParamtersTrigger);
00471 }
00472 else
00473 {
00474 if (NULL != updateOdeParamtersSensor.getAttachedField())
00475 updateOdeParamtersSensor.detach();
00476 }
00477
00478 connectionsSetUp = onOff;
00479 return !connectionsSetUp;
00480 }
00481
00482
00492 SbBool SoWorldPhysics::readInstance(SoInput* in, unsigned short flags)
00493 {
00494 this->setUpConnections(FALSE, TRUE);
00495 SbBool resultValue = SoSeparator::readInstance(in, flags);
00496 this->setUpConnections(TRUE, TRUE);
00497 return resultValue;
00498 }
00499
00500
00509 SoCallbackAction::Response SoWorldPhysics::UpdateSingleWorldCB(void* userdata, SoCallbackAction* action, const SoNode* node)
00510 {
00511 SoWorldPhysics* world = dynamic_cast<SoWorldPhysics*> (const_cast<SoNode*> (node));
00512 assert(NULL != world && "SoWorldPhysics::UpdateSingleWorldCB(): no world present to operate on.");
00513
00514 dJointGroupEmpty (world->contactgroup);
00515 world->iContactFeedback.clear();
00516 SoFrictionCone::RemoveAllFrictionConesFromGraph(world);
00517
00518
00519
00520 dSpaceCollide (world->ownspace, world, &NearCallback);
00521
00522
00523 switch (world->stepping.getValue())
00524 {
00525 case (SoWorldPhysics::WORLDSTEP):
00526 dWorldStep (world->ownworld, world->stepsize.getValue());
00527 break;
00528 case (SoWorldPhysics::QUICKSTEP):
00529 dWorldQuickStep (world->ownworld, world->stepsize.getValue());
00530 break;
00531
00532
00533
00534 default:
00535 assert(0 && "Unknown stepping method, aborting.");
00536 break;
00537 };
00538
00539 return SoCallbackAction::CONTINUE;
00540 }
00541
00549 void SoWorldPhysics::StepOde(void* data, SoSensor*)
00550 {
00551 SoNode* n = static_cast<SoNode*> (data);
00552 if (NULL == n)
00553 {
00554 printf("No World available for stepping\n");
00555
00556 }
00557 SoCallbackAction updateODEAction;
00558 updateODEAction.addPostCallback(SoWorldPhysics::getClassTypeId(), UpdateSingleWorldCB,NULL);
00559 updateODEAction.addPostCallback(SoPhysics::getClassTypeId(), SoPhysics::UpdateOdeBodiesCB,NULL);
00560 updateODEAction.apply(n);
00561 }
00562
00563
00570 void SoWorldPhysics::resetWorld()
00571 {
00572
00573 SoCallbackAction resetBodyAction;
00574 resetBodyAction.addPreCallback(SoPhysics::getClassTypeId(), SoPhysics::ResetOdeBodiesCB, NULL);
00575 resetBodyAction.apply(this);
00576
00577
00578 SoCallbackAction initJoint;
00579 initJoint.addPreCallback(SoJoint::getClassTypeId(), SoJoint::InitOdeJointsCB,NULL);
00580 initJoint.apply(this);
00581
00582
00583 dJointGroupEmpty (this->contactgroup);
00584 this->iContactFeedback.clear();
00585 SoFrictionCone::RemoveAllFrictionConesFromGraph(this);
00586
00587 }
00588
00593 void SoWorldPhysics::initialiseWorld()
00594 {
00595
00596 SoCallbackAction initCollisionShapes;
00597 initCollisionShapes.addPostCallback(SoCollisionShape::getClassTypeId(), SoCollisionShape::InitCollisionShapesCB, this);
00598 initCollisionShapes.apply(this);
00599
00600
00601 SoCallbackAction initPhysicsBodies;
00602 initPhysicsBodies.addPostCallback(SoPhysics::getClassTypeId(), SoPhysics::InitialiseOdeBodiesCB, this);
00603 initPhysicsBodies.apply(this);
00604
00605
00606 SoCallbackAction initJoint;
00607 initJoint.addPreCallback(SoJoint::getClassTypeId(), SoJoint::InitOdeJointsCB,NULL);
00608 initJoint.apply(this);
00609 printf("World & bodies initialised\n\r");
00610 }
00611
00612
00621 SoCallbackAction::Response SoWorldPhysics::InitialiseWorldCB(void* userdata, SoCallbackAction* action, const SoNode* node)
00622 {
00623 SoWorldPhysics* world = dynamic_cast<SoWorldPhysics*> (const_cast<SoNode*> (node));
00624 if (NULL != world)
00625 world->initialiseWorld();
00626 return SoCallbackAction::CONTINUE;
00627 }
00628
00629
00638 SoCallbackAction::Response SoWorldPhysics::ResetWorldCB(void* userdata, SoCallbackAction* action, const SoNode* node)
00639 {
00640 SoWorldPhysics* world = dynamic_cast<SoWorldPhysics*> (const_cast<SoNode*> (node));
00641 if (NULL != world)
00642 world->resetWorld();
00643 return SoCallbackAction::CONTINUE;
00644 }
00645
00646
00655 SoCallbackAction::Response SoWorldPhysics::ScheduleWorldCB(void* userdata, SoCallbackAction* action, const SoNode* node)
00656 {
00657 SoWorldPhysics* world = dynamic_cast<SoWorldPhysics*> (const_cast<SoNode*> (node));
00658 if (NULL != world)
00659 world->schedule();
00660 return SoCallbackAction::CONTINUE;
00661 }
00662
00663
00672 SoCallbackAction::Response SoWorldPhysics::UnscheduleWorldCB(void* userdata, SoCallbackAction* action, const SoNode* node)
00673 {
00674 SoWorldPhysics* world = dynamic_cast<SoWorldPhysics*> (const_cast<SoNode*> (node));
00675 if (NULL != world)
00676 world->unschedule();
00677 return SoCallbackAction::CONTINUE;
00678 }
00679
00680
00690 void SoWorldPhysics::ApplyActionToWorldPhysicNodesInGraph(SoCallbackAction::SoCallbackActionCB &cb, SoNode* root, void* userdata)
00691 {
00692 SoCallbackAction callbackAction;
00693 callbackAction.addPostCallback(SoWorldPhysics::getClassTypeId(), cb, userdata);
00694 callbackAction.apply(root);
00695 }
00696
00697
00704 void SoWorldPhysics::setStepsize(float stepSizeInSeconds)
00705 {
00706
00707 if (stepSizeInSeconds <= 0.0)
00708 {
00709 printf("Invalid Stepsize: %f [sec]! Keeping old value: %f\n", stepSizeInSeconds, this->stepsize.getValue());
00710 }
00711 else
00712 {
00713 this->stepsize.setValue(stepSizeInSeconds);
00714 printf("Set Stepsize to: %f [sec].\n", stepSizeInSeconds);
00715 }
00716 }
00717
00718
00723 float SoWorldPhysics::getStepsize()
00724 {
00725 return this->stepsize.getValue();
00726 }
00727
00728
00731 void SoWorldPhysics::schedule()
00732 {
00733 if (!this->sens.isScheduled())
00734 this->sens.schedule();
00735 printf("ODE scheduled.\n");
00736 }
00737
00738
00741 void SoWorldPhysics::unschedule()
00742 {
00743 if (this->sens.isScheduled())
00744 this->sens.unschedule();
00745 printf("ODE unscheduled.\n");
00746 }
00747
00748
00758 bool SoWorldPhysics::IsNaN(double value)
00759 {
00760 return (value != value);
00761 }
00762
00763
00767
00768 void SoWorldPhysics::initClasses()
00769 {
00770 if (bClassesInitialised)
00771 return;
00772
00773 SoWorldPhysics::initClass();
00774
00775 SoCollisionShape::initClass();
00776 SoCollisionShapeBox::initClass();
00777 SoCollisionShapeCylinder::initClass();
00778 SoCollisionShapeSphere::initClass();
00779 SoCollisionShapePlane::initClass();
00780 SoCollisionShapeTriMesh::initClass();
00781
00782 SoJoint::initClass();
00783 SoJointAMotor::initClass();
00784 SoJointBall::initClass();
00785 SoJointFixed::initClass();
00786 SoJointHinge::initClass();
00787 SoJointHinge2::initClass();
00788 SoJointSlider::initClass();
00789 SoJointUniversal::initClass();
00790
00791 SoPhysics::initClass();
00792 SoPhysicsBox::initClass();
00793 SoPhysicsCylinder::initClass();
00794 SoPhysicsCapsule::initClass();
00795 SoPhysicsSphere::initClass();
00796 SoPhysicsTorus::initClass();
00797 SoPhysicsTriMesh::initClass();
00798
00799 SoFrictionCone::initClass();
00800 SoPrefixNode::initClass();
00801 bClassesInitialised = true;
00802 }
00803
00804
00805
00806 double SoWorldPhysics::frictioncoeff[SoCollisionShape::NO_OF_SURFACEMATERIALS][SoCollisionShape::NO_OF_SURFACEMATERIALS] =
00807 {
00808
00809 { 0.0, 1.0, 0.0, 0.0, 0.0 ,0.0},
00810 { 1.0, 1.0, 1.0, 1.0, 1.0 ,1.0},
00811 { 0.0, 1.0, 0.4, 0.3, 0.3 ,0.5},
00812 { 0.0, 1.0, 0.3, 0.4, 0.6 ,0.8},
00813 { 0.0, 1.0, 0.2, 0.3, 0.7 ,0.8},
00814 { 0.0, 1.0, 0.5, 0.8, 0.8 ,1.0}
00815 };