Tutorial.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800
  1. #include "Tutorial.h"
  2. #include "../CommonInterfaces/CommonGraphicsAppInterface.h"
  3. #include "../CommonInterfaces/CommonRenderInterface.h"
  4. #include "../CommonInterfaces/CommonExampleInterface.h"
  5. #include "LinearMath/btTransform.h"
  6. #include "../CommonInterfaces/CommonGUIHelperInterface.h"
  7. #include "../RenderingExamples/TimeSeriesCanvas.h"
  8. #include "stb_image/stb_image.h"
  9. #include "Bullet3Common/b3Quaternion.h"
  10. #include "Bullet3Common/b3Matrix3x3.h"
  11. #include "../CommonInterfaces/CommonParameterInterface.h"
  12. #include "LinearMath/btAlignedObjectArray.h"
  13. #define stdvector btAlignedObjectArray
  14. #define SPHERE_RADIUS 1
  15. static btScalar gRestitution = 0.f;
  16. static btScalar gMassA = 1.f;
  17. static btScalar gMassB = 0.f;
  18. enum LWEnumCollisionTypes
  19. {
  20. LW_PLANE_TYPE,
  21. LW_SPHERE_TYPE,
  22. LW_BOX_TYPE
  23. };
  24. struct LWPlane
  25. {
  26. BT_DECLARE_ALIGNED_ALLOCATOR();
  27. b3Vector3 m_normal;
  28. btScalar m_planeConstant;
  29. };
  30. struct LWSphere
  31. {
  32. btScalar m_radius;
  33. void computeLocalInertia(b3Scalar mass, b3Vector3& localInertia)
  34. {
  35. btScalar elem = b3Scalar(0.4) * mass * m_radius*m_radius;
  36. localInertia.setValue(elem,elem,elem);
  37. }
  38. };
  39. struct LWBox
  40. {
  41. BT_DECLARE_ALIGNED_ALLOCATOR();
  42. b3Vector3 m_halfExtents;
  43. };
  44. struct LWCollisionShape
  45. {
  46. LWEnumCollisionTypes m_type;
  47. union
  48. {
  49. LWPlane m_plane;
  50. LWSphere m_sphere;
  51. LWBox m_box;
  52. };
  53. };
  54. struct LWPose
  55. {
  56. BT_DECLARE_ALIGNED_ALLOCATOR();
  57. b3Vector3 m_position;
  58. b3Quaternion m_orientation;
  59. LWPose()
  60. :m_position(b3MakeVector3(0,0,0)),
  61. m_orientation(0,0,0,1)
  62. {
  63. }
  64. b3Vector3 transformPoint(const b3Vector3& pointIn)
  65. {
  66. b3Vector3 rotPoint = b3QuatRotate(m_orientation,pointIn);
  67. return rotPoint+m_position;
  68. }
  69. };
  70. struct LWContactPoint
  71. {
  72. b3Vector3 m_ptOnAWorld;
  73. b3Vector3 m_ptOnBWorld;
  74. b3Vector3 m_normalOnB;
  75. btScalar m_distance;
  76. };
  77. ///returns true if we found a pair of closest points
  78. void ComputeClosestPointsPlaneSphere(const LWPlane& planeWorld, const LWSphere& sphere, const LWPose& spherePose, LWContactPoint& pointOut) {
  79. b3Vector3 spherePosWorld = spherePose.m_position;
  80. btScalar t = -(spherePosWorld.dot(-planeWorld.m_normal)+planeWorld.m_planeConstant);
  81. b3Vector3 intersectionPoint = spherePosWorld+t*-planeWorld.m_normal;
  82. b3Scalar distance = t-sphere.m_radius;
  83. pointOut.m_distance = distance;
  84. pointOut.m_ptOnBWorld = intersectionPoint;
  85. pointOut.m_ptOnAWorld = spherePosWorld+sphere.m_radius*-planeWorld.m_normal;
  86. pointOut.m_normalOnB = planeWorld.m_normal;
  87. }
  88. void ComputeClosestPointsSphereSphere(const LWSphere& sphereA, const LWPose& sphereAPose, const LWSphere& sphereB, const LWPose& sphereBPose, LWContactPoint& pointOut) {
  89. b3Vector3 diff = sphereAPose.m_position-sphereBPose.m_position;
  90. btScalar len = diff.length();
  91. pointOut.m_distance = len - (sphereA.m_radius+sphereB.m_radius);
  92. pointOut.m_normalOnB = b3MakeVector3(1,0,0);
  93. if (len > B3_EPSILON) {
  94. pointOut.m_normalOnB = diff / len;
  95. }
  96. pointOut.m_ptOnAWorld = sphereAPose.m_position - sphereA.m_radius*pointOut.m_normalOnB;
  97. pointOut.m_ptOnBWorld = pointOut.m_ptOnAWorld-pointOut.m_normalOnB*pointOut.m_distance;
  98. }
  99. enum LWRIGIDBODY_FLAGS
  100. {
  101. LWFLAG_USE_QUATERNION_DERIVATIVE = 1,
  102. };
  103. struct LWRigidBody
  104. {
  105. BT_DECLARE_ALIGNED_ALLOCATOR();
  106. LWPose m_worldPose;
  107. b3Vector3 m_linearVelocity;
  108. b3Vector3 m_angularVelocity;
  109. b3Vector3 m_gravityAcceleration;
  110. b3Vector3 m_localInertia;
  111. b3Scalar m_invMass;
  112. b3Matrix3x3 m_invInertiaTensorWorld;
  113. void computeInvInertiaTensorWorld()
  114. {
  115. b3Vector3 invInertiaLocal;
  116. invInertiaLocal.setValue(m_localInertia.x != btScalar(0.0) ? btScalar(1.0) / m_localInertia.x: btScalar(0.0),
  117. m_localInertia.y != btScalar(0.0) ? btScalar(1.0) / m_localInertia.y: btScalar(0.0),
  118. m_localInertia.z != btScalar(0.0) ? btScalar(1.0) / m_localInertia.z: btScalar(0.0));
  119. b3Matrix3x3 m (m_worldPose.m_orientation);
  120. m_invInertiaTensorWorld = m.scaled(invInertiaLocal) * m.transpose();
  121. }
  122. int m_graphicsIndex;
  123. LWCollisionShape m_collisionShape;
  124. LWRIGIDBODY_FLAGS m_flags;
  125. LWRigidBody()
  126. :m_linearVelocity(b3MakeVector3(0,0,0)),
  127. m_angularVelocity(b3MakeVector3(0,0,0)),
  128. m_gravityAcceleration(b3MakeVector3(0,0,0)),//-10,0)),
  129. m_flags(LWFLAG_USE_QUATERNION_DERIVATIVE)
  130. {
  131. }
  132. const b3Vector3& getPosition() const
  133. {
  134. return m_worldPose.m_position;
  135. }
  136. b3Vector3 getVelocity(const b3Vector3& relPos) const
  137. {
  138. return m_linearVelocity + m_angularVelocity.cross(relPos);
  139. }
  140. void integrateAcceleration(double deltaTime) {
  141. m_linearVelocity += m_gravityAcceleration*deltaTime;
  142. }
  143. void applyImpulse(const b3Vector3& impulse, const b3Vector3& rel_pos)
  144. {
  145. m_linearVelocity += impulse * m_invMass;
  146. b3Vector3 torqueImpulse = rel_pos.cross(impulse);
  147. m_angularVelocity += m_invInertiaTensorWorld * torqueImpulse;
  148. }
  149. void integrateVelocity(double deltaTime)
  150. {
  151. LWPose newPose;
  152. newPose.m_position = m_worldPose.m_position + m_linearVelocity*deltaTime;
  153. if (m_flags & LWFLAG_USE_QUATERNION_DERIVATIVE)
  154. {
  155. newPose.m_orientation = m_worldPose.m_orientation;
  156. newPose.m_orientation += (m_angularVelocity * newPose.m_orientation) * (deltaTime * btScalar(0.5));
  157. newPose.m_orientation.normalize();
  158. m_worldPose = newPose;
  159. } else
  160. {
  161. //Exponential map
  162. //google for "Practical Parameterization of Rotations Using the Exponential Map", F. Sebastian Grassia
  163. //btQuaternion q_w = [ sin(|w|*dt/2) * w/|w| , cos(|w|*dt/2)]
  164. //btQuaternion q_new = q_w * q_old;
  165. b3Vector3 axis;
  166. b3Scalar fAngle = m_angularVelocity.length();
  167. //limit the angular motion
  168. const btScalar angularMotionThreshold = btScalar(0.5)*SIMD_HALF_PI;
  169. if (fAngle*deltaTime > angularMotionThreshold)
  170. {
  171. fAngle = angularMotionThreshold / deltaTime;
  172. }
  173. if ( fAngle < btScalar(0.001) )
  174. {
  175. // use Taylor's expansions of sync function
  176. axis = m_angularVelocity*( btScalar(0.5)*deltaTime-(deltaTime*deltaTime*deltaTime)*(btScalar(0.020833333333))*fAngle*fAngle );
  177. }
  178. else
  179. {
  180. // sync(fAngle) = sin(c*fAngle)/t
  181. axis = m_angularVelocity*( btSin(btScalar(0.5)*fAngle*deltaTime)/fAngle );
  182. }
  183. b3Quaternion dorn (axis.x,axis.y,axis.z,btCos( fAngle*deltaTime*b3Scalar(0.5) ));
  184. b3Quaternion orn0 = m_worldPose.m_orientation;
  185. b3Quaternion predictedOrn = dorn * orn0;
  186. predictedOrn.normalize();
  187. m_worldPose.m_orientation = predictedOrn;
  188. }
  189. }
  190. void stepSimulation(double deltaTime)
  191. {
  192. integrateVelocity(deltaTime);
  193. }
  194. };
  195. b3Scalar resolveCollision(LWRigidBody& bodyA,
  196. LWRigidBody& bodyB,
  197. LWContactPoint& contactPoint)
  198. {
  199. b3Assert(contactPoint.m_distance<=0);
  200. btScalar appliedImpulse = 0.f;
  201. b3Vector3 rel_pos1 = contactPoint.m_ptOnAWorld - bodyA.m_worldPose.m_position;
  202. b3Vector3 rel_pos2 = contactPoint.m_ptOnBWorld - bodyB.getPosition();
  203. btScalar rel_vel = contactPoint.m_normalOnB.dot(bodyA.getVelocity(rel_pos1) - bodyB.getVelocity(rel_pos2));
  204. if (rel_vel < -B3_EPSILON)
  205. {
  206. b3Vector3 temp1 = bodyA.m_invInertiaTensorWorld * rel_pos1.cross(contactPoint.m_normalOnB);
  207. b3Vector3 temp2 = bodyB.m_invInertiaTensorWorld * rel_pos2.cross(contactPoint.m_normalOnB);
  208. btScalar impulse = -(1.0f + gRestitution) * rel_vel /
  209. (bodyA.m_invMass + bodyB.m_invMass + contactPoint.m_normalOnB.dot(temp1.cross(rel_pos1) + temp2.cross(rel_pos2)));
  210. b3Vector3 impulse_vector = contactPoint.m_normalOnB * impulse;
  211. b3Printf("impulse = %f\n", impulse);
  212. appliedImpulse = impulse;
  213. bodyA.applyImpulse(impulse_vector, rel_pos1);
  214. bodyB.applyImpulse(-impulse_vector, rel_pos2);
  215. }
  216. return appliedImpulse;
  217. }
  218. class Tutorial : public CommonExampleInterface
  219. {
  220. CommonGraphicsApp* m_app;
  221. GUIHelperInterface* m_guiHelper;
  222. int m_tutorialIndex;
  223. stdvector<LWRigidBody*> m_bodies;
  224. TimeSeriesCanvas* m_timeSeriesCanvas0;
  225. TimeSeriesCanvas* m_timeSeriesCanvas1;
  226. stdvector<LWContactPoint> m_contactPoints;
  227. int m_stage;
  228. int m_counter;
  229. public:
  230. Tutorial(GUIHelperInterface* guiHelper, int tutorialIndex)
  231. :m_app(guiHelper->getAppInterface()),
  232. m_guiHelper(guiHelper),
  233. m_tutorialIndex(tutorialIndex),
  234. m_stage(0),
  235. m_counter(0),
  236. m_timeSeriesCanvas0(0),
  237. m_timeSeriesCanvas1(0)
  238. {
  239. int numBodies = 1;
  240. m_app->setUpAxis(1);
  241. m_app->m_renderer->enableBlend(true);
  242. switch (m_tutorialIndex)
  243. {
  244. case TUT_VELOCITY:
  245. {
  246. numBodies=10;
  247. m_timeSeriesCanvas0 = new TimeSeriesCanvas(m_app->m_2dCanvasInterface,512,256,"Constant Velocity");
  248. m_timeSeriesCanvas0 ->setupTimeSeries(2,60, 0);
  249. m_timeSeriesCanvas0->addDataSource("X position (m)", 255,0,0);
  250. m_timeSeriesCanvas0->addDataSource("X velocity (m/s)", 0,0,255);
  251. m_timeSeriesCanvas0->addDataSource("dX/dt (m/s)", 0,0,0);
  252. break;
  253. }
  254. case TUT_ACCELERATION:
  255. {
  256. numBodies=10;
  257. m_timeSeriesCanvas1 = new TimeSeriesCanvas(m_app->m_2dCanvasInterface,256,512,"Constant Acceleration");
  258. m_timeSeriesCanvas1 ->setupTimeSeries(50,60, 0);
  259. m_timeSeriesCanvas1->addDataSource("Y position (m)", 255,0,0);
  260. m_timeSeriesCanvas1->addDataSource("Y velocity (m/s)", 0,0,255);
  261. m_timeSeriesCanvas1->addDataSource("dY/dt (m/s)", 0,0,0);
  262. break;
  263. }
  264. case TUT_COLLISION:
  265. {
  266. numBodies=2;
  267. m_timeSeriesCanvas1 = new TimeSeriesCanvas(m_app->m_2dCanvasInterface,512,200,"Distance");
  268. m_timeSeriesCanvas1 ->setupTimeSeries(1.5,60, 0);
  269. m_timeSeriesCanvas1->addDataSource("distance", 255,0,0);
  270. break;
  271. }
  272. case TUT_SOLVE_CONTACT_CONSTRAINT:
  273. {
  274. numBodies=2;
  275. m_timeSeriesCanvas1 = new TimeSeriesCanvas(m_app->m_2dCanvasInterface,512,200,"Collision Impulse");
  276. m_timeSeriesCanvas1 ->setupTimeSeries(1.5,60, 0);
  277. m_timeSeriesCanvas1->addDataSource("Distance", 0,0,255);
  278. m_timeSeriesCanvas1->addDataSource("Impulse magnutide", 255,0,0);
  279. {
  280. SliderParams slider("Restitution",&gRestitution);
  281. slider.m_minVal=0;
  282. slider.m_maxVal=1;
  283. m_guiHelper->getParameterInterface()->registerSliderFloatParameter(slider);
  284. }
  285. {
  286. SliderParams slider("Mass A",&gMassA);
  287. slider.m_minVal=0;
  288. slider.m_maxVal=100;
  289. m_guiHelper->getParameterInterface()->registerSliderFloatParameter(slider);
  290. }
  291. {
  292. SliderParams slider("Mass B",&gMassB);
  293. slider.m_minVal=0;
  294. slider.m_maxVal=100;
  295. m_guiHelper->getParameterInterface()->registerSliderFloatParameter(slider);
  296. }
  297. break;
  298. }
  299. default:
  300. {
  301. m_timeSeriesCanvas0 = new TimeSeriesCanvas(m_app->m_2dCanvasInterface,512,256,"Unknown");
  302. m_timeSeriesCanvas0 ->setupTimeSeries(1,60, 0);
  303. }
  304. };
  305. if (m_tutorialIndex==TUT_VELOCITY)
  306. {
  307. int boxId = m_app->registerCubeShape(100,1,100);
  308. b3Vector3 pos = b3MakeVector3(0,-3.5,0);
  309. b3Quaternion orn(0,0,0,1);
  310. b3Vector4 color = b3MakeVector4(1,1,1,1);
  311. b3Vector3 scaling = b3MakeVector3(1,1,1);
  312. m_app->m_renderer->registerGraphicsInstance(boxId,pos,orn,color,scaling);
  313. }
  314. for (int i=0;i<numBodies;i++)
  315. {
  316. m_bodies.push_back(new LWRigidBody());
  317. }
  318. for (int i=0;i<m_bodies.size();i++)
  319. {
  320. m_bodies[i]->m_worldPose.m_position.setValue((i/4)*5,3,(i&3)*5);
  321. }
  322. {
  323. int textureIndex = -1;
  324. if (1)
  325. {
  326. int width,height,n;
  327. const char* filename = "data/cube.png";
  328. const unsigned char* image=0;
  329. const char* prefix[]={"./","../","../../","../../../","../../../../"};
  330. int numprefix = sizeof(prefix)/sizeof(const char*);
  331. for (int i=0;!image && i<numprefix;i++)
  332. {
  333. char relativeFileName[1024];
  334. sprintf(relativeFileName,"%s%s",prefix[i],filename);
  335. image = stbi_load(relativeFileName, &width, &height, &n, 3);
  336. }
  337. b3Assert(image);
  338. if (image)
  339. {
  340. textureIndex = m_app->m_renderer->registerTexture(image,width,height);
  341. }
  342. }
  343. // int boxId = m_app->registerCubeShape(1,1,1,textureIndex);
  344. int boxId = m_app->registerGraphicsUnitSphereShape(SPHERE_LOD_HIGH, textureIndex);
  345. b3Vector4 color = b3MakeVector4(1,1,1,0.8);
  346. b3Vector3 scaling = b3MakeVector3(SPHERE_RADIUS,SPHERE_RADIUS,SPHERE_RADIUS);
  347. for (int i=0;i<m_bodies.size();i++)
  348. {
  349. m_bodies[i]->m_collisionShape.m_sphere.m_radius = SPHERE_RADIUS;
  350. m_bodies[i]->m_collisionShape.m_type = LW_SPHERE_TYPE;
  351. m_bodies[i]->m_graphicsIndex = m_app->m_renderer->registerGraphicsInstance(boxId,m_bodies[i]->m_worldPose.m_position, m_bodies[i]->m_worldPose.m_orientation,color,scaling);
  352. m_app->m_renderer->writeSingleInstanceTransformToCPU(m_bodies[i]->m_worldPose.m_position, m_bodies[i]->m_worldPose.m_orientation, m_bodies[i]->m_graphicsIndex);
  353. }
  354. }
  355. if (m_tutorialIndex == TUT_SOLVE_CONTACT_CONSTRAINT)
  356. {
  357. m_bodies[0]->m_invMass = gMassA? 1./gMassA : 0;
  358. m_bodies[0]->m_collisionShape.m_sphere.computeLocalInertia(gMassA,m_bodies[0]->m_localInertia);
  359. m_bodies[1]->m_invMass =gMassB? 1./gMassB : 0;
  360. m_bodies[1]->m_collisionShape.m_sphere.computeLocalInertia(gMassB,m_bodies[1]->m_localInertia);
  361. if (gMassA)
  362. m_bodies[0]->m_linearVelocity.setValue(0,0,1);
  363. if (gMassB)
  364. m_bodies[1]->m_linearVelocity.setValue(0,0,-1);
  365. }
  366. m_app->m_renderer->writeTransforms();
  367. }
  368. virtual ~Tutorial()
  369. {
  370. delete m_timeSeriesCanvas0;
  371. delete m_timeSeriesCanvas1;
  372. m_timeSeriesCanvas0 = 0;
  373. m_timeSeriesCanvas1 = 0;
  374. m_app->m_renderer->enableBlend(false);
  375. }
  376. virtual void initPhysics()
  377. {
  378. }
  379. virtual void exitPhysics()
  380. {
  381. }
  382. void tutorial1Update(float deltaTime);
  383. void tutorial2Update(float deltaTime);
  384. void tutorialCollisionUpdate(float deltaTime,LWContactPoint& contact);
  385. void tutorialSolveContactConstraintUpdate(float deltaTime,LWContactPoint& contact);
  386. virtual void stepSimulation(float deltaTime)
  387. {
  388. switch (m_tutorialIndex)
  389. {
  390. case TUT_VELOCITY:
  391. {
  392. tutorial1Update(deltaTime);
  393. float xPos = m_bodies[0]->m_worldPose.m_position.x;
  394. float xVel = m_bodies[0]->m_linearVelocity.x;
  395. m_timeSeriesCanvas0->insertDataAtCurrentTime(xPos,0,true);
  396. m_timeSeriesCanvas0->insertDataAtCurrentTime(xVel,1,true);
  397. break;
  398. }
  399. case TUT_ACCELERATION:
  400. {
  401. tutorial2Update(deltaTime);
  402. float yPos = m_bodies[0]->m_worldPose.m_position.y;
  403. float yVel = m_bodies[0]->m_linearVelocity.y;
  404. m_timeSeriesCanvas1->insertDataAtCurrentTime(yPos,0,true);
  405. m_timeSeriesCanvas1->insertDataAtCurrentTime(yVel,1,true);
  406. break;
  407. }
  408. case TUT_COLLISION:
  409. {
  410. m_contactPoints.clear();
  411. LWContactPoint contactPoint;
  412. tutorialCollisionUpdate(deltaTime, contactPoint);
  413. m_contactPoints.push_back(contactPoint);
  414. m_timeSeriesCanvas1->insertDataAtCurrentTime(contactPoint.m_distance,0,true);
  415. break;
  416. }
  417. case TUT_SOLVE_CONTACT_CONSTRAINT:
  418. {
  419. m_contactPoints.clear();
  420. LWContactPoint contactPoint;
  421. tutorialSolveContactConstraintUpdate(deltaTime, contactPoint);
  422. m_contactPoints.push_back(contactPoint);
  423. if (contactPoint.m_distance<0)
  424. {
  425. m_bodies[0]->computeInvInertiaTensorWorld();
  426. m_bodies[1]->computeInvInertiaTensorWorld();
  427. b3Scalar appliedImpulse = resolveCollision(*m_bodies[0],
  428. *m_bodies[1],
  429. contactPoint
  430. );
  431. m_timeSeriesCanvas1->insertDataAtCurrentTime(appliedImpulse,1,true);
  432. } else
  433. {
  434. m_timeSeriesCanvas1->insertDataAtCurrentTime(0.,1,true);
  435. }
  436. m_timeSeriesCanvas1->insertDataAtCurrentTime(contactPoint.m_distance,0,true);
  437. break;
  438. }
  439. default:
  440. {
  441. }
  442. };
  443. if (m_timeSeriesCanvas0)
  444. m_timeSeriesCanvas0->nextTick();
  445. if (m_timeSeriesCanvas1)
  446. m_timeSeriesCanvas1->nextTick();
  447. for (int i=0;i<m_bodies.size();i++)
  448. {
  449. m_bodies[i]->integrateAcceleration(deltaTime);
  450. m_bodies[i]->integrateVelocity(deltaTime);
  451. m_app->m_renderer->writeSingleInstanceTransformToCPU(m_bodies[i]->m_worldPose.m_position, m_bodies[i]->m_worldPose.m_orientation, m_bodies[i]->m_graphicsIndex);
  452. }
  453. m_app->m_renderer->writeTransforms();
  454. }
  455. virtual void renderScene()
  456. {
  457. m_app->m_renderer->renderScene();
  458. m_app->drawText3D("X",1,0,0,1);
  459. m_app->drawText3D("Y",0,1,0,1);
  460. m_app->drawText3D("Z",0,0,1,1);
  461. for (int i=0;i<m_contactPoints.size();i++)
  462. {
  463. const LWContactPoint& contact = m_contactPoints[i];
  464. b3Vector3 color=b3MakeVector3(1,1,0);
  465. float lineWidth=3;
  466. if (contact.m_distance<0)
  467. {
  468. color.setValue(1,0,0);
  469. }
  470. m_app->m_renderer->drawLine(contact.m_ptOnAWorld,contact.m_ptOnBWorld,color,lineWidth);
  471. }
  472. }
  473. virtual void physicsDebugDraw(int debugDrawFlags)
  474. {
  475. }
  476. virtual bool mouseMoveCallback(float x,float y)
  477. {
  478. return false;
  479. }
  480. virtual bool mouseButtonCallback(int button, int state, float x, float y)
  481. {
  482. return false;
  483. }
  484. virtual bool keyboardCallback(int key, int state)
  485. {
  486. return false;
  487. }
  488. virtual void resetCamera()
  489. {
  490. float dist = 10.5;
  491. float pitch = 136;
  492. float yaw = 32;
  493. float targetPos[3]={0,0,0};
  494. if (m_app->m_renderer && m_app->m_renderer->getActiveCamera())
  495. {
  496. m_app->m_renderer->getActiveCamera()->setCameraDistance(dist);
  497. m_app->m_renderer->getActiveCamera()->setCameraPitch(pitch);
  498. m_app->m_renderer->getActiveCamera()->setCameraYaw(yaw);
  499. m_app->m_renderer->getActiveCamera()->setCameraTargetPosition(targetPos[0],targetPos[1],targetPos[2]);
  500. }
  501. }
  502. };
  503. void Tutorial::tutorial2Update(float deltaTime)
  504. {
  505. for (int i=0;i<m_bodies.size();i++)
  506. {
  507. m_bodies[i]->m_gravityAcceleration.setValue(0,-10,0);
  508. }
  509. }
  510. void Tutorial::tutorial1Update(float deltaTime)
  511. {
  512. for (int i=0;i<m_bodies.size();i++)
  513. {
  514. switch (m_stage)
  515. {
  516. case 0:
  517. {
  518. m_bodies[i]->m_angularVelocity=b3MakeVector3(0,0,0);
  519. m_bodies[i]->m_linearVelocity=b3MakeVector3(1,0,0);
  520. break;
  521. }
  522. case 1:
  523. {
  524. m_bodies[i]->m_linearVelocity=b3MakeVector3(-1,0,0);
  525. break;
  526. }
  527. case 2:
  528. {
  529. m_bodies[i]->m_linearVelocity=b3MakeVector3(0,1,0);
  530. break;
  531. }
  532. case 3:
  533. {
  534. m_bodies[i]->m_linearVelocity=b3MakeVector3(0,-1,0);
  535. break;
  536. }
  537. case 4:
  538. {
  539. m_bodies[i]->m_linearVelocity=b3MakeVector3(0,0,1);
  540. break;
  541. }
  542. case 5:
  543. {
  544. m_bodies[i]->m_linearVelocity=b3MakeVector3(0,0,-1);
  545. break;
  546. }
  547. case 6:
  548. {
  549. m_bodies[i]->m_linearVelocity=b3MakeVector3(0,0,0);
  550. m_bodies[i]->m_angularVelocity=b3MakeVector3(1,0,0);
  551. break;
  552. }
  553. case 7:
  554. {
  555. m_bodies[i]->m_angularVelocity=b3MakeVector3(-1,0,0);
  556. break;
  557. }
  558. case 8:
  559. {
  560. m_bodies[i]->m_angularVelocity=b3MakeVector3(0,1,0);
  561. break;
  562. }
  563. case 9:
  564. {
  565. m_bodies[i]->m_angularVelocity=b3MakeVector3(0,-1,0);
  566. break;
  567. }
  568. case 10:
  569. {
  570. m_bodies[i]->m_angularVelocity=b3MakeVector3(0,0,1);
  571. break;
  572. }
  573. case 11:
  574. {
  575. m_bodies[i]->m_angularVelocity=b3MakeVector3(0,0,-1);
  576. break;
  577. }
  578. default:
  579. {
  580. m_bodies[i]->m_angularVelocity=b3MakeVector3(0,0,0);
  581. }
  582. };
  583. }
  584. m_counter++;
  585. if (m_counter>60)
  586. {
  587. m_counter=0;
  588. m_stage++;
  589. if (m_stage>11)
  590. m_stage=0;
  591. b3Printf("Stage = %d\n",m_stage);
  592. b3Printf("linVel = %f,%f,%f\n",m_bodies[0]->m_linearVelocity.x,m_bodies[0]->m_linearVelocity.y,m_bodies[0]->m_linearVelocity.z);
  593. b3Printf("angVel = %f,%f,%f\n",m_bodies[0]->m_angularVelocity.x,m_bodies[0]->m_angularVelocity.y,m_bodies[0]->m_angularVelocity.z);
  594. }
  595. }
  596. void Tutorial::tutorialSolveContactConstraintUpdate(float deltaTime,LWContactPoint& contact)
  597. {
  598. ComputeClosestPointsSphereSphere(m_bodies[0]->m_collisionShape.m_sphere,
  599. m_bodies[0]->m_worldPose,
  600. m_bodies[1]->m_collisionShape.m_sphere,
  601. m_bodies[1]->m_worldPose,
  602. contact);
  603. }
  604. void Tutorial::tutorialCollisionUpdate(float deltaTime,LWContactPoint& contact)
  605. {
  606. m_bodies[1]->m_worldPose.m_position.z = 3;
  607. ComputeClosestPointsSphereSphere(m_bodies[0]->m_collisionShape.m_sphere,
  608. m_bodies[0]->m_worldPose,
  609. m_bodies[1]->m_collisionShape.m_sphere,
  610. m_bodies[1]->m_worldPose,
  611. contact);
  612. switch (m_stage)
  613. {
  614. case 0:
  615. {
  616. m_bodies[0]->m_angularVelocity=b3MakeVector3(0,0,0);
  617. m_bodies[0]->m_linearVelocity=b3MakeVector3(1,0,0);
  618. break;
  619. }
  620. case 1:
  621. {
  622. m_bodies[0]->m_linearVelocity=b3MakeVector3(-1,0,0);
  623. break;
  624. }
  625. case 2:
  626. {
  627. m_bodies[0]->m_linearVelocity=b3MakeVector3(0,1,0);
  628. break;
  629. }
  630. case 3:
  631. {
  632. m_bodies[0]->m_linearVelocity=b3MakeVector3(0,-1,0);
  633. break;
  634. }
  635. case 4:
  636. {
  637. m_bodies[0]->m_linearVelocity=b3MakeVector3(0,0,1);
  638. break;
  639. }
  640. case 5:
  641. {
  642. m_bodies[0]->m_linearVelocity=b3MakeVector3(0,0,-1);
  643. break;
  644. }
  645. default:{}
  646. };
  647. m_counter++;
  648. if (m_counter>120)
  649. {
  650. m_counter=0;
  651. m_stage++;
  652. if (m_stage>5)
  653. m_stage=0;
  654. }
  655. }
  656. class CommonExampleInterface* TutorialCreateFunc(struct CommonExampleOptions& options)
  657. {
  658. return new Tutorial(options.m_guiHelper, options.m_option);
  659. }