BulletPhysics.cpp
Go to the documentation of this file.
00001 /* 
00002  * Copyright (c) 2013 University of Jaume-I.
00003  * All rights reserved. This program and the accompanying materials
00004  * are made available under the terms of the GNU Public License v3.0
00005  * which accompanies this distribution, and is available at
00006  * http://www.gnu.org/licenses/gpl.html
00007  * 
00008  * Contributors:
00009  *     Mario Prats
00010  *     Javier Perez
00011  */
00012 
00013 #include <uwsim/BulletPhysics.h>
00014 
00015 #if BT_BULLET_VERSION > 279
00016 #include "BulletDynamics/MLCPSolvers/btDantzigSolver.h"
00017 #include "BulletDynamics/MLCPSolvers/btSolveProjectedGaussSeidel.h"
00018 #include "BulletDynamics/MLCPSolvers/btMLCPSolver.h"
00019 #endif
00020 
00021 // Define filter masks
00022 unsigned int vehicleCollidesWith(COL_OBJECTS);
00023 unsigned int objectsCollidesWith(COL_EVERYTHING);
00024 
00025 //This motion state just keeps track of another btObject (used for force sensors)
00026 class MirrorMotionState : public btMotionState
00027 {
00028 public:
00029   MirrorMotionState(btRigidBody * copied)
00030   {
00031     copy=copied;
00032   }
00033 
00034   virtual void getWorldTransform(btTransform &worldTrans) const
00035   {
00036      copy->getMotionState()->getWorldTransform(worldTrans);
00037   }
00038 
00039   virtual void setWorldTransform(const btTransform &worldTrans)
00040   {
00041     //There is no need to do nothing as there is no real object
00042   }
00043 
00044 protected:
00045   btRigidBody * copy;
00046 
00047 };
00048 
00049 //Copies a bullet body with it's physical properties. (used for force sensors)
00050 btRigidBody* BulletPhysics::copyObject(btRigidBody * copied)
00051 {
00052 
00053   btVector3 inertia;
00054   copied->getCollisionShape()->calculateLocalInertia(1.0/copied->getInvMass(), inertia);
00055 
00056   MirrorMotionState* motion = new MirrorMotionState(copied);
00057   btRigidBody::btRigidBodyConstructionInfo rb(1.0/copied->getInvMass(), motion,copied->getCollisionShape(),inertia);  //inertia should be copied too
00058   btRigidBody* body = new btRigidBody(rb);
00059 
00060   CollisionDataType * colData = new CollisionDataType("copied", "copied", 1);
00061   body->setUserPointer(colData);
00062 
00063   //Restrictions are not being copied
00064 
00065   body->setDamping(copied->getLinearDamping(), copied->getAngularDamping());
00066 
00067   //addRigidBody adds its own collision masks, changing after object creation do not update masks so objects are removed and readded in order to update masks to improve collisions performance.
00068   dynamicsWorld->addRigidBody(body);
00069 
00070   //We suppose it's a vehicle
00071   dynamicsWorld->btCollisionWorld::removeCollisionObject(body);
00072   dynamicsWorld->addCollisionObject(body, short(COL_VEHICLE), short(vehicleCollidesWith));
00073 
00074   body->setActivationState(DISABLE_DEACTIVATION);
00075 
00076 
00077   return (body);
00078 }
00079 
00080 
00081 class MyMotionState : public btMotionState
00082 {
00083 public:
00084 
00085   MyMotionState(osg::Node * obj, osg::MatrixTransform *root)
00086   {
00087     transf = root;
00088     object = obj;
00089   }
00090 
00091   void setNode(osg::Node *node)
00092   {
00093     object = node;
00094   }
00095 
00096   virtual void getWorldTransform(btTransform &worldTrans) const
00097   {
00098     boost::shared_ptr<osg::Matrix> mat = getWorldCoords(object);
00099     //BTTransforms do not use scale, so we turn it back to 1.
00100     mat->preMultScale(osg::Vec3d(1.0/mat->getScale().x(),1.0/mat->getScale().y(),1.0/mat->getScale().z())); 
00101     worldTrans = osgbCollision::asBtTransform(*mat);
00102   }
00103 
00104   virtual void setWorldTransform(const btTransform &worldTrans)
00105   {
00106     //Object initial position
00107     boost::shared_ptr<osg::Matrix> mat = getWorldCoords(transf->getParent(0));
00108 
00109     //Get object position in matrixd
00110     osg::Matrixd worldMatrix;
00111     btQuaternion rot = worldTrans.getRotation();
00112     btVector3 pos = worldTrans.getOrigin();
00113     worldMatrix.makeRotate(osg::Quat(rot.x(), rot.y(), rot.z(), rot.w()));
00114     worldMatrix.setTrans(osg::Vec3d(pos.x(), pos.y(), pos.z()));
00115     //BTtransforms do not use scale, as collisionShape is scaled to Node scale we apply osg scale
00116     worldMatrix.preMultScale(osg::Vec3d(mat->getScale().x(),mat->getScale().y(),mat->getScale().z()));
00117 
00118     //matrix transform from object initial position to final position
00119     osg::Matrixd rootmat = worldMatrix * (mat->inverse(*mat));
00120 
00121     //Apply transform to object matrix
00122     transf->setMatrix(rootmat);
00123   }
00124 
00125 protected:
00126   osg::Node * object;
00127   osg::MatrixTransform *transf;
00128 
00129 };
00130 
00131 void BulletPhysics::stepSimulation(btScalar timeStep, int maxSubSteps = 1,
00132                                    btScalar fixedTimeStep = btScalar(1.) / btScalar(60.))
00133 {
00134   //dynamicsWorld->debugDrawWorld();
00135   //printManifolds();
00136   //cleanManifolds();
00137   physicsStep=1; //Keeps track of ongoing physics processing.
00138   callbackManager->substep=0;
00139   ((btDynamicsWorld*)dynamicsWorld)->stepSimulation(timeStep, maxSubSteps, fixedTimeStep);
00140   physicsStep=0;
00141 }
00142 
00143 void BulletPhysics::printManifolds()
00144 {
00145   //std::cout<<dispatcher->getNumManifolds()<<std::endl;
00146   for (int i = 0; i < dispatcher->getNumManifolds(); i++)
00147   {
00148     btCollisionObject* colObj0 = (btCollisionObject*)dispatcher->getManifoldByIndexInternal(i)->getBody0();
00149     btCollisionObject* colObj1 = (btCollisionObject*)dispatcher->getManifoldByIndexInternal(i)->getBody1();
00150     CollisionDataType * nombre = (CollisionDataType *)colObj0->getUserPointer();
00151     CollisionDataType * nombre2 = (CollisionDataType *)colObj1->getUserPointer();
00152     double min = 999999;
00153     for (int j = 0; j < dispatcher->getManifoldByIndexInternal(i)->getNumContacts(); j++)
00154       if (dispatcher->getManifoldByIndexInternal(i)->getContactPoint(j).getDistance() < min)
00155         min = dispatcher->getManifoldByIndexInternal(i)->getContactPoint(j).getDistance();
00156     if (min < 999999)
00157     {
00158       std::cout << i << " ";
00159       if (nombre)
00160         std::cout << nombre->name << " " << " ";
00161       if (nombre2)
00162         std::cout << nombre2->name;
00163       std::cout << " " << min << std::endl;
00164     }
00165   }
00166 }
00167 
00168 //Adds tick callback manager which will do all stuff needed in pretick callback
00169 void preTickCallback(btDynamicsWorld *world, btScalar timeStep)
00170 {
00171     BulletPhysics::TickCallbackManager *w = static_cast<BulletPhysics::TickCallbackManager *>(world->getWorldUserInfo());
00172     w->physicsInternalPreProcessCallback(timeStep);
00173 }
00174 
00175 //Adds tick callback manager which will do all stuff needed in posttick callback
00176 void postTickCallback(btDynamicsWorld *world, btScalar timeStep)
00177 {
00178     BulletPhysics::TickCallbackManager *w = static_cast<BulletPhysics::TickCallbackManager *>(world->getWorldUserInfo());
00179     w->physicsInternalPostProcessCallback(timeStep);
00180 }
00181 
00182 //oceanSurf is not used right now, but should be to add water physics
00183 BulletPhysics::BulletPhysics(PhysicsConfig physicsConfig, osgOcean::OceanTechnique* oceanSurf) 
00184 {
00185   collisionConfiguration = new btDefaultCollisionConfiguration();
00186   dispatcher = new btCollisionDispatcher(collisionConfiguration);
00187   
00188   #if BT_BULLET_VERSION <= 279
00189     solver = new btSequentialImpulseConstraintSolver();
00190   #else
00191     if(physicsConfig.solver==PhysicsConfig::Dantzig){
00192       btDantzigSolver* mlcp = new btDantzigSolver();
00193       solver = new btMLCPSolver(mlcp);
00194     }
00195 
00196     else if(physicsConfig.solver==PhysicsConfig::SolveProjectedGauss){
00197       btSolveProjectedGaussSeidel* mlcp = new btSolveProjectedGaussSeidel;
00198       solver = new btMLCPSolver(mlcp);
00199     }
00200 
00201     else if(physicsConfig.solver==PhysicsConfig::SequentialImpulse){
00202       solver = new btSequentialImpulseConstraintSolver();
00203     }
00204   #endif
00205 
00206 
00207   btVector3 worldAabbMin(-10000, -10000, -10000);
00208   btVector3 worldAabbMax(10000, 10000, 10000);
00209   inter = new btAxisSweep3(worldAabbMin, worldAabbMax, 1000);
00210 
00211   dynamicsWorld = new btDiscreteDynamicsWorld(dispatcher, inter, solver, collisionConfiguration);
00212   dynamicsWorld->getDispatchInfo().m_enableSPU = true;
00213 
00214   btVector3 gravity(physicsConfig.gravity[0], physicsConfig.gravity[1], physicsConfig.gravity[2]);
00215   if (physicsConfig.gravity[0] == 0 && physicsConfig.gravity[1] == 0 && physicsConfig.gravity[2] == 0)
00216   {
00217     gravity = UWSIM_DEFAULT_GRAVITY;
00218   }
00219 
00220   dynamicsWorld->setGravity(gravity);
00221   oceanSurface = oceanSurf;
00222 
00223   /*debugDrawer.setDebugMode(btIDebugDraw::DBG_DrawContactPoints|| btIDebugDraw::DBG_DrawWireframe || btIDebugDraw::DBG_DrawText);
00224    dynamicsWorld->setDebugDrawer(&debugDrawer);
00225    debugDrawer.BeginDraw();
00226    debugDrawer.setEnabled(true);*/
00227 
00228    //Create pre-tick and post-tick callbacks
00229    callbackManager= new TickCallbackManager();
00230    dynamicsWorld->setInternalTickCallback(preTickCallback, static_cast<void *>(callbackManager),true);
00231    dynamicsWorld->setInternalTickCallback(postTickCallback, static_cast<void *>(callbackManager));
00232 }
00233 
00234 //Adds a force sensor to tickCallbackManager
00235 int BulletPhysics::TickCallbackManager::addForceSensor(btRigidBody * copy, btRigidBody * target)
00236 {
00237   ForceSensorcbInfo fs;
00238   fs.target=target;
00239   fs.copy=copy;
00240   forceSensors.push_back(fs);
00241 
00242   return forceSensors.size()-1;
00243 }
00244 
00245 //Gets Speed difference from tickcallbackmanager using reference returned on addition
00246 void BulletPhysics::TickCallbackManager::getForceSensorSpeed(int forceSensor, double linSpeed[3],double angSpeed[3])
00247 {
00248   linSpeed[0]=forceSensors[forceSensor].linFinal.x()-forceSensors[forceSensor].linInitial.x();
00249   linSpeed[1]=forceSensors[forceSensor].linFinal.y()-forceSensors[forceSensor].linInitial.y();
00250   linSpeed[2]=forceSensors[forceSensor].linFinal.z()-forceSensors[forceSensor].linInitial.z();
00251 
00252   angSpeed[0]=forceSensors[forceSensor].angFinal.x()-forceSensors[forceSensor].angInitial.x();
00253   angSpeed[1]=forceSensors[forceSensor].angFinal.y()-forceSensors[forceSensor].angInitial.y();
00254   angSpeed[2]=forceSensors[forceSensor].angFinal.z()-forceSensors[forceSensor].angInitial.z();
00255 }
00256 
00257 //forceSensor pre-tick callback
00258 void BulletPhysics::TickCallbackManager::preTickForceSensors()
00259 {
00260   for(int i=0;i<forceSensors.size();i++)
00261   {
00262     forceSensors[i].copy->setCenterOfMassTransform(forceSensors[i].target->getCenterOfMassTransform());
00263     forceSensors[i].copy->clearForces();
00264     forceSensors[i].copy->setLinearVelocity(forceSensors[i].target->getLinearVelocity());
00265     forceSensors[i].copy->setAngularVelocity(forceSensors[i].target->getAngularVelocity());
00266     forceSensors[i].linInitial=forceSensors[i].copy->getLinearVelocity();
00267     forceSensors[i].angInitial=forceSensors[i].copy->getAngularVelocity();
00268   }
00269 }
00270 
00271 //forceSensor post-tick callback
00272 void BulletPhysics::TickCallbackManager::postTickForceSensors()
00273 {
00274   for(int i=0;i<forceSensors.size();i++)
00275   {
00276     forceSensors[i].linFinal=forceSensors[i].copy->getLinearVelocity();
00277     forceSensors[i].angFinal=forceSensors[i].copy->getAngularVelocity();
00278   }
00279 }
00280 
00281 //This function will be called just before physics step (or substep) start,
00282 //It may be used to add buoyancy and drag forces to dynamic objects
00283 void BulletPhysics::TickCallbackManager::physicsInternalPreProcessCallback(btScalar timeStep)
00284 {
00285   if (substep==0){
00286     preTickForceSensors();
00287   }
00288 }
00289 
00290 //This function will be called just after physics step (or substep) finishes
00291 void BulletPhysics::TickCallbackManager::physicsInternalPostProcessCallback(btScalar timeStep)
00292 {
00293   postTickForceSensors();
00294   substep++;
00295 }
00296 
00297 btCollisionShape* BulletPhysics::GetCSFromOSG(osg::Node * node, collisionShapeType_t ctype)
00298 {
00299   btCollisionShape* cs = NULL;
00300 
00301   if (ctype == SHAPE_BOX)
00302     cs = osgbCollision::btBoxCollisionShapeFromOSG(node);
00303   else if (ctype == SHAPE_SPHERE)
00304     cs = osgbCollision::btSphereCollisionShapeFromOSG(node);
00305   else if (ctype == SHAPE_COMPOUND_TRIMESH)
00306     cs = osgbCollision::btCompoundShapeFromOSGGeodes(node, CONVEX_TRIANGLEMESH_SHAPE_PROXYTYPE);
00307   else if (ctype == SHAPE_COMPOUND_BOX)
00308     cs = osgbCollision::btCompoundShapeFromOSGGeodes(node, BOX_SHAPE_PROXYTYPE);
00309   else if (ctype == SHAPE_COMPOUND_CYLINDER)
00310     cs = osgbCollision::btCompoundShapeFromOSGGeodes(node, CYLINDER_SHAPE_PROXYTYPE);
00311   else if (ctype == SHAPE_TRIMESH)
00312     cs = osgbCollision::btTriMeshCollisionShapeFromOSG(node);
00313 
00314   return cs;
00315 }
00316 
00317 btRigidBody* BulletPhysics::addObject(osg::MatrixTransform *root, osg::Node *node, CollisionDataType * data,
00318                                       boost::shared_ptr<PhysicProperties> pp, osg::Node * colShape)
00319 {
00320   //if not physic properties set default.
00321   if (!pp)
00322   {
00323     pp.reset(new PhysicProperties);
00324     pp->init();
00325     if (data->isVehicle)
00326     {
00327       pp->isKinematic = 1;
00328       pp->csType = "compound box";
00329       pp->mass = 0; //there is no need to set mass (and inertia) to kinematic objects
00330     }
00331   }
00332 
00333   collisionShapeType_t ctype = SHAPE_BOX;
00334 
00335   if (pp->csType == "box")
00336     ctype = BulletPhysics::SHAPE_BOX;
00337   else if (pp->csType == "sphere")
00338     ctype = BulletPhysics::SHAPE_SPHERE;
00339   else if (pp->csType == "compound box")
00340     ctype = BulletPhysics::SHAPE_COMPOUND_BOX;
00341   else if (pp->csType == "compound cylinder")
00342     ctype = BulletPhysics::SHAPE_COMPOUND_CYLINDER;
00343   else if (pp->csType == "trimesh")
00344     ctype = BulletPhysics::SHAPE_TRIMESH;
00345   else if (pp->csType == "compound trimesh")
00346     ctype = BulletPhysics::SHAPE_COMPOUND_TRIMESH;
00347   else
00348     OSG_WARN << data->name << " has an unknown collision shape type: " << pp->csType
00349         << ". Using default box shape(dynamic) trimesh(kinematic). Check xml file, allowed collision shapes are 'box' 'compound box' 'trimesh' 'compound trimesh' 'compound cylinder."
00350         << std::endl;
00351 
00352   btCollisionShape* cs;
00353   if (colShape == NULL)
00354     cs = GetCSFromOSG(node, ctype);
00355   else
00356     cs = GetCSFromOSG(colShape, ctype);
00357 
00358   //As btTransforms do not work with scale, we scale the collision shape
00359   boost::shared_ptr<osg::Matrix> mat = getWorldCoords(node);
00360   cs->setLocalScaling(btVector3(mat->getScale().x(),mat->getScale().y(),mat->getScale().z()));
00361 
00362   btVector3 inertia = btVector3(pp->inertia[0], pp->inertia[1], pp->inertia[2]);
00363 
00364   MyMotionState* motion = new MyMotionState(node, root);
00365   if (inertia.length() == 0) //asking bullet to calculate inertia only if it is unset
00366     cs->calculateLocalInertia(pp->mass, inertia);
00367   btRigidBody::btRigidBodyConstructionInfo rb(pp->mass, motion, cs, inertia);
00368   btRigidBody* body = new btRigidBody(rb);
00369   body->setUserPointer(data);
00370 
00371   if (pp->maxAngularLimit[0] >= pp->minAngularLimit[0] || pp->maxAngularLimit[1] >= pp->minAngularLimit[1]
00372       || pp->maxAngularLimit[1] >= pp->minAngularLimit[1] || pp->maxLinearLimit[0] >= pp->minLinearLimit[0]
00373       || pp->maxLinearLimit[1] >= pp->minLinearLimit[1] || pp->maxLinearLimit[1] >= pp->minLinearLimit[1])
00374   {
00375     btRigidBody* pBodyB = new btRigidBody(0, motion, 0);
00376     pBodyB->setActivationState(DISABLE_DEACTIVATION);
00377 
00378     btTransform frameInA, frameInB;
00379     frameInA = btTransform::getIdentity();
00380     frameInB = btTransform::getIdentity();
00381     if (pp->minAngularLimit[1] < pp->maxAngularLimit[1])
00382     { //There is a constraint on Y axis (quaternions uncertainties can make it unstable)
00383       if (not (pp->minAngularLimit[0] < pp->maxAngularLimit[0] or pp->minAngularLimit[2] < pp->maxAngularLimit[2]))
00384       { //There is no constraint on X and Z so we rotate to move it
00385         frameInA.getBasis().setEulerZYX(0, 0, 1.57);
00386         frameInB.getBasis().setEulerZYX(0, 0, 1.57);
00387         double aux = pp->minAngularLimit[0];
00388         pp->minAngularLimit[0] = pp->minAngularLimit[1];
00389         pp->minAngularLimit[1] = aux;
00390         aux = pp->maxAngularLimit[0];
00391         pp->maxAngularLimit[0] = pp->maxAngularLimit[1];
00392         pp->maxAngularLimit[1] = aux;
00393       } //TODO check other possible rotations to avoid aborting.
00394       else if (pp->minAngularLimit[1] <= -1.50 || pp->minAngularLimit[1] >= 1.50)
00395       { //safety threshold
00396         std::cerr << "Constraints in Y axis must be between -PI/2 PI/2" << std::endl;
00397         exit(0);
00398       }
00399     }
00400 
00401     btGeneric6DofConstraint* pGen6DOF = new btGeneric6DofConstraint(*body, *pBodyB, frameInA, frameInB, true);
00402     pGen6DOF->setLinearLowerLimit(btVector3(pp->minLinearLimit[0], pp->minLinearLimit[1], pp->minLinearLimit[2]));
00403     pGen6DOF->setLinearUpperLimit(btVector3(pp->maxLinearLimit[0], pp->maxLinearLimit[1], pp->maxLinearLimit[2]));
00404 
00405     pGen6DOF->setAngularLowerLimit(btVector3(pp->minAngularLimit[0], pp->minAngularLimit[1], pp->minAngularLimit[2]));
00406     pGen6DOF->setAngularUpperLimit(btVector3(pp->maxAngularLimit[0], pp->maxAngularLimit[1], pp->maxAngularLimit[2]));
00407 
00408     dynamicsWorld->addConstraint(pGen6DOF, true);
00409   }
00410 
00411   //body->setLinearFactor(btVector3(pp->linearFactor[0],pp->linearFactor[1],pp->linearFactor[2]));
00412   //body->setAngularFactor(btVector3(pp->angularFactor[0],pp->angularFactor[1],pp->angularFactor[2]));
00413 
00414   body->setDamping(pp->linearDamping, pp->angularDamping);
00415 
00416   //addRigidBody adds its own collision masks, changing after object creation do not update masks so objects are removed and readded in order to update masks to improve collisions performance.
00417   dynamicsWorld->addRigidBody(body);
00418   if (data->isVehicle)
00419   {
00420     dynamicsWorld->btCollisionWorld::removeCollisionObject(body);
00421     dynamicsWorld->addCollisionObject(body, short(COL_VEHICLE), short(vehicleCollidesWith));
00422   }
00423   else
00424   {
00425     dynamicsWorld->btCollisionWorld::removeCollisionObject(body);
00426     dynamicsWorld->addCollisionObject(body, short(COL_OBJECTS), short(objectsCollidesWith));
00427   }
00428 
00429   body->setActivationState(DISABLE_DEACTIVATION);
00430   if (pp->isKinematic)
00431   {
00432     body->setCollisionFlags(body->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT);
00433   }
00434 
00435   return (body);
00436 }
00437 
00438 int BulletPhysics::getNumCollisions()
00439 {
00440   return dispatcher->getNumManifolds();
00441 }
00442 
00443 btPersistentManifold * BulletPhysics::getCollision(int i)
00444 {
00445   return dispatcher->getManifoldByIndexInternal(i);
00446 }
00447 
00448 void BulletPhysics::cleanManifolds()
00449 { //it removes contact points with long lifetime
00450   //std::cout<<dispatcher->getNumManifolds()<<"aa"<<std::endl;
00451   for (int i = 0; i < dispatcher->getNumManifolds(); i++)
00452   {
00453     btPersistentManifold * col = dispatcher->getManifoldByIndexInternal(i);
00454     //std::cout<<col->getNumContacts()<<std::endl;
00455     for (int j = 0; j < col->getNumContacts(); j++)
00456       if (col->getContactPoint(j).getLifeTime() > 300)
00457         col->removeContactPoint(j);
00458 
00459   }
00460 }


uwsim
Author(s): Mario Prats , Javier Perez
autogenerated on Fri Aug 28 2015 13:28:58