CommonMultiBodyBase.h 13 KB

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