SerialChains.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  1. #include "SerialChains.h"
  2. #include "../OpenGLWindow/SimpleOpenGL3App.h"
  3. #include "btBulletDynamicsCommon.h"
  4. #include "BulletDynamics/MLCPSolvers/btDantzigSolver.h"
  5. #include "BulletDynamics/MLCPSolvers/btSolveProjectedGaussSeidel.h"
  6. #include "BulletDynamics/Featherstone/btMultiBody.h"
  7. #include "BulletDynamics/Featherstone/btMultiBodyConstraintSolver.h"
  8. #include "BulletDynamics/Featherstone/btMultiBodyMLCPConstraintSolver.h"
  9. #include "BulletDynamics/Featherstone/btMultiBodyDynamicsWorld.h"
  10. #include "BulletDynamics/Featherstone/btMultiBodyLinkCollider.h"
  11. #include "BulletDynamics/Featherstone/btMultiBodyLink.h"
  12. #include "BulletDynamics/Featherstone/btMultiBodyJointLimitConstraint.h"
  13. #include "BulletDynamics/Featherstone/btMultiBodyJointMotor.h"
  14. #include "BulletDynamics/Featherstone/btMultiBodyPoint2Point.h"
  15. #include "BulletDynamics/Featherstone/btMultiBodyFixedConstraint.h"
  16. #include "BulletDynamics/Featherstone/btMultiBodySliderConstraint.h"
  17. #include "../OpenGLWindow/GLInstancingRenderer.h"
  18. #include "BulletCollision/CollisionShapes/btShapeHull.h"
  19. #include "../CommonInterfaces/CommonMultiBodyBase.h"
  20. class SerialChains : public CommonMultiBodyBase
  21. {
  22. public:
  23. SerialChains(GUIHelperInterface* helper);
  24. virtual ~SerialChains();
  25. virtual void initPhysics();
  26. virtual void stepSimulation(float deltaTime);
  27. virtual void resetCamera()
  28. {
  29. float dist = 1;
  30. float pitch = -35;
  31. float yaw = 50;
  32. float targetPos[3] = {-3, 2.8, -2.5};
  33. m_guiHelper->resetCamera(dist, yaw, pitch, targetPos[0], targetPos[1], targetPos[2]);
  34. }
  35. btMultiBody* createFeatherstoneMultiBody(class btMultiBodyDynamicsWorld* world, int numLinks, const btVector3& basePosition, const btVector3& baseHalfExtents, const btVector3& linkHalfExtents, bool spherical = false, bool fixedBase = false);
  36. void createGround(const btVector3& halfExtents = btVector3(50, 50, 50), btScalar zOffSet = btScalar(-1.55));
  37. void addColliders(btMultiBody* pMultiBody, btMultiBodyDynamicsWorld* pWorld, const btVector3& baseHalfExtents, const btVector3& linkHalfExtents);
  38. };
  39. static bool g_fixedBase = true;
  40. static bool g_firstInit = true;
  41. static float scaling = 0.4f;
  42. static float friction = 1.;
  43. static int g_constraintSolverType = 0;
  44. SerialChains::SerialChains(GUIHelperInterface* helper)
  45. : CommonMultiBodyBase(helper)
  46. {
  47. m_guiHelper->setUpAxis(1);
  48. }
  49. SerialChains::~SerialChains()
  50. {
  51. // Do nothing
  52. }
  53. void SerialChains::stepSimulation(float deltaTime)
  54. {
  55. //use a smaller internal timestep, there are stability issues
  56. float internalTimeStep = 1. / 240.f;
  57. m_dynamicsWorld->stepSimulation(deltaTime, 10, internalTimeStep);
  58. }
  59. void SerialChains::initPhysics()
  60. {
  61. m_guiHelper->setUpAxis(1);
  62. if (g_firstInit)
  63. {
  64. m_guiHelper->getRenderInterface()->getActiveCamera()->setCameraDistance(btScalar(10. * scaling));
  65. m_guiHelper->getRenderInterface()->getActiveCamera()->setCameraPitch(50);
  66. g_firstInit = false;
  67. }
  68. ///collision configuration contains default setup for memory, collision setup
  69. m_collisionConfiguration = new btDefaultCollisionConfiguration();
  70. ///use the default collision dispatcher. For parallel processing you can use a diffent dispatcher (see Extras/BulletMultiThreaded)
  71. m_dispatcher = new btCollisionDispatcher(m_collisionConfiguration);
  72. m_broadphase = new btDbvtBroadphase();
  73. if (g_constraintSolverType == 3)
  74. {
  75. g_constraintSolverType = 0;
  76. g_fixedBase = !g_fixedBase;
  77. }
  78. btMLCPSolverInterface* mlcp;
  79. switch (g_constraintSolverType++)
  80. {
  81. case 0:
  82. m_solver = new btMultiBodyConstraintSolver;
  83. b3Printf("Constraint Solver: Sequential Impulse");
  84. break;
  85. case 1:
  86. mlcp = new btSolveProjectedGaussSeidel();
  87. m_solver = new btMultiBodyMLCPConstraintSolver(mlcp);
  88. b3Printf("Constraint Solver: MLCP + PGS");
  89. break;
  90. default:
  91. mlcp = new btDantzigSolver();
  92. m_solver = new btMultiBodyMLCPConstraintSolver(mlcp);
  93. b3Printf("Constraint Solver: MLCP + Dantzig");
  94. break;
  95. }
  96. btMultiBodyDynamicsWorld* world = new btMultiBodyDynamicsWorld(m_dispatcher, m_broadphase, m_solver, m_collisionConfiguration);
  97. m_dynamicsWorld = world;
  98. m_guiHelper->createPhysicsDebugDrawer(m_dynamicsWorld);
  99. m_dynamicsWorld->setGravity(btVector3(0, -10, 0));
  100. m_dynamicsWorld->getSolverInfo().m_globalCfm = btScalar(1e-4); //todo: what value is good?
  101. ///create a few basic rigid bodies
  102. btVector3 groundHalfExtents(50, 50, 50);
  103. btCollisionShape* groundShape = new btBoxShape(groundHalfExtents);
  104. m_collisionShapes.push_back(groundShape);
  105. btTransform groundTransform;
  106. groundTransform.setIdentity();
  107. groundTransform.setOrigin(btVector3(0, -50, 00));
  108. /////////////////////////////////////////////////////////////////
  109. /////////////////////////////////////////////////////////////////
  110. bool damping = true;
  111. bool gyro = true;
  112. int numLinks = 5;
  113. bool spherical = true; //set it ot false -to use 1DoF hinges instead of 3DoF sphericals
  114. bool multibodyOnly = true; //false
  115. bool canSleep = true;
  116. bool selfCollide = true;
  117. btVector3 linkHalfExtents(0.05, 0.37, 0.1);
  118. btVector3 baseHalfExtents(0.05, 0.37, 0.1);
  119. btMultiBody* mbC1 = createFeatherstoneMultiBody(world, numLinks, btVector3(-0.4f, 3.f, 0.f), linkHalfExtents, baseHalfExtents, spherical, g_fixedBase);
  120. btMultiBody* mbC2 = createFeatherstoneMultiBody(world, numLinks, btVector3(-0.4f, 3.0f, 0.5f), linkHalfExtents, baseHalfExtents, spherical, g_fixedBase);
  121. mbC1->setCanSleep(canSleep);
  122. mbC1->setHasSelfCollision(selfCollide);
  123. mbC1->setUseGyroTerm(gyro);
  124. if (!damping)
  125. {
  126. mbC1->setLinearDamping(0.f);
  127. mbC1->setAngularDamping(0.f);
  128. }
  129. else
  130. {
  131. mbC1->setLinearDamping(0.1f);
  132. mbC1->setAngularDamping(0.9f);
  133. }
  134. //
  135. m_dynamicsWorld->setGravity(btVector3(0, -9.81, 0));
  136. //////////////////////////////////////////////
  137. if (numLinks > 0)
  138. {
  139. btScalar q0 = 45.f * SIMD_PI / 180.f;
  140. if (!spherical)
  141. {
  142. mbC1->setJointPosMultiDof(0, &q0);
  143. }
  144. else
  145. {
  146. btQuaternion quat0(btVector3(1, 1, 0).normalized(), q0);
  147. quat0.normalize();
  148. mbC1->setJointPosMultiDof(0, quat0);
  149. }
  150. }
  151. ///
  152. addColliders(mbC1, world, baseHalfExtents, linkHalfExtents);
  153. mbC2->setCanSleep(canSleep);
  154. mbC2->setHasSelfCollision(selfCollide);
  155. mbC2->setUseGyroTerm(gyro);
  156. //
  157. if (!damping)
  158. {
  159. mbC2->setLinearDamping(0.f);
  160. mbC2->setAngularDamping(0.f);
  161. }
  162. else
  163. {
  164. mbC2->setLinearDamping(0.1f);
  165. mbC2->setAngularDamping(0.9f);
  166. }
  167. //
  168. m_dynamicsWorld->setGravity(btVector3(0, -9.81, 0));
  169. //////////////////////////////////////////////
  170. if (numLinks > 0)
  171. {
  172. btScalar q0 = -45.f * SIMD_PI / 180.f;
  173. if (!spherical)
  174. {
  175. mbC2->setJointPosMultiDof(0, &q0);
  176. }
  177. else
  178. {
  179. btQuaternion quat0(btVector3(1, 1, 0).normalized(), q0);
  180. quat0.normalize();
  181. mbC2->setJointPosMultiDof(0, quat0);
  182. }
  183. }
  184. ///
  185. addColliders(mbC2, world, baseHalfExtents, linkHalfExtents);
  186. /////////////////////////////////////////////////////////////////
  187. btScalar groundHeight = -51.55;
  188. btScalar mass(0.);
  189. //rigidbody is dynamic if and only if mass is non zero, otherwise static
  190. bool isDynamic = (mass != 0.f);
  191. btVector3 localInertia(0, 0, 0);
  192. if (isDynamic)
  193. groundShape->calculateLocalInertia(mass, localInertia);
  194. //using motionstate is recommended, it provides interpolation capabilities, and only synchronizes 'active' objects
  195. groundTransform.setIdentity();
  196. groundTransform.setOrigin(btVector3(0, groundHeight, 0));
  197. btDefaultMotionState* myMotionState = new btDefaultMotionState(groundTransform);
  198. btRigidBody::btRigidBodyConstructionInfo rbInfo(mass, myMotionState, groundShape, localInertia);
  199. btRigidBody* body = new btRigidBody(rbInfo);
  200. //add the body to the dynamics world
  201. m_dynamicsWorld->addRigidBody(body, 1, 1 + 2); //,1,1+2);
  202. /////////////////////////////////////////////////////////////////
  203. createGround();
  204. m_guiHelper->autogenerateGraphicsObjects(m_dynamicsWorld);
  205. /////////////////////////////////////////////////////////////////
  206. }
  207. btMultiBody* SerialChains::createFeatherstoneMultiBody(btMultiBodyDynamicsWorld* pWorld, int numLinks, const btVector3& basePosition, const btVector3& baseHalfExtents, const btVector3& linkHalfExtents, bool spherical, bool fixedBase)
  208. {
  209. //init the base
  210. btVector3 baseInertiaDiag(0.f, 0.f, 0.f);
  211. float baseMass = 1.f;
  212. if (baseMass)
  213. {
  214. btCollisionShape* pTempBox = new btBoxShape(btVector3(baseHalfExtents[0], baseHalfExtents[1], baseHalfExtents[2]));
  215. pTempBox->calculateLocalInertia(baseMass, baseInertiaDiag);
  216. delete pTempBox;
  217. }
  218. bool canSleep = false;
  219. btMultiBody* pMultiBody = new btMultiBody(numLinks, baseMass, baseInertiaDiag, fixedBase, canSleep);
  220. btQuaternion baseOriQuat(0.f, 0.f, 0.f, 1.f);
  221. pMultiBody->setBasePos(basePosition);
  222. pMultiBody->setWorldToBaseRot(baseOriQuat);
  223. btVector3 vel(0, 0, 0);
  224. //init the links
  225. btVector3 hingeJointAxis(1, 0, 0);
  226. float linkMass = 1.f;
  227. btVector3 linkInertiaDiag(0.f, 0.f, 0.f);
  228. btCollisionShape* pTempBox = new btBoxShape(btVector3(linkHalfExtents[0], linkHalfExtents[1], linkHalfExtents[2]));
  229. pTempBox->calculateLocalInertia(linkMass, linkInertiaDiag);
  230. delete pTempBox;
  231. //y-axis assumed up
  232. btVector3 parentComToCurrentCom(0, -linkHalfExtents[1] * 2.f, 0); //par body's COM to cur body's COM offset
  233. btVector3 currentPivotToCurrentCom(0, -linkHalfExtents[1], 0); //cur body's COM to cur body's PIV offset
  234. btVector3 parentComToCurrentPivot = parentComToCurrentCom - currentPivotToCurrentCom; //par body's COM to cur body's PIV offset
  235. //////
  236. btScalar q0 = 0.f * SIMD_PI / 180.f;
  237. btQuaternion quat0(btVector3(0, 1, 0).normalized(), q0);
  238. quat0.normalize();
  239. /////
  240. for (int i = 0; i < numLinks; ++i)
  241. {
  242. if (!spherical)
  243. pMultiBody->setupRevolute(i, linkMass, linkInertiaDiag, i - 1, btQuaternion(0.f, 0.f, 0.f, 1.f), hingeJointAxis, parentComToCurrentPivot, currentPivotToCurrentCom, true);
  244. else
  245. //pMultiBody->setupPlanar(i, linkMass, linkInertiaDiag, i - 1, btQuaternion(0.f, 0.f, 0.f, 1.f)/*quat0*/, btVector3(1, 0, 0), parentComToCurrentPivot*2, false);
  246. pMultiBody->setupSpherical(i, linkMass, linkInertiaDiag, i - 1, btQuaternion(0.f, 0.f, 0.f, 1.f), parentComToCurrentPivot, currentPivotToCurrentCom, true);
  247. }
  248. pMultiBody->finalizeMultiDof();
  249. ///
  250. pWorld->addMultiBody(pMultiBody);
  251. ///
  252. return pMultiBody;
  253. }
  254. void SerialChains::createGround(const btVector3& halfExtents, btScalar zOffSet)
  255. {
  256. btCollisionShape* groundShape = new btBoxShape(halfExtents);
  257. m_collisionShapes.push_back(groundShape);
  258. // rigidbody is dynamic if and only if mass is non zero, otherwise static
  259. btScalar mass(0.);
  260. const bool isDynamic = (mass != 0.f);
  261. btVector3 localInertia(0, 0, 0);
  262. if (isDynamic)
  263. groundShape->calculateLocalInertia(mass, localInertia);
  264. // using motionstate is recommended, it provides interpolation capabilities, and only synchronizes 'active' objects
  265. btTransform groundTransform;
  266. groundTransform.setIdentity();
  267. groundTransform.setOrigin(btVector3(0, -halfExtents.z() + zOffSet, 0));
  268. btDefaultMotionState* myMotionState = new btDefaultMotionState(groundTransform);
  269. btRigidBody::btRigidBodyConstructionInfo rbInfo(mass, myMotionState, groundShape, localInertia);
  270. btRigidBody* body = new btRigidBody(rbInfo);
  271. // add the body to the dynamics world
  272. m_dynamicsWorld->addRigidBody(body, 1, 1 + 2);
  273. }
  274. void SerialChains::addColliders(btMultiBody* pMultiBody, btMultiBodyDynamicsWorld* pWorld, const btVector3& baseHalfExtents, const btVector3& linkHalfExtents)
  275. {
  276. btAlignedObjectArray<btQuaternion> world_to_local;
  277. world_to_local.resize(pMultiBody->getNumLinks() + 1);
  278. btAlignedObjectArray<btVector3> local_origin;
  279. local_origin.resize(pMultiBody->getNumLinks() + 1);
  280. world_to_local[0] = pMultiBody->getWorldToBaseRot();
  281. local_origin[0] = pMultiBody->getBasePos();
  282. {
  283. btScalar quat[4] = {-world_to_local[0].x(), -world_to_local[0].y(), -world_to_local[0].z(), world_to_local[0].w()};
  284. if (1)
  285. {
  286. btCollisionShape* box = new btBoxShape(baseHalfExtents);
  287. btMultiBodyLinkCollider* col = new btMultiBodyLinkCollider(pMultiBody, -1);
  288. col->setCollisionShape(box);
  289. btTransform tr;
  290. tr.setIdentity();
  291. tr.setOrigin(local_origin[0]);
  292. tr.setRotation(btQuaternion(quat[0], quat[1], quat[2], quat[3]));
  293. col->setWorldTransform(tr);
  294. pWorld->addCollisionObject(col, 2, 1 + 2);
  295. col->setFriction(friction);
  296. pMultiBody->setBaseCollider(col);
  297. }
  298. }
  299. for (int i = 0; i < pMultiBody->getNumLinks(); ++i)
  300. {
  301. const int parent = pMultiBody->getParent(i);
  302. world_to_local[i + 1] = pMultiBody->getParentToLocalRot(i) * world_to_local[parent + 1];
  303. local_origin[i + 1] = local_origin[parent + 1] + (quatRotate(world_to_local[i + 1].inverse(), pMultiBody->getRVector(i)));
  304. }
  305. for (int i = 0; i < pMultiBody->getNumLinks(); ++i)
  306. {
  307. btVector3 posr = local_origin[i + 1];
  308. btScalar quat[4] = {-world_to_local[i + 1].x(), -world_to_local[i + 1].y(), -world_to_local[i + 1].z(), world_to_local[i + 1].w()};
  309. btCollisionShape* box = new btBoxShape(linkHalfExtents);
  310. btMultiBodyLinkCollider* col = new btMultiBodyLinkCollider(pMultiBody, i);
  311. col->setCollisionShape(box);
  312. btTransform tr;
  313. tr.setIdentity();
  314. tr.setOrigin(posr);
  315. tr.setRotation(btQuaternion(quat[0], quat[1], quat[2], quat[3]));
  316. col->setWorldTransform(tr);
  317. col->setFriction(friction);
  318. pWorld->addCollisionObject(col, 2, 1 + 2);
  319. pMultiBody->getLink(i).m_collider = col;
  320. }
  321. }
  322. CommonExampleInterface* SerialChainsCreateFunc(CommonExampleOptions& options)
  323. {
  324. return new SerialChains(options.m_guiHelper);
  325. }