CommonMultiBodyBase.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524
  1. #ifndef COMMON_MULTI_BODY_SETUP_H
  2. #define COMMON_MULTI_BODY_SETUP_H
  3. #include "btBulletDynamicsCommon.h"
  4. #include "BulletDynamics/Featherstone/btMultiBodyDynamicsWorld.h"
  5. #include "BulletDynamics/Featherstone/btMultiBodyConstraintSolver.h"
  6. #include "BulletDynamics/Featherstone/btMultiBodyPoint2Point.h"
  7. #include "BulletDynamics/Featherstone/btMultiBodyLinkCollider.h"
  8. #include "btBulletDynamicsCommon.h"
  9. #include "CommonExampleInterface.h"
  10. #include "CommonGUIHelperInterface.h"
  11. #include "CommonRenderInterface.h"
  12. #include "CommonGraphicsAppInterface.h"
  13. #include "CommonWindowInterface.h"
  14. #include "CommonCameraInterface.h"
  15. enum MyFilterModes
  16. {
  17. FILTER_GROUPAMASKB_AND_GROUPBMASKA2 = 0,
  18. FILTER_GROUPAMASKB_OR_GROUPBMASKA2
  19. };
  20. struct MyOverlapFilterCallback2 : public btOverlapFilterCallback
  21. {
  22. int m_filterMode;
  23. MyOverlapFilterCallback2()
  24. : m_filterMode(FILTER_GROUPAMASKB_AND_GROUPBMASKA2)
  25. {
  26. }
  27. virtual ~MyOverlapFilterCallback2()
  28. {
  29. }
  30. // return true when pairs need collision
  31. virtual bool needBroadphaseCollision(btBroadphaseProxy* proxy0, btBroadphaseProxy* proxy1) const
  32. {
  33. if (m_filterMode == FILTER_GROUPAMASKB_AND_GROUPBMASKA2)
  34. {
  35. bool collides = (proxy0->m_collisionFilterGroup & proxy1->m_collisionFilterMask) != 0;
  36. collides = collides && (proxy1->m_collisionFilterGroup & proxy0->m_collisionFilterMask);
  37. return collides;
  38. }
  39. if (m_filterMode == FILTER_GROUPAMASKB_OR_GROUPBMASKA2)
  40. {
  41. bool collides = (proxy0->m_collisionFilterGroup & proxy1->m_collisionFilterMask) != 0;
  42. collides = collides || (proxy1->m_collisionFilterGroup & proxy0->m_collisionFilterMask);
  43. return collides;
  44. }
  45. return false;
  46. }
  47. };
  48. struct CommonMultiBodyBase : public CommonExampleInterface
  49. {
  50. //keep the collision shapes, for deletion/cleanup
  51. btAlignedObjectArray<btCollisionShape*> m_collisionShapes;
  52. MyOverlapFilterCallback2* m_filterCallback;
  53. btOverlappingPairCache* m_pairCache;
  54. btBroadphaseInterface* m_broadphase;
  55. btCollisionDispatcher* m_dispatcher;
  56. btMultiBodyConstraintSolver* m_solver;
  57. btDefaultCollisionConfiguration* m_collisionConfiguration;
  58. btMultiBodyDynamicsWorld* m_dynamicsWorld;
  59. //data for picking objects
  60. class btRigidBody* m_pickedBody;
  61. class btTypedConstraint* m_pickedConstraint;
  62. class btMultiBodyPoint2Point* m_pickingMultiBodyPoint2Point;
  63. btVector3 m_oldPickingPos;
  64. btVector3 m_hitPos;
  65. btScalar m_oldPickingDist;
  66. bool m_prevCanSleep;
  67. struct GUIHelperInterface* m_guiHelper;
  68. CommonMultiBodyBase(GUIHelperInterface* helper)
  69. : m_filterCallback(0),
  70. m_pairCache(0),
  71. m_broadphase(0),
  72. m_dispatcher(0),
  73. m_solver(0),
  74. m_collisionConfiguration(0),
  75. m_dynamicsWorld(0),
  76. m_pickedBody(0),
  77. m_pickedConstraint(0),
  78. m_pickingMultiBodyPoint2Point(0),
  79. m_prevCanSleep(false),
  80. m_guiHelper(helper)
  81. {
  82. }
  83. virtual void createEmptyDynamicsWorld()
  84. {
  85. ///collision configuration contains default setup for memory, collision setup
  86. m_collisionConfiguration = new btDefaultCollisionConfiguration();
  87. //m_collisionConfiguration->setConvexConvexMultipointIterations();
  88. m_filterCallback = new MyOverlapFilterCallback2();
  89. ///use the default collision dispatcher. For parallel processing you can use a diffent dispatcher (see Extras/BulletMultiThreaded)
  90. m_dispatcher = new btCollisionDispatcher(m_collisionConfiguration);
  91. m_pairCache = new btHashedOverlappingPairCache();
  92. m_pairCache->setOverlapFilterCallback(m_filterCallback);
  93. m_broadphase = new btDbvtBroadphase(m_pairCache); //btSimpleBroadphase();
  94. m_solver = new btMultiBodyConstraintSolver;
  95. m_dynamicsWorld = new btMultiBodyDynamicsWorld(m_dispatcher, m_broadphase, m_solver, m_collisionConfiguration);
  96. m_dynamicsWorld->setGravity(btVector3(0, -10, 0));
  97. }
  98. virtual void stepSimulation(float deltaTime)
  99. {
  100. if (m_dynamicsWorld)
  101. {
  102. m_dynamicsWorld->stepSimulation(deltaTime);
  103. }
  104. }
  105. virtual void exitPhysics()
  106. {
  107. removePickingConstraint();
  108. //cleanup in the reverse order of creation/initialization
  109. //remove the rigidbodies from the dynamics world and delete them
  110. if (m_dynamicsWorld)
  111. {
  112. int i;
  113. for (i = m_dynamicsWorld->getNumConstraints() - 1; i >= 0; i--)
  114. {
  115. m_dynamicsWorld->removeConstraint(m_dynamicsWorld->getConstraint(i));
  116. }
  117. for (i = m_dynamicsWorld->getNumMultiBodyConstraints() - 1; i >= 0; i--)
  118. {
  119. btMultiBodyConstraint* mbc = m_dynamicsWorld->getMultiBodyConstraint(i);
  120. m_dynamicsWorld->removeMultiBodyConstraint(mbc);
  121. delete mbc;
  122. }
  123. for (i = m_dynamicsWorld->getNumMultibodies() - 1; i >= 0; i--)
  124. {
  125. btMultiBody* mb = m_dynamicsWorld->getMultiBody(i);
  126. m_dynamicsWorld->removeMultiBody(mb);
  127. delete mb;
  128. }
  129. for (i = m_dynamicsWorld->getNumCollisionObjects() - 1; i >= 0; i--)
  130. {
  131. btCollisionObject* obj = m_dynamicsWorld->getCollisionObjectArray()[i];
  132. btRigidBody* body = btRigidBody::upcast(obj);
  133. if (body && body->getMotionState())
  134. {
  135. delete body->getMotionState();
  136. }
  137. m_dynamicsWorld->removeCollisionObject(obj);
  138. delete obj;
  139. }
  140. }
  141. //delete collision shapes
  142. for (int j = 0; j < m_collisionShapes.size(); j++)
  143. {
  144. btCollisionShape* shape = m_collisionShapes[j];
  145. delete shape;
  146. }
  147. m_collisionShapes.clear();
  148. delete m_dynamicsWorld;
  149. m_dynamicsWorld = 0;
  150. delete m_solver;
  151. m_solver = 0;
  152. delete m_broadphase;
  153. m_broadphase = 0;
  154. delete m_dispatcher;
  155. m_dispatcher = 0;
  156. delete m_pairCache;
  157. m_pairCache = 0;
  158. delete m_filterCallback;
  159. m_filterCallback = 0;
  160. delete m_collisionConfiguration;
  161. m_collisionConfiguration = 0;
  162. }
  163. virtual void syncPhysicsToGraphics()
  164. {
  165. if (m_dynamicsWorld)
  166. {
  167. m_guiHelper->syncPhysicsToGraphics(m_dynamicsWorld);
  168. }
  169. }
  170. virtual void renderScene()
  171. {
  172. if (m_dynamicsWorld)
  173. {
  174. m_guiHelper->syncPhysicsToGraphics(m_dynamicsWorld);
  175. m_guiHelper->render(m_dynamicsWorld);
  176. }
  177. }
  178. virtual void physicsDebugDraw(int debugDrawFlags)
  179. {
  180. if (m_dynamicsWorld)
  181. {
  182. if (m_dynamicsWorld->getDebugDrawer())
  183. {
  184. m_dynamicsWorld->getDebugDrawer()->setDebugMode(debugDrawFlags);
  185. }
  186. m_dynamicsWorld->debugDrawWorld();
  187. }
  188. }
  189. virtual bool keyboardCallback(int key, int state)
  190. {
  191. if ((key == B3G_F3) && state && m_dynamicsWorld)
  192. {
  193. btDefaultSerializer* serializer = new btDefaultSerializer();
  194. m_dynamicsWorld->serialize(serializer);
  195. FILE* file = fopen("testFile.bullet", "wb");
  196. fwrite(serializer->getBufferPointer(), serializer->getCurrentBufferSize(), 1, file);
  197. fclose(file);
  198. //b3Printf("btDefaultSerializer wrote testFile.bullet");
  199. delete serializer;
  200. return true;
  201. }
  202. return false; //don't handle this key
  203. }
  204. btVector3 getRayTo(int x, int y)
  205. {
  206. CommonRenderInterface* renderer = m_guiHelper->getRenderInterface();
  207. if (!renderer)
  208. {
  209. btAssert(0);
  210. return btVector3(0, 0, 0);
  211. }
  212. float top = 1.f;
  213. float bottom = -1.f;
  214. float nearPlane = 1.f;
  215. float tanFov = (top - bottom) * 0.5f / nearPlane;
  216. float fov = btScalar(2.0) * btAtan(tanFov);
  217. btVector3 camPos, camTarget;
  218. renderer->getActiveCamera()->getCameraPosition(camPos);
  219. renderer->getActiveCamera()->getCameraTargetPosition(camTarget);
  220. btVector3 rayFrom = camPos;
  221. btVector3 rayForward = (camTarget - camPos);
  222. rayForward.normalize();
  223. float farPlane = 10000.f;
  224. rayForward *= farPlane;
  225. btVector3 rightOffset;
  226. btVector3 cameraUp = btVector3(0, 0, 0);
  227. cameraUp[m_guiHelper->getAppInterface()->getUpAxis()] = 1;
  228. btVector3 vertical = cameraUp;
  229. btVector3 hor;
  230. hor = rayForward.cross(vertical);
  231. hor.normalize();
  232. vertical = hor.cross(rayForward);
  233. vertical.normalize();
  234. float tanfov = tanf(0.5f * fov);
  235. hor *= 2.f * farPlane * tanfov;
  236. vertical *= 2.f * farPlane * tanfov;
  237. btScalar aspect;
  238. float width = float(renderer->getScreenWidth());
  239. float height = float(renderer->getScreenHeight());
  240. aspect = width / height;
  241. hor *= aspect;
  242. btVector3 rayToCenter = rayFrom + rayForward;
  243. btVector3 dHor = hor * 1.f / width;
  244. btVector3 dVert = vertical * 1.f / height;
  245. btVector3 rayTo = rayToCenter - 0.5f * hor + 0.5f * vertical;
  246. rayTo += btScalar(x) * dHor;
  247. rayTo -= btScalar(y) * dVert;
  248. return rayTo;
  249. }
  250. virtual bool mouseMoveCallback(float x, float y)
  251. {
  252. CommonRenderInterface* renderer = m_guiHelper->getRenderInterface();
  253. if (!renderer)
  254. {
  255. btAssert(0);
  256. return false;
  257. }
  258. btVector3 rayTo = getRayTo(int(x), int(y));
  259. btVector3 rayFrom;
  260. renderer->getActiveCamera()->getCameraPosition(rayFrom);
  261. movePickedBody(rayFrom, rayTo);
  262. return false;
  263. }
  264. virtual bool mouseButtonCallback(int button, int state, float x, float y)
  265. {
  266. CommonRenderInterface* renderer = m_guiHelper->getRenderInterface();
  267. if (!renderer)
  268. {
  269. btAssert(0);
  270. return false;
  271. }
  272. CommonWindowInterface* window = m_guiHelper->getAppInterface()->m_window;
  273. if (state == 1)
  274. {
  275. if (button == 0 && (!window->isModifierKeyPressed(B3G_ALT) && !window->isModifierKeyPressed(B3G_CONTROL)))
  276. {
  277. btVector3 camPos;
  278. renderer->getActiveCamera()->getCameraPosition(camPos);
  279. btVector3 rayFrom = camPos;
  280. btVector3 rayTo = getRayTo(int(x), int(y));
  281. pickBody(rayFrom, rayTo);
  282. }
  283. }
  284. else
  285. {
  286. if (button == 0)
  287. {
  288. removePickingConstraint();
  289. //remove p2p
  290. }
  291. }
  292. //printf("button=%d, state=%d\n",button,state);
  293. return false;
  294. }
  295. virtual bool pickBody(const btVector3& rayFromWorld, const btVector3& rayToWorld)
  296. {
  297. if (m_dynamicsWorld == 0)
  298. return false;
  299. btCollisionWorld::ClosestRayResultCallback rayCallback(rayFromWorld, rayToWorld);
  300. m_dynamicsWorld->rayTest(rayFromWorld, rayToWorld, rayCallback);
  301. if (rayCallback.hasHit())
  302. {
  303. btVector3 pickPos = rayCallback.m_hitPointWorld;
  304. btRigidBody* body = (btRigidBody*)btRigidBody::upcast(rayCallback.m_collisionObject);
  305. if (body)
  306. {
  307. //other exclusions?
  308. if (!(body->isStaticObject() || body->isKinematicObject()))
  309. {
  310. m_pickedBody = body;
  311. m_pickedBody->setActivationState(DISABLE_DEACTIVATION);
  312. //printf("pickPos=%f,%f,%f\n",pickPos.getX(),pickPos.getY(),pickPos.getZ());
  313. btVector3 localPivot = body->getCenterOfMassTransform().inverse() * pickPos;
  314. btPoint2PointConstraint* p2p = new btPoint2PointConstraint(*body, localPivot);
  315. m_dynamicsWorld->addConstraint(p2p, true);
  316. m_pickedConstraint = p2p;
  317. btScalar mousePickClamping = 30.f;
  318. p2p->m_setting.m_impulseClamp = mousePickClamping;
  319. //very weak constraint for picking
  320. p2p->m_setting.m_tau = 0.001f;
  321. }
  322. }
  323. else
  324. {
  325. btMultiBodyLinkCollider* multiCol = (btMultiBodyLinkCollider*)btMultiBodyLinkCollider::upcast(rayCallback.m_collisionObject);
  326. if (multiCol && multiCol->m_multiBody)
  327. {
  328. m_prevCanSleep = multiCol->m_multiBody->getCanSleep();
  329. multiCol->m_multiBody->setCanSleep(false);
  330. btVector3 pivotInA = multiCol->m_multiBody->worldPosToLocal(multiCol->m_link, pickPos);
  331. btMultiBodyPoint2Point* p2p = new btMultiBodyPoint2Point(multiCol->m_multiBody, multiCol->m_link, 0, pivotInA, pickPos);
  332. //if you add too much energy to the system, causing high angular velocities, simulation 'explodes'
  333. //see also http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?f=4&t=949
  334. //so we try to avoid it by clamping the maximum impulse (force) that the mouse pick can apply
  335. //it is not satisfying, hopefully we find a better solution (higher order integrator, using joint friction using a zero-velocity target motor with limited force etc?)
  336. btScalar scaling = 1;
  337. p2p->setMaxAppliedImpulse(2 * scaling);
  338. btMultiBodyDynamicsWorld* world = (btMultiBodyDynamicsWorld*)m_dynamicsWorld;
  339. world->addMultiBodyConstraint(p2p);
  340. m_pickingMultiBodyPoint2Point = p2p;
  341. }
  342. }
  343. // pickObject(pickPos, rayCallback.m_collisionObject);
  344. m_oldPickingPos = rayToWorld;
  345. m_hitPos = pickPos;
  346. m_oldPickingDist = (pickPos - rayFromWorld).length();
  347. // printf("hit !\n");
  348. //add p2p
  349. }
  350. return false;
  351. }
  352. virtual bool movePickedBody(const btVector3& rayFromWorld, const btVector3& rayToWorld)
  353. {
  354. if (m_pickedBody && m_pickedConstraint)
  355. {
  356. btPoint2PointConstraint* pickCon = static_cast<btPoint2PointConstraint*>(m_pickedConstraint);
  357. if (pickCon)
  358. {
  359. //keep it at the same picking distance
  360. btVector3 dir = rayToWorld - rayFromWorld;
  361. dir.normalize();
  362. dir *= m_oldPickingDist;
  363. btVector3 newPivotB = rayFromWorld + dir;
  364. pickCon->setPivotB(newPivotB);
  365. }
  366. }
  367. if (m_pickingMultiBodyPoint2Point)
  368. {
  369. //keep it at the same picking distance
  370. btVector3 dir = rayToWorld - rayFromWorld;
  371. dir.normalize();
  372. dir *= m_oldPickingDist;
  373. btVector3 newPivotB = rayFromWorld + dir;
  374. m_pickingMultiBodyPoint2Point->setPivotInB(newPivotB);
  375. }
  376. return false;
  377. }
  378. virtual void removePickingConstraint()
  379. {
  380. if (m_pickedConstraint)
  381. {
  382. m_dynamicsWorld->removeConstraint(m_pickedConstraint);
  383. if (m_pickedBody)
  384. {
  385. m_pickedBody->forceActivationState(ACTIVE_TAG);
  386. m_pickedBody->activate(true);
  387. }
  388. delete m_pickedConstraint;
  389. m_pickedConstraint = 0;
  390. m_pickedBody = 0;
  391. }
  392. if (m_pickingMultiBodyPoint2Point)
  393. {
  394. m_pickingMultiBodyPoint2Point->getMultiBodyA()->setCanSleep(m_prevCanSleep);
  395. btMultiBodyDynamicsWorld* world = (btMultiBodyDynamicsWorld*)m_dynamicsWorld;
  396. world->removeMultiBodyConstraint(m_pickingMultiBodyPoint2Point);
  397. delete m_pickingMultiBodyPoint2Point;
  398. m_pickingMultiBodyPoint2Point = 0;
  399. }
  400. }
  401. btBoxShape* createBoxShape(const btVector3& halfExtents)
  402. {
  403. btBoxShape* box = new btBoxShape(halfExtents);
  404. return box;
  405. }
  406. btRigidBody* createRigidBody(float mass, const btTransform& startTransform, btCollisionShape* shape, const btVector4& color = btVector4(1, 0, 0, 1))
  407. {
  408. btAssert((!shape || shape->getShapeType() != INVALID_SHAPE_PROXYTYPE));
  409. //rigidbody is dynamic if and only if mass is non zero, otherwise static
  410. bool isDynamic = (mass != 0.f);
  411. btVector3 localInertia(0, 0, 0);
  412. if (isDynamic)
  413. shape->calculateLocalInertia(mass, localInertia);
  414. //using motionstate is recommended, it provides interpolation capabilities, and only synchronizes 'active' objects
  415. #define USE_MOTIONSTATE 1
  416. #ifdef USE_MOTIONSTATE
  417. btDefaultMotionState* myMotionState = new btDefaultMotionState(startTransform);
  418. btRigidBody::btRigidBodyConstructionInfo cInfo(mass, myMotionState, shape, localInertia);
  419. btRigidBody* body = new btRigidBody(cInfo);
  420. //body->setContactProcessingThreshold(m_defaultContactProcessingThreshold);
  421. #else
  422. btRigidBody* body = new btRigidBody(mass, 0, shape, localInertia);
  423. body->setWorldTransform(startTransform);
  424. #endif //
  425. body->setUserIndex(-1);
  426. m_dynamicsWorld->addRigidBody(body);
  427. return body;
  428. }
  429. };
  430. #endif //COMMON_MULTI_BODY_SETUP_H