00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #include <uwsim/BulletPhysics.h>
00014
00015
00016 unsigned int vehicleCollidesWith(COL_OBJECTS);
00017 unsigned int objectsCollidesWith(COL_EVERYTHING);
00018
00019
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
00036 }
00037
00038 protected:
00039 btRigidBody * copy;
00040
00041 };
00042
00043
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);
00052 btRigidBody* body = new btRigidBody(rb);
00053
00054 CollisionDataType * colData = new CollisionDataType("copied", "copied", 1);
00055 body->setUserPointer(colData);
00056
00057
00058
00059 body->setDamping(copied->getLinearDamping(), copied->getAngularDamping());
00060
00061
00062 dynamicsWorld->addRigidBody(body);
00063
00064
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
00098 boost::shared_ptr<osg::Matrix> mat = getWorldCoords(transf->getParent(0));
00099
00100
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
00108 osg::Matrixd rootmat = worldMatrix * (mat->inverse(*mat));
00109
00110
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
00126
00127
00128 if (fluid)
00129 updateOceanSurface();
00130 physicsStep=1;
00131 ((btDynamicsWorld*)dynamicsWorld)->stepSimulation(timeStep, maxSubSteps, fixedTimeStep);
00132 physicsStep=0;
00133 }
00134
00135 void BulletPhysics::printManifolds()
00136 {
00137
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
00188 btTransform xform;
00189 xform.setIdentity();
00190 xform.getOrigin() = btVector3(physicsWater.position[0], physicsWater.position[1], physicsWater.position[2]);
00191
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
00207
00208
00209
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
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;
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)
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 {
00317 if (not (pp->minAngularLimit[0] < pp->maxAngularLimit[0] or pp->minAngularLimit[2] < pp->maxAngularLimit[2]))
00318 {
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 }
00328 else if (pp->minAngularLimit[1] <= -1.50 || pp->minAngularLimit[1] >= 1.50)
00329 {
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
00346
00347
00348 body->setDamping(pp->linearDamping, pp->angularDamping);
00349
00350
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
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
00426
00427
00428 body->setDamping(pp->linearDamping, pp->angularDamping);
00429
00430
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 {
00451
00452 for (int i = 0; i < dispatcher->getNumManifolds(); i++)
00453 {
00454 btPersistentManifold * col = dispatcher->getManifoldByIndexInternal(i);
00455
00456 for (int j = 0; j < col->getNumContacts(); j++)
00457 if (col->getContactPoint(j).getLifeTime() > 300)
00458 col->removeContactPoint(j);
00459
00460 }
00461 }