MotorDemo.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450
  1. /*
  2. Bullet Continuous Collision Detection and Physics Library Copyright (c) 2007 Erwin Coumans
  3. Motor Demo
  4. This software is provided 'as-is', without any express or implied warranty.
  5. In no event will the authors be held liable for any damages arising from the use of this software.
  6. Permission is granted to anyone to use this software for any purpose,
  7. including commercial applications, and to alter it and redistribute it freely,
  8. subject to the following restrictions:
  9. 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
  10. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
  11. 3. This notice may not be removed or altered from any source distribution.
  12. */
  13. #include "btBulletDynamicsCommon.h"
  14. #include "LinearMath/btIDebugDraw.h"
  15. #include "MotorDemo.h"
  16. #include "LinearMath/btAlignedObjectArray.h"
  17. class btBroadphaseInterface;
  18. class btCollisionShape;
  19. class btOverlappingPairCache;
  20. class btCollisionDispatcher;
  21. class btConstraintSolver;
  22. struct btCollisionAlgorithmCreateFunc;
  23. class btDefaultCollisionConfiguration;
  24. #include "../CommonInterfaces/CommonRigidBodyBase.h"
  25. class MotorDemo : public CommonRigidBodyBase
  26. {
  27. float m_Time;
  28. float m_fCyclePeriod; // in milliseconds
  29. float m_fMuscleStrength;
  30. btAlignedObjectArray<class TestRig*> m_rigs;
  31. public:
  32. MotorDemo(struct GUIHelperInterface* helper)
  33. :CommonRigidBodyBase(helper)
  34. {
  35. }
  36. void initPhysics();
  37. void exitPhysics();
  38. virtual ~MotorDemo()
  39. {
  40. }
  41. void spawnTestRig(const btVector3& startOffset, bool bFixed);
  42. // virtual void keyboardCallback(unsigned char key, int x, int y);
  43. void setMotorTargets(btScalar deltaTime);
  44. void resetCamera()
  45. {
  46. float dist = 11;
  47. float pitch = 52;
  48. float yaw = 35;
  49. float targetPos[3]={0,0.46,0};
  50. m_guiHelper->resetCamera(dist,pitch,yaw,targetPos[0],targetPos[1],targetPos[2]);
  51. }
  52. };
  53. #ifndef M_PI
  54. #define M_PI 3.14159265358979323846
  55. #endif
  56. #ifndef M_PI_2
  57. #define M_PI_2 1.57079632679489661923
  58. #endif
  59. #ifndef M_PI_4
  60. #define M_PI_4 0.785398163397448309616
  61. #endif
  62. #ifndef M_PI_8
  63. #define M_PI_8 0.5 * M_PI_4
  64. #endif
  65. // /LOCAL FUNCTIONS
  66. #define NUM_LEGS 6
  67. #define BODYPART_COUNT 2 * NUM_LEGS + 1
  68. #define JOINT_COUNT BODYPART_COUNT - 1
  69. class TestRig
  70. {
  71. btDynamicsWorld* m_ownerWorld;
  72. btCollisionShape* m_shapes[BODYPART_COUNT];
  73. btRigidBody* m_bodies[BODYPART_COUNT];
  74. btTypedConstraint* m_joints[JOINT_COUNT];
  75. btRigidBody* localCreateRigidBody (btScalar mass, const btTransform& startTransform, btCollisionShape* shape)
  76. {
  77. bool isDynamic = (mass != 0.f);
  78. btVector3 localInertia(0,0,0);
  79. if (isDynamic)
  80. shape->calculateLocalInertia(mass,localInertia);
  81. btDefaultMotionState* myMotionState = new btDefaultMotionState(startTransform);
  82. btRigidBody::btRigidBodyConstructionInfo rbInfo(mass,myMotionState,shape,localInertia);
  83. btRigidBody* body = new btRigidBody(rbInfo);
  84. m_ownerWorld->addRigidBody(body);
  85. return body;
  86. }
  87. public:
  88. TestRig (btDynamicsWorld* ownerWorld, const btVector3& positionOffset, bool bFixed)
  89. : m_ownerWorld (ownerWorld)
  90. {
  91. btVector3 vUp(0, 1, 0);
  92. //
  93. // Setup geometry
  94. //
  95. float fBodySize = 0.25f;
  96. float fLegLength = 0.45f;
  97. float fForeLegLength = 0.75f;
  98. m_shapes[0] = new btCapsuleShape(btScalar(fBodySize), btScalar(0.10));
  99. int i;
  100. for ( i=0; i<NUM_LEGS; i++)
  101. {
  102. m_shapes[1 + 2*i] = new btCapsuleShape(btScalar(0.10), btScalar(fLegLength));
  103. m_shapes[2 + 2*i] = new btCapsuleShape(btScalar(0.08), btScalar(fForeLegLength));
  104. }
  105. //
  106. // Setup rigid bodies
  107. //
  108. float fHeight = 0.5;
  109. btTransform offset; offset.setIdentity();
  110. offset.setOrigin(positionOffset);
  111. // root
  112. btVector3 vRoot = btVector3(btScalar(0.), btScalar(fHeight), btScalar(0.));
  113. btTransform transform;
  114. transform.setIdentity();
  115. transform.setOrigin(vRoot);
  116. if (bFixed)
  117. {
  118. m_bodies[0] = localCreateRigidBody(btScalar(0.), offset*transform, m_shapes[0]);
  119. } else
  120. {
  121. m_bodies[0] = localCreateRigidBody(btScalar(1.), offset*transform, m_shapes[0]);
  122. }
  123. // legs
  124. for ( i=0; i<NUM_LEGS; i++)
  125. {
  126. float fAngle = 2 * M_PI * i / NUM_LEGS;
  127. float fSin = sin(fAngle);
  128. float fCos = cos(fAngle);
  129. transform.setIdentity();
  130. btVector3 vBoneOrigin = btVector3(btScalar(fCos*(fBodySize+0.5*fLegLength)), btScalar(fHeight), btScalar(fSin*(fBodySize+0.5*fLegLength)));
  131. transform.setOrigin(vBoneOrigin);
  132. // thigh
  133. btVector3 vToBone = (vBoneOrigin - vRoot).normalize();
  134. btVector3 vAxis = vToBone.cross(vUp);
  135. transform.setRotation(btQuaternion(vAxis, M_PI_2));
  136. m_bodies[1+2*i] = localCreateRigidBody(btScalar(1.), offset*transform, m_shapes[1+2*i]);
  137. // shin
  138. transform.setIdentity();
  139. transform.setOrigin(btVector3(btScalar(fCos*(fBodySize+fLegLength)), btScalar(fHeight-0.5*fForeLegLength), btScalar(fSin*(fBodySize+fLegLength))));
  140. m_bodies[2+2*i] = localCreateRigidBody(btScalar(1.), offset*transform, m_shapes[2+2*i]);
  141. }
  142. // Setup some damping on the m_bodies
  143. for (i = 0; i < BODYPART_COUNT; ++i)
  144. {
  145. m_bodies[i]->setDamping(0.05, 0.85);
  146. m_bodies[i]->setDeactivationTime(0.8);
  147. //m_bodies[i]->setSleepingThresholds(1.6, 2.5);
  148. m_bodies[i]->setSleepingThresholds(0.5f, 0.5f);
  149. }
  150. //
  151. // Setup the constraints
  152. //
  153. btHingeConstraint* hingeC;
  154. //btConeTwistConstraint* coneC;
  155. btTransform localA, localB, localC;
  156. for ( i=0; i<NUM_LEGS; i++)
  157. {
  158. float fAngle = 2 * M_PI * i / NUM_LEGS;
  159. float fSin = sin(fAngle);
  160. float fCos = cos(fAngle);
  161. // hip joints
  162. localA.setIdentity(); localB.setIdentity();
  163. localA.getBasis().setEulerZYX(0,-fAngle,0); localA.setOrigin(btVector3(btScalar(fCos*fBodySize), btScalar(0.), btScalar(fSin*fBodySize)));
  164. localB = m_bodies[1+2*i]->getWorldTransform().inverse() * m_bodies[0]->getWorldTransform() * localA;
  165. hingeC = new btHingeConstraint(*m_bodies[0], *m_bodies[1+2*i], localA, localB);
  166. hingeC->setLimit(btScalar(-0.75 * M_PI_4), btScalar(M_PI_8));
  167. //hingeC->setLimit(btScalar(-0.1), btScalar(0.1));
  168. m_joints[2*i] = hingeC;
  169. m_ownerWorld->addConstraint(m_joints[2*i], true);
  170. // knee joints
  171. localA.setIdentity(); localB.setIdentity(); localC.setIdentity();
  172. localA.getBasis().setEulerZYX(0,-fAngle,0); localA.setOrigin(btVector3(btScalar(fCos*(fBodySize+fLegLength)), btScalar(0.), btScalar(fSin*(fBodySize+fLegLength))));
  173. localB = m_bodies[1+2*i]->getWorldTransform().inverse() * m_bodies[0]->getWorldTransform() * localA;
  174. localC = m_bodies[2+2*i]->getWorldTransform().inverse() * m_bodies[0]->getWorldTransform() * localA;
  175. hingeC = new btHingeConstraint(*m_bodies[1+2*i], *m_bodies[2+2*i], localB, localC);
  176. //hingeC->setLimit(btScalar(-0.01), btScalar(0.01));
  177. hingeC->setLimit(btScalar(-M_PI_8), btScalar(0.2));
  178. m_joints[1+2*i] = hingeC;
  179. m_ownerWorld->addConstraint(m_joints[1+2*i], true);
  180. }
  181. }
  182. virtual ~TestRig ()
  183. {
  184. int i;
  185. // Remove all constraints
  186. for ( i = 0; i < JOINT_COUNT; ++i)
  187. {
  188. m_ownerWorld->removeConstraint(m_joints[i]);
  189. delete m_joints[i]; m_joints[i] = 0;
  190. }
  191. // Remove all bodies and shapes
  192. for ( i = 0; i < BODYPART_COUNT; ++i)
  193. {
  194. m_ownerWorld->removeRigidBody(m_bodies[i]);
  195. delete m_bodies[i]->getMotionState();
  196. delete m_bodies[i]; m_bodies[i] = 0;
  197. delete m_shapes[i]; m_shapes[i] = 0;
  198. }
  199. }
  200. btTypedConstraint** GetJoints() {return &m_joints[0];}
  201. };
  202. void motorPreTickCallback (btDynamicsWorld *world, btScalar timeStep)
  203. {
  204. MotorDemo* motorDemo = (MotorDemo*)world->getWorldUserInfo();
  205. motorDemo->setMotorTargets(timeStep);
  206. }
  207. void MotorDemo::initPhysics()
  208. {
  209. m_guiHelper->setUpAxis(1);
  210. // Setup the basic world
  211. m_Time = 0;
  212. m_fCyclePeriod = 2000.f; // in milliseconds
  213. // m_fMuscleStrength = 0.05f;
  214. // new SIMD solver for joints clips accumulated impulse, so the new limits for the motor
  215. // should be (numberOfsolverIterations * oldLimits)
  216. // currently solver uses 10 iterations, so:
  217. m_fMuscleStrength = 0.5f;
  218. m_collisionConfiguration = new btDefaultCollisionConfiguration();
  219. m_dispatcher = new btCollisionDispatcher(m_collisionConfiguration);
  220. btVector3 worldAabbMin(-10000,-10000,-10000);
  221. btVector3 worldAabbMax(10000,10000,10000);
  222. m_broadphase = new btAxisSweep3 (worldAabbMin, worldAabbMax);
  223. m_solver = new btSequentialImpulseConstraintSolver;
  224. m_dynamicsWorld = new btDiscreteDynamicsWorld(m_dispatcher,m_broadphase,m_solver,m_collisionConfiguration);
  225. m_dynamicsWorld->setInternalTickCallback(motorPreTickCallback,this,true);
  226. m_guiHelper->createPhysicsDebugDrawer(m_dynamicsWorld);
  227. // Setup a big ground box
  228. {
  229. btCollisionShape* groundShape = new btBoxShape(btVector3(btScalar(200.),btScalar(10.),btScalar(200.)));
  230. m_collisionShapes.push_back(groundShape);
  231. btTransform groundTransform;
  232. groundTransform.setIdentity();
  233. groundTransform.setOrigin(btVector3(0,-10,0));
  234. createRigidBody(btScalar(0.),groundTransform,groundShape);
  235. }
  236. // Spawn one ragdoll
  237. btVector3 startOffset(1,0.5,0);
  238. spawnTestRig(startOffset, false);
  239. startOffset.setValue(-2,0.5,0);
  240. spawnTestRig(startOffset, true);
  241. m_guiHelper->autogenerateGraphicsObjects(m_dynamicsWorld);
  242. }
  243. void MotorDemo::spawnTestRig(const btVector3& startOffset, bool bFixed)
  244. {
  245. TestRig* rig = new TestRig(m_dynamicsWorld, startOffset, bFixed);
  246. m_rigs.push_back(rig);
  247. }
  248. void PreStep()
  249. {
  250. }
  251. void MotorDemo::setMotorTargets(btScalar deltaTime)
  252. {
  253. float ms = deltaTime*1000000.;
  254. float minFPS = 1000000.f/60.f;
  255. if (ms > minFPS)
  256. ms = minFPS;
  257. m_Time += ms;
  258. //
  259. // set per-frame sinusoidal position targets using angular motor (hacky?)
  260. //
  261. for (int r=0; r<m_rigs.size(); r++)
  262. {
  263. for (int i=0; i<2*NUM_LEGS; i++)
  264. {
  265. btHingeConstraint* hingeC = static_cast<btHingeConstraint*>(m_rigs[r]->GetJoints()[i]);
  266. btScalar fCurAngle = hingeC->getHingeAngle();
  267. btScalar fTargetPercent = (int(m_Time / 1000) % int(m_fCyclePeriod)) / m_fCyclePeriod;
  268. btScalar fTargetAngle = 0.5 * (1 + sin(2 * M_PI * fTargetPercent));
  269. btScalar fTargetLimitAngle = hingeC->getLowerLimit() + fTargetAngle * (hingeC->getUpperLimit() - hingeC->getLowerLimit());
  270. btScalar fAngleError = fTargetLimitAngle - fCurAngle;
  271. btScalar fDesiredAngularVel = 1000000.f * fAngleError/ms;
  272. hingeC->enableAngularMotor(true, fDesiredAngularVel, m_fMuscleStrength);
  273. }
  274. }
  275. }
  276. #if 0
  277. void MotorDemo::keyboardCallback(unsigned char key, int x, int y)
  278. {
  279. switch (key)
  280. {
  281. case '+': case '=':
  282. m_fCyclePeriod /= 1.1f;
  283. if (m_fCyclePeriod < 1.f)
  284. m_fCyclePeriod = 1.f;
  285. break;
  286. case '-': case '_':
  287. m_fCyclePeriod *= 1.1f;
  288. break;
  289. case '[':
  290. m_fMuscleStrength /= 1.1f;
  291. break;
  292. case ']':
  293. m_fMuscleStrength *= 1.1f;
  294. break;
  295. default:
  296. DemoApplication::keyboardCallback(key, x, y);
  297. }
  298. }
  299. #endif
  300. void MotorDemo::exitPhysics()
  301. {
  302. int i;
  303. for (i=0;i<m_rigs.size();i++)
  304. {
  305. TestRig* rig = m_rigs[i];
  306. delete rig;
  307. }
  308. //cleanup in the reverse order of creation/initialization
  309. //remove the rigidbodies from the dynamics world and delete them
  310. for (i=m_dynamicsWorld->getNumCollisionObjects()-1; i>=0 ;i--)
  311. {
  312. btCollisionObject* obj = m_dynamicsWorld->getCollisionObjectArray()[i];
  313. btRigidBody* body = btRigidBody::upcast(obj);
  314. if (body && body->getMotionState())
  315. {
  316. delete body->getMotionState();
  317. }
  318. m_dynamicsWorld->removeCollisionObject( obj );
  319. delete obj;
  320. }
  321. //delete collision shapes
  322. for (int j=0;j<m_collisionShapes.size();j++)
  323. {
  324. btCollisionShape* shape = m_collisionShapes[j];
  325. delete shape;
  326. }
  327. //delete dynamics world
  328. delete m_dynamicsWorld;
  329. //delete solver
  330. delete m_solver;
  331. //delete broadphase
  332. delete m_broadphase;
  333. //delete dispatcher
  334. delete m_dispatcher;
  335. delete m_collisionConfiguration;
  336. }
  337. class CommonExampleInterface* MotorControlCreateFunc(struct CommonExampleOptions& options)
  338. {
  339. return new MotorDemo(options.m_guiHelper);
  340. }