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 // Define filter masks
00016 unsigned int vehicleCollidesWith(COL_OBJECTS);
00017 unsigned int objectsCollidesWith(COL_EVERYTHING);
00018 
00019 //This motion state just keeps track of another btObject (used for force sensors)
00020 class MirrorMotionState : public btMotionState
00021 {
00022 public:
00023   MirrorMotionState(btRigidBody * copied)
00024   {
00025     copy=copied;
00026   }
00027 
00028   virtual void getWorldTransform(btTransform &worldTrans) const
00029   {
00030      copy->getMotionState()->getWorldTransform(worldTrans);
00031   }
00032 
00033   virtual void setWorldTransform(const btTransform &worldTrans)
00034   {
00035     //There is no need to do nothing as there is no real object
00036   }
00037 
00038 protected:
00039   btRigidBody * copy;
00040 
00041 };
00042 
00043 //Copies a bullet body with it's physical properties. (used for force sensors)
00044 btRigidBody* BulletPhysics::copyObject(btRigidBody * copied)
00045 {
00046 
00047   btVector3 inertia;
00048   copied->getCollisionShape()->calculateLocalInertia(1.0/copied->getInvMass(), inertia);
00049 
00050   MirrorMotionState* motion = new MirrorMotionState(copied);
00051   btRigidBody::btRigidBodyConstructionInfo rb(1.0/copied->getInvMass(), motion,copied->getCollisionShape(),inertia);  //inertia should be copied too
00052   btRigidBody* body = new btRigidBody(rb);
00053 
00054   CollisionDataType * colData = new CollisionDataType("copied", "copied", 1);
00055   body->setUserPointer(colData);
00056 
00057   //Restrictions are not being copied
00058 
00059   body->setDamping(copied->getLinearDamping(), copied->getAngularDamping());
00060 
00061   //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.
00062   dynamicsWorld->addRigidBody(body);
00063 
00064   //We suppose it's a vehicle
00065   dynamicsWorld->btCollisionWorld::removeCollisionObject(body);
00066   dynamicsWorld->addCollisionObject(body, short(COL_VEHICLE), short(vehicleCollidesWith));
00067 
00068   body->setActivationState(DISABLE_DEACTIVATION);
00069 
00070 
00071   return (body);
00072 }
00073 
00074 
00075 class MyMotionState : public btMotionState
00076 {
00077 public:
00078 
00079   MyMotionState(osg::Node * obj, osg::MatrixTransform *root)
00080   {
00081     transf = root;
00082     object = obj;
00083   }
00084 
00085   void setNode(osg::Node *node)
00086   {
00087     object = node;
00088   }
00089 
00090   virtual void getWorldTransform(btTransform &worldTrans) const
00091   {
00092     worldTrans = osgbCollision::asBtTransform(*getWorldCoords(object));
00093   }
00094 
00095   virtual void setWorldTransform(const btTransform &worldTrans)
00096   {
00097     //Object initial position
00098     boost::shared_ptr<osg::Matrix> mat = getWorldCoords(transf->getParent(0));
00099 
00100     //Get object position in matrixd
00101     osg::Matrixd worldMatrix;
00102     btQuaternion rot = worldTrans.getRotation();
00103     btVector3 pos = worldTrans.getOrigin();
00104     worldMatrix.setTrans(osg::Vec3d(pos.x(), pos.y(), pos.z()));
00105     worldMatrix.setRotate(osg::Quat(rot.x(), rot.y(), rot.z(), rot.w()));
00106 
00107     //matrix transform from object initial position to final position
00108     osg::Matrixd rootmat = worldMatrix * (mat->inverse(*mat));
00109 
00110     //Apply transform to object matrix
00111     rootmat.setTrans(rootmat.getTrans());
00112     rootmat.setRotate(rootmat.getRotate());
00113     transf->setMatrix(rootmat);
00114   }
00115 
00116 protected:
00117   osg::Node * object;
00118   osg::MatrixTransform *transf;
00119 
00120 };
00121 
00122 void BulletPhysics::stepSimulation(btScalar timeStep, int maxSubSteps = 1,
00123                                    btScalar fixedTimeStep = btScalar(1.) / btScalar(60.))
00124 {
00125   //dynamicsWorld->debugDrawWorld();
00126   //printManifolds();
00127   //cleanManifolds();
00128   if (fluid)
00129     updateOceanSurface();
00130   physicsStep=1; //Keeps track of ongoing physics processing.
00131   ((btDynamicsWorld*)dynamicsWorld)->stepSimulation(timeStep, maxSubSteps, fixedTimeStep);
00132   physicsStep=0;
00133 }
00134 
00135 void BulletPhysics::printManifolds()
00136 {
00137   //std::cout<<dispatcher->getNumManifolds()<<std::endl;
00138   for (int i = 0; i < dispatcher->getNumManifolds(); i++)
00139   {
00140     btCollisionObject* colObj0 = (btCollisionObject*)dispatcher->getManifoldByIndexInternal(i)->getBody0();
00141     btCollisionObject* colObj1 = (btCollisionObject*)dispatcher->getManifoldByIndexInternal(i)->getBody1();
00142     CollisionDataType * nombre = (CollisionDataType *)colObj0->getUserPointer();
00143     CollisionDataType * nombre2 = (CollisionDataType *)colObj1->getUserPointer();
00144     double min = 999999;
00145     for (int j = 0; j < dispatcher->getManifoldByIndexInternal(i)->getNumContacts(); j++)
00146       if (dispatcher->getManifoldByIndexInternal(i)->getContactPoint(j).getDistance() < min)
00147         min = dispatcher->getManifoldByIndexInternal(i)->getContactPoint(j).getDistance();
00148     if (min < 999999)
00149     {
00150       std::cout << i << " ";
00151       if (nombre)
00152         std::cout << nombre->name << " " << " ";
00153       if (nombre2)
00154         std::cout << nombre2->name;
00155       std::cout << " " << min << std::endl;
00156     }
00157   }
00158 }
00159 
00160 BulletPhysics::BulletPhysics(double configGravity[3], osgOcean::OceanTechnique* oceanSurf, PhysicsWater physicsWater)
00161 {
00162   collisionConfiguration = new btHfFluidRigidCollisionConfiguration();
00163   dispatcher = new btCollisionDispatcher(collisionConfiguration);
00164   solver = new btSequentialImpulseConstraintSolver();
00165 
00166   btVector3 worldAabbMin(-10000, -10000, -10000);
00167   btVector3 worldAabbMax(10000, 10000, 10000);
00168   inter = new btAxisSweep3(worldAabbMin, worldAabbMax, 1000);
00169 
00170   dynamicsWorld = new btHfFluidRigidDynamicsWorld(dispatcher, inter, solver, collisionConfiguration);
00171   dynamicsWorld->getDispatchInfo().m_enableSPU = true;
00172 
00173   btVector3 gravity(configGravity[0], configGravity[1], configGravity[2]);
00174   if (configGravity[0] == 0 && configGravity[1] == 0 && configGravity[2] == 0)
00175   {
00176     gravity = UWSIM_DEFAULT_GRAVITY;
00177   }
00178 
00179   dynamicsWorld->setGravity(gravity);
00180   oceanSurface = oceanSurf;
00181 
00182   if (physicsWater.enable)
00183   {
00184 
00185     fluid = new btHfFluid(physicsWater.resolution, physicsWater.size[0], physicsWater.size[1], physicsWater.size[2],
00186                           physicsWater.size[3], physicsWater.size[4], physicsWater.size[5]);
00187     //fluid = new btHfFluid (btScalar(0.25), 100,100);
00188     btTransform xform;
00189     xform.setIdentity();
00190     xform.getOrigin() = btVector3(physicsWater.position[0], physicsWater.position[1], physicsWater.position[2]);
00191     //xform.setRotation(btQuaternion(0,1.57,0));
00192     fluid->setWorldTransform(xform);
00193     fluid->setHorizontalVelocityScale(btScalar(0.0f));
00194     fluid->setVolumeDisplacementScale(btScalar(0.0f));
00195     dynamicsWorld->addHfFluid(fluid);
00196 
00197     for (int i = 0; i < fluid->getNumNodesLength() * fluid->getNumNodesWidth(); i++)
00198     {
00199       fluid->setFluidHeight(i, btScalar(0.0f));
00200     }
00201 
00202     fluid->prep();
00203   }
00204   else
00205     fluid = NULL;
00206   /*debugDrawer.setDebugMode(btIDebugDraw::DBG_DrawContactPoints|| btIDebugDraw::DBG_DrawWireframe || btIDebugDraw::DBG_DrawText);
00207    dynamicsWorld->setDebugDrawer(&debugDrawer);
00208    debugDrawer.BeginDraw();
00209    debugDrawer.setEnabled(true);*/
00210 }
00211 
00212 void BulletPhysics::updateOceanSurface()
00213 {
00214 
00215   int nodeswidth = fluid->getNumNodesWidth();
00216 
00217   int nodeslength = fluid->getNumNodesLength();
00218   double cellwidth = fluid->getGridCellWidth();
00219   double halfnodeswidth = nodeswidth / 2 * cellwidth;
00220   double halfnodeslength = nodeslength / 2 * cellwidth;
00221 
00222   for (int i = 0; i < nodeswidth; i++)
00223   {
00224     for (int j = 0; j < nodeslength; j++)
00225     {
00226       fluid->setFluidHeight(
00227           i,
00228           j,
00229           oceanSurface->getSurfaceHeightAt(i * cellwidth - halfnodeswidth + cellwidth / 2,
00230                                            j * cellwidth - halfnodeslength + cellwidth / 2) * -1);
00231     }
00232   }
00233 }
00234 
00235 btCollisionShape* BulletPhysics::GetCSFromOSG(osg::Node * node, collisionShapeType_t ctype)
00236 {
00237   btCollisionShape* cs = NULL;
00238 
00239   if (ctype == SHAPE_BOX)
00240     cs = osgbCollision::btBoxCollisionShapeFromOSG(node);
00241   else if (ctype == SHAPE_SPHERE)
00242     cs = osgbCollision::btSphereCollisionShapeFromOSG(node);
00243   else if (ctype == SHAPE_COMPOUND_TRIMESH)
00244     cs = osgbCollision::btCompoundShapeFromOSGGeodes(node, CONVEX_TRIANGLEMESH_SHAPE_PROXYTYPE);
00245   else if (ctype == SHAPE_COMPOUND_BOX)
00246     cs = osgbCollision::btCompoundShapeFromOSGGeodes(node, BOX_SHAPE_PROXYTYPE);
00247   else if (ctype == SHAPE_COMPOUND_CYLINDER)
00248     cs = osgbCollision::btCompoundShapeFromOSGGeodes(node, CYLINDER_SHAPE_PROXYTYPE);
00249   else if (ctype == SHAPE_TRIMESH)
00250     cs = osgbCollision::btTriMeshCollisionShapeFromOSG(node);
00251 
00252   return cs;
00253 }
00254 
00255 btRigidBody* BulletPhysics::addObject(osg::MatrixTransform *root, osg::Node *node, CollisionDataType * data,
00256                                       boost::shared_ptr<PhysicProperties> pp, osg::Node * colShape)
00257 {
00258   //if not physic properties set default.
00259   if (!pp)
00260   {
00261     pp.reset(new PhysicProperties);
00262     pp->init();
00263     if (data->isVehicle)
00264     {
00265       pp->isKinematic = 1;
00266       pp->csType = "compound box";
00267       pp->mass = 0; //there is no need to set mass (and inertia) to kinematic objects
00268     }
00269   }
00270 
00271   collisionShapeType_t ctype = SHAPE_BOX;
00272 
00273   if (pp->csType == "box")
00274     ctype = BulletPhysics::SHAPE_BOX;
00275   else if (pp->csType == "sphere")
00276     ctype = BulletPhysics::SHAPE_SPHERE;
00277   else if (pp->csType == "compound box")
00278     ctype = BulletPhysics::SHAPE_COMPOUND_BOX;
00279   else if (pp->csType == "compound cylinder")
00280     ctype = BulletPhysics::SHAPE_COMPOUND_CYLINDER;
00281   else if (pp->csType == "trimesh")
00282     ctype = BulletPhysics::SHAPE_TRIMESH;
00283   else if (pp->csType == "compound trimesh")
00284     ctype = BulletPhysics::SHAPE_COMPOUND_TRIMESH;
00285   else
00286     OSG_WARN << data->name << " has an unknown collision shape type: " << pp->csType
00287         << ". Using default box shape(dynamic) trimesh(kinematic). Check xml file, allowed collision shapes are 'box' 'compound box' 'trimesh' 'compound trimesh' 'compound cylinder."
00288         << std::endl;
00289 
00290   btCollisionShape* cs;
00291   if (colShape == NULL)
00292     cs = GetCSFromOSG(node, ctype);
00293   else
00294     cs = GetCSFromOSG(colShape, ctype);
00295 
00296   btVector3 inertia = btVector3(pp->inertia[0], pp->inertia[1], pp->inertia[2]);
00297 
00298   MyMotionState* motion = new MyMotionState(node, root);
00299   if (inertia.length() == 0) //asking bullet to calculate inertia only if it is unset
00300     cs->calculateLocalInertia(pp->mass, inertia);
00301   btRigidBody::btRigidBodyConstructionInfo rb(pp->mass, motion, cs, inertia);
00302   btRigidBody* body = new btRigidBody(rb);
00303   body->setUserPointer(data);
00304 
00305   if (pp->maxAngularLimit[0] >= pp->minAngularLimit[0] || pp->maxAngularLimit[1] >= pp->minAngularLimit[1]
00306       || pp->maxAngularLimit[1] >= pp->minAngularLimit[1] || pp->maxLinearLimit[0] >= pp->minLinearLimit[0]
00307       || pp->maxLinearLimit[1] >= pp->minLinearLimit[1] || pp->maxLinearLimit[1] >= pp->minLinearLimit[1])
00308   {
00309     btRigidBody* pBodyB = new btRigidBody(0, motion, 0);
00310     pBodyB->setActivationState(DISABLE_DEACTIVATION);
00311 
00312     btTransform frameInA, frameInB;
00313     frameInA = btTransform::getIdentity();
00314     frameInB = btTransform::getIdentity();
00315     if (pp->minAngularLimit[1] < pp->maxAngularLimit[1])
00316     { //There is a constraint on Y axis (quaternions uncertainties can make it unstable)
00317       if (not (pp->minAngularLimit[0] < pp->maxAngularLimit[0] or pp->minAngularLimit[2] < pp->maxAngularLimit[2]))
00318       { //There is no constraint on X and Z so we rotate to move it
00319         frameInA.getBasis().setEulerZYX(0, 0, 1.57);
00320         frameInB.getBasis().setEulerZYX(0, 0, 1.57);
00321         double aux = pp->minAngularLimit[0];
00322         pp->minAngularLimit[0] = pp->minAngularLimit[1];
00323         pp->minAngularLimit[1] = aux;
00324         aux = pp->maxAngularLimit[0];
00325         pp->maxAngularLimit[0] = pp->maxAngularLimit[1];
00326         pp->maxAngularLimit[1] = aux;
00327       } //TODO check other possible rotations to avoid aborting.
00328       else if (pp->minAngularLimit[1] <= -1.50 || pp->minAngularLimit[1] >= 1.50)
00329       { //safety threshold
00330         std::cerr << "Constraints in Y axis must be between -PI/2 PI/2" << std::endl;
00331         exit(0);
00332       }
00333     }
00334 
00335     btGeneric6DofConstraint* pGen6DOF = new btGeneric6DofConstraint(*body, *pBodyB, frameInA, frameInB, true);
00336     pGen6DOF->setLinearLowerLimit(btVector3(pp->minLinearLimit[0], pp->minLinearLimit[1], pp->minLinearLimit[2]));
00337     pGen6DOF->setLinearUpperLimit(btVector3(pp->maxLinearLimit[0], pp->maxLinearLimit[1], pp->maxLinearLimit[2]));
00338 
00339     pGen6DOF->setAngularLowerLimit(btVector3(pp->minAngularLimit[0], pp->minAngularLimit[1], pp->minAngularLimit[2]));
00340     pGen6DOF->setAngularUpperLimit(btVector3(pp->maxAngularLimit[0], pp->maxAngularLimit[1], pp->maxAngularLimit[2]));
00341 
00342     dynamicsWorld->addConstraint(pGen6DOF, true);
00343   }
00344 
00345   //body->setLinearFactor(btVector3(pp->linearFactor[0],pp->linearFactor[1],pp->linearFactor[2]));
00346   //body->setAngularFactor(btVector3(pp->angularFactor[0],pp->angularFactor[1],pp->angularFactor[2]));
00347 
00348   body->setDamping(pp->linearDamping, pp->angularDamping);
00349 
00350   //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.
00351   dynamicsWorld->addRigidBody(body);
00352   if (data->isVehicle)
00353   {
00354     dynamicsWorld->btCollisionWorld::removeCollisionObject(body);
00355     dynamicsWorld->addCollisionObject(body, short(COL_VEHICLE), short(vehicleCollidesWith));
00356   }
00357   else
00358   {
00359     dynamicsWorld->btCollisionWorld::removeCollisionObject(body);
00360     dynamicsWorld->addCollisionObject(body, short(COL_OBJECTS), short(objectsCollidesWith));
00361   }
00362 
00363   body->setActivationState(DISABLE_DEACTIVATION);
00364   if (pp->isKinematic)
00365   {
00366     body->setCollisionFlags(body->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT);
00367   }
00368 
00369   return (body);
00370 }
00371 
00372 //Buoyant Shapes only admits simple convex  shapes
00373 btConvexShape* BulletPhysics::GetConvexCSFromOSG(osg::Node * node, collisionShapeType_t ctype)
00374 {
00375   btConvexShape* cs = NULL;
00376 
00377   if (ctype == SHAPE_BOX)
00378     cs = osgbCollision::btBoxCollisionShapeFromOSG(node);
00379   else if (ctype == SHAPE_SPHERE)
00380     cs = osgbCollision::btSphereCollisionShapeFromOSG(node);
00381 
00382   return cs;
00383 }
00384 
00385 btRigidBody* BulletPhysics::addFloatingObject(osg::MatrixTransform *root, osg::Node *node, CollisionDataType * data,
00386                                               boost::shared_ptr<PhysicProperties> pp, osg::Node * colShape)
00387 {
00388   if (!pp)
00389   {
00390     pp.reset(new PhysicProperties);
00391     pp->init();
00392   }
00393 
00394   collisionShapeType_t ctype = SHAPE_BOX;
00395 
00396   if (pp->csType == "box")
00397     ctype = BulletPhysics::SHAPE_BOX;
00398   else if (pp->csType == "sphere")
00399     ctype = BulletPhysics::SHAPE_SPHERE;
00400   else
00401     OSG_WARN << data->name << " has an unknown collision shape type: " << pp->csType
00402         << ". Using default box shape(dynamic) trimesh(kinematic). Check xml file, allowed collision shapes are 'box' 'compound box' 'trimesh' 'compound trimesh'."
00403         << std::endl;
00404 
00405   btConvexShape* cs;
00406   if (colShape == NULL)
00407     cs = GetConvexCSFromOSG(node, ctype);
00408   else
00409     cs = GetConvexCSFromOSG(colShape, ctype);
00410 
00411   btVector3 inertia = btVector3(pp->inertia[0], pp->inertia[1], pp->inertia[2]);
00412 
00413   MyMotionState* motion = new MyMotionState(node, root);
00414   cs->calculateLocalInertia(pp->mass, inertia);
00415 
00416   btHfFluidBuoyantConvexShape* buoyantShape = new btHfFluidBuoyantConvexShape(cs);
00417   buoyantShape->generateShape(btScalar(0.05f), btScalar(0.01f));
00418   buoyantShape->setFloatyness(btScalar(1.0f));
00419 
00420   btRigidBody::btRigidBodyConstructionInfo rb(pp->mass, motion, buoyantShape, inertia);
00421   btRigidBody* body = new btRigidBody(rb);
00422 
00423   body->setUserPointer(data);
00424 
00425   //body->setLinearFactor(btVector3(pp->linearFactor[0],pp->linearFactor[1],pp->linearFactor[2]));
00426   //body->setAngularFactor(btVector3(pp->angularFactor[0],pp->angularFactor[1],pp->angularFactor[2]));
00427 
00428   body->setDamping(pp->linearDamping, pp->angularDamping);
00429 
00430   //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.
00431   dynamicsWorld->addRigidBody(body);
00432   dynamicsWorld->btCollisionWorld::removeCollisionObject(body);
00433   dynamicsWorld->addCollisionObject(body, short(COL_OBJECTS), short(objectsCollidesWith));
00434 
00435   body->setActivationState(DISABLE_DEACTIVATION);
00436   return (body);
00437 }
00438 
00439 int BulletPhysics::getNumCollisions()
00440 {
00441   return dispatcher->getNumManifolds();
00442 }
00443 
00444 btPersistentManifold * BulletPhysics::getCollision(int i)
00445 {
00446   return dispatcher->getManifoldByIndexInternal(i);
00447 }
00448 
00449 void BulletPhysics::cleanManifolds()
00450 { //it removes contact points with long lifetime
00451   //std::cout<<dispatcher->getNumManifolds()<<"aa"<<std::endl;
00452   for (int i = 0; i < dispatcher->getNumManifolds(); i++)
00453   {
00454     btPersistentManifold * col = dispatcher->getManifoldByIndexInternal(i);
00455     //std::cout<<col->getNumContacts()<<std::endl;
00456     for (int j = 0; j < col->getNumContacts(); j++)
00457       if (col->getContactPoint(j).getLifeTime() > 300)
00458         col->removeContactPoint(j);
00459 
00460   }
00461 }


uwsim
Author(s): Mario Prats
autogenerated on Mon Oct 6 2014 08:24:07