CommonMultiBodyBase.h 12 KB

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