1 #include "Dof6ConstraintTutorial.h"
2
3 #include "btBulletDynamicsCommon.h"
4 #include "BulletDynamics/ConstraintSolver/btNNCGConstraintSolver.h"
5 #include "BulletDynamics/MLCPSolvers/btMLCPSolver.h"
6 #include "BulletDynamics/MLCPSolvers/btSolveProjectedGaussSeidel.h"
7 #include "BulletDynamics/MLCPSolvers/btLemkeSolver.h"
8 #include "BulletDynamics/MLCPSolvers/btDantzigSolver.h"
9 #include "../RenderingExamples/TimeSeriesCanvas.h"
10
11 #include "BulletDynamics/ConstraintSolver/btGeneric6DofSpring2Constraint.h"
12
13 #ifndef M_PI
14 #define M_PI 3.14159265358979323846
15 #endif
16
17 #ifndef M_PI_2
18 #define M_PI_2 1.57079632679489661923
19 #endif
20
21 #ifndef M_PI_4
22 #define M_PI_4 0.785398163397448309616
23 #endif
24
25 extern float g_additionalBodyMass;
26
27 //comment this out to compare with original spring constraint
28 #define USE_6DOF2
29 #ifdef USE_6DOF2
30 #define CONSTRAINT_TYPE btGeneric6DofSpring2Constraint
31 #define EXTRAPARAMS
32 #else
33 #define CONSTRAINT_TYPE btGeneric6DofSpringConstraint
34 #define EXTRAPARAMS , true
35 #endif
36
37 #include "../CommonInterfaces/CommonRigidBodyBase.h"
38
39 struct Dof6ConstraintTutorial : public CommonRigidBodyBase
40 {
41 struct Dof6ConstraintTutorialInternalData* m_data;
42
43 Dof6ConstraintTutorial(struct GUIHelperInterface* helper);
44 virtual ~Dof6ConstraintTutorial();
45 virtual void initPhysics();
46
47 virtual void stepSimulation(float deltaTime);
48
49 void animate();
50
resetCameraDof6ConstraintTutorial51 virtual void resetCamera()
52 {
53 float dist = 5;
54 float pitch = -35;
55 float yaw = 722;
56 float targetPos[3] = {4, 2, -11};
57 m_guiHelper->resetCamera(dist, yaw, pitch, targetPos[0], targetPos[1], targetPos[2]);
58 }
59 };
60
61 struct Dof6ConstraintTutorialInternalData
62 {
63 btRigidBody* m_TranslateSpringBody;
64 btRigidBody* m_TranslateSpringBody2;
65 btRigidBody* m_RotateSpringBody;
66 btRigidBody* m_RotateSpringBody2;
67 btRigidBody* m_BouncingTranslateBody;
68 btRigidBody* m_MotorBody;
69 btRigidBody* m_ServoMotorBody;
70 btRigidBody* m_ChainLeftBody;
71 btRigidBody* m_ChainRightBody;
72 CONSTRAINT_TYPE* m_ServoMotorConstraint;
73 CONSTRAINT_TYPE* m_ChainLeftConstraint;
74 CONSTRAINT_TYPE* m_ChainRightConstraint;
75
76 TimeSeriesCanvas* m_timeSeriesCanvas;
77
78 float mDt;
79
80 unsigned int frameID;
Dof6ConstraintTutorialInternalDataDof6ConstraintTutorialInternalData81 Dof6ConstraintTutorialInternalData()
82 : mDt(1. / 60.), frameID(0)
83 {
84 }
85 };
86
Dof6ConstraintTutorial(struct GUIHelperInterface * helper)87 Dof6ConstraintTutorial::Dof6ConstraintTutorial(struct GUIHelperInterface* helper)
88 : CommonRigidBodyBase(helper)
89 {
90 m_data = new Dof6ConstraintTutorialInternalData;
91 m_data->m_timeSeriesCanvas = new TimeSeriesCanvas(helper->get2dCanvasInterface(), 256, 256, "Position and Velocity");
92 m_data->m_timeSeriesCanvas->setupTimeSeries(20, 100, 0);
93 m_data->m_timeSeriesCanvas->addDataSource("X position (m)", 255, 0, 0);
94 m_data->m_timeSeriesCanvas->addDataSource("X velocity (m/s)", 0, 0, 255);
95 m_data->m_timeSeriesCanvas->addDataSource("dX/dt (m/s)", 0, 0, 0);
96 }
~Dof6ConstraintTutorial()97 Dof6ConstraintTutorial::~Dof6ConstraintTutorial()
98 {
99 delete m_data->m_timeSeriesCanvas;
100 m_data->m_timeSeriesCanvas = 0;
101 exitPhysics();
102 delete m_data;
103 }
initPhysics()104 void Dof6ConstraintTutorial::initPhysics()
105 {
106 // Setup the basic world
107
108 m_guiHelper->setUpAxis(1);
109
110 m_collisionConfiguration = new btDefaultCollisionConfiguration();
111 m_dispatcher = new btCollisionDispatcher(m_collisionConfiguration);
112 btVector3 worldAabbMin(-10000, -10000, -10000);
113 btVector3 worldAabbMax(10000, 10000, 10000);
114 m_broadphase = new btAxisSweep3(worldAabbMin, worldAabbMax);
115
116 /////// uncomment the corresponding line to test a solver.
117 //m_solver = new btSequentialImpulseConstraintSolver;
118 m_solver = new btNNCGConstraintSolver;
119 //m_solver = new btMLCPSolver(new btSolveProjectedGaussSeidel());
120 //m_solver = new btMLCPSolver(new btDantzigSolver());
121 //m_solver = new btMLCPSolver(new btLemkeSolver());
122
123 m_dynamicsWorld = new btDiscreteDynamicsWorld(m_dispatcher, m_broadphase, m_solver, m_collisionConfiguration);
124 m_dynamicsWorld->getDispatchInfo().m_useContinuous = true;
125 m_guiHelper->createPhysicsDebugDrawer(m_dynamicsWorld);
126
127 m_dynamicsWorld->setGravity(btVector3(0, 0, 0));
128
129 // Setup a big ground box
130 if (0)
131 {
132 btCollisionShape* groundShape = new btBoxShape(btVector3(btScalar(200.), btScalar(5.), btScalar(200.)));
133 btTransform groundTransform;
134 groundTransform.setIdentity();
135 groundTransform.setOrigin(btVector3(0, -10, 0));
136 #define CREATE_GROUND_COLLISION_OBJECT 1
137 #ifdef CREATE_GROUND_COLLISION_OBJECT
138 btCollisionObject* fixedGround = new btCollisionObject();
139 fixedGround->setCollisionShape(groundShape);
140 fixedGround->setWorldTransform(groundTransform);
141 m_dynamicsWorld->addCollisionObject(fixedGround);
142 #else
143 localCreateRigidBody(btScalar(0.), groundTransform, groundShape);
144 #endif //CREATE_GROUND_COLLISION_OBJECT
145 }
146
147 m_dynamicsWorld->getSolverInfo().m_numIterations = 100;
148
149 btCollisionShape* shape;
150 btVector3 localInertia(0, 0, 0);
151 btDefaultMotionState* motionState;
152 btTransform bodyTransform;
153 btScalar mass;
154 btTransform localA;
155 btTransform localB;
156 CONSTRAINT_TYPE* constraint;
157
158 //static body centered in the origo
159 mass = 0.0;
160 shape = new btBoxShape(btVector3(0.5, 0.5, 0.5));
161 localInertia = btVector3(0, 0, 0);
162 bodyTransform.setIdentity();
163 motionState = new btDefaultMotionState(bodyTransform);
164 btRigidBody* staticBody = new btRigidBody(mass, motionState, shape, localInertia);
165 m_dynamicsWorld->addRigidBody(staticBody);
166
167 /////////// box with undamped translate spring attached to static body
168 /////////// the box should oscillate left-to-right forever
169 {
170 mass = 1.0;
171 shape = new btBoxShape(btVector3(0.5, 0.5, 0.5));
172 shape->calculateLocalInertia(mass, localInertia);
173 bodyTransform.setIdentity();
174 bodyTransform.setOrigin(btVector3(-2, 0, -5));
175 motionState = new btDefaultMotionState(bodyTransform);
176 m_data->m_TranslateSpringBody = new btRigidBody(mass, motionState, shape, localInertia);
177 m_data->m_TranslateSpringBody->setActivationState(DISABLE_DEACTIVATION);
178 m_dynamicsWorld->addRigidBody(m_data->m_TranslateSpringBody);
179 localA.setIdentity();
180 localA.getOrigin() = btVector3(0, 0, -5);
181 localB.setIdentity();
182 constraint = new CONSTRAINT_TYPE(*staticBody, *m_data->m_TranslateSpringBody, localA, localB EXTRAPARAMS);
183 constraint->setLimit(0, 1, -1);
184 constraint->setLimit(1, 0, 0);
185 constraint->setLimit(2, 0, 0);
186 constraint->setLimit(3, 0, 0);
187 constraint->setLimit(4, 0, 0);
188 constraint->setLimit(5, 0, 0);
189 constraint->enableSpring(0, true);
190 constraint->setStiffness(0, 100);
191 #ifdef USE_6DOF2
192 constraint->setDamping(0, 0);
193 #else
194 constraint->setDamping(0, 1);
195 #endif
196 constraint->setEquilibriumPoint(0, 0);
197 constraint->setDbgDrawSize(btScalar(2.f));
198 m_dynamicsWorld->addConstraint(constraint, true);
199 }
200 #if 0
201 /////////// box with rotate spring, attached to static body
202 /////////// box should swing (rotate) left-to-right forever
203 {
204 mass = 1.0;
205 shape= new btBoxShape(btVector3(0.5,0.5,0.5));
206 shape->calculateLocalInertia(mass,localInertia);
207 bodyTransform.setIdentity();
208 bodyTransform.getBasis().setEulerZYX(0,0,M_PI_2);
209 motionState = new btDefaultMotionState(bodyTransform);
210 m_data->m_RotateSpringBody = new btRigidBody(mass,motionState,shape,localInertia);
211 m_data->m_RotateSpringBody->setActivationState(DISABLE_DEACTIVATION);
212 m_dynamicsWorld->addRigidBody(m_data->m_RotateSpringBody);
213 localA.setIdentity();localA.getOrigin() = btVector3(0,0,0);
214 localB.setIdentity();localB.setOrigin(btVector3(0,0.5,0));
215 constraint = new CONSTRAINT_TYPE(*staticBody, *m_data->m_RotateSpringBody, localA, localB EXTRAPARAMS);
216 constraint->setLimit(0, 0, 0);
217 constraint->setLimit(1, 0, 0);
218 constraint->setLimit(2, 0, 0);
219 constraint->setLimit(3, 0, 0);
220 constraint->setLimit(4, 0, 0);
221 constraint->setLimit(5, 1, -1);
222 constraint->enableSpring(5, true);
223 constraint->setStiffness(5, 100);
224 #ifdef USE_6DOF2
225 constraint->setDamping(5, 0);
226 #else
227 constraint->setDamping(5, 1);
228 #endif
229 constraint->setEquilibriumPoint(0, 0);
230 constraint->setDbgDrawSize(btScalar(2.f));
231 m_dynamicsWorld->addConstraint(constraint, true);
232 }
233
234 /////////// box with bouncing constraint, translation is bounced at the positive x limit, but not at the negative limit
235 /////////// bouncing can not be set independently at low and high limits, so two constraints will be created: one that defines the low (non bouncing) limit, and one that defines the high (bouncing) limit
236 /////////// the box should move to the left (as an impulse will be applied to it periodically) until it reaches its limit, then bounce back
237 {
238 mass = 1.0;
239 shape= new btBoxShape(btVector3(0.5,0.5,0.5));
240 shape->calculateLocalInertia(mass,localInertia);
241 bodyTransform.setIdentity();
242 bodyTransform.setOrigin(btVector3(0,0,-3));
243 motionState = new btDefaultMotionState(bodyTransform);
244 m_data->m_BouncingTranslateBody = new btRigidBody(mass,motionState,shape,localInertia);
245 m_data->m_BouncingTranslateBody->setActivationState(DISABLE_DEACTIVATION);
246 m_data->m_BouncingTranslateBody->setDeactivationTime(btScalar(20000000));
247 m_dynamicsWorld->addRigidBody(m_data->m_BouncingTranslateBody);
248 localA.setIdentity();localA.getOrigin() = btVector3(0,0,0);
249 localB.setIdentity();
250 constraint = new CONSTRAINT_TYPE(*staticBody, *m_data->m_BouncingTranslateBody, localA, localB EXTRAPARAMS);
251 constraint->setLimit(0, -2, SIMD_INFINITY);
252 constraint->setLimit(1, 0, 0);
253 constraint->setLimit(2, -3, -3);
254 constraint->setLimit(3, 0, 0);
255 constraint->setLimit(4, 0, 0);
256 constraint->setLimit(5, 0, 0);
257 #ifdef USE_6DOF2
258 constraint->setBounce(0,0);
259 #else //bounce is named restitution in 6dofspring, but not implemented for translational limit motor, so the following line has no effect
260 constraint->getTranslationalLimitMotor()->m_restitution = 0.0;
261 #endif
262 constraint->setParam(BT_CONSTRAINT_STOP_ERP,0.995,0);
263 constraint->setParam(BT_CONSTRAINT_STOP_CFM,0.0,0);
264 constraint->setDbgDrawSize(btScalar(2.f));
265 m_dynamicsWorld->addConstraint(constraint, true);
266 constraint = new CONSTRAINT_TYPE(*staticBody, *m_data->m_BouncingTranslateBody, localA, localB EXTRAPARAMS);
267 constraint->setLimit(0, -SIMD_INFINITY, 2);
268 constraint->setLimit(1, 0, 0);
269 constraint->setLimit(2, -3, -3);
270 constraint->setLimit(3, 0, 0);
271 constraint->setLimit(4, 0, 0);
272 constraint->setLimit(5, 0, 0);
273 #ifdef USE_6DOF2
274 constraint->setBounce(0,1);
275 #else //bounce is named restitution in 6dofspring, but not implemented for translational limit motor, so the following line has no effect
276 constraint->getTranslationalLimitMotor()->m_restitution = 1.0;
277 #endif
278 constraint->setParam(BT_CONSTRAINT_STOP_ERP,0.995,0);
279 constraint->setParam(BT_CONSTRAINT_STOP_CFM,0.0,0);
280 constraint->setDbgDrawSize(btScalar(2.f));
281 m_dynamicsWorld->addConstraint(constraint, true);
282 }
283
284 /////////// box with rotational motor, attached to static body
285 /////////// the box should rotate around the y axis
286 {
287 mass = 1.0;
288 shape= new btBoxShape(btVector3(0.5,0.5,0.5));
289 shape->calculateLocalInertia(mass,localInertia);
290 bodyTransform.setIdentity();
291 bodyTransform.setOrigin(btVector3(4,0,0));
292 motionState = new btDefaultMotionState(bodyTransform);
293 m_data->m_MotorBody = new btRigidBody(mass,motionState,shape,localInertia);
294 m_data->m_MotorBody->setActivationState(DISABLE_DEACTIVATION);
295 m_dynamicsWorld->addRigidBody(m_data->m_MotorBody);
296 localA.setIdentity();localA.getOrigin() = btVector3(4,0,0);
297 localB.setIdentity();
298 constraint = new CONSTRAINT_TYPE(*staticBody, *m_data->m_MotorBody, localA, localB EXTRAPARAMS);
299 constraint->setLimit(0, 0, 0);
300 constraint->setLimit(1, 0, 0);
301 constraint->setLimit(2, 0, 0);
302 constraint->setLimit(3, 0, 0);
303 constraint->setLimit(4, 0, 0);
304 constraint->setLimit(5, 1,-1);
305 #ifdef USE_6DOF2
306 constraint->enableMotor(5,true);
307 constraint->setTargetVelocity(5,3.f);
308 constraint->setMaxMotorForce(5,600.f);
309 #else
310 constraint->getRotationalLimitMotor(2)->m_enableMotor = true;
311 constraint->getRotationalLimitMotor(2)->m_targetVelocity = 3.f;
312 constraint->getRotationalLimitMotor(2)->m_maxMotorForce = 600.f;
313 #endif
314 constraint->setDbgDrawSize(btScalar(2.f));
315 m_dynamicsWorld->addConstraint(constraint, true);
316 }
317
318 /////////// box with rotational servo motor, attached to static body
319 /////////// the box should rotate around the y axis until it reaches its target
320 /////////// the target will be negated periodically
321 {
322 mass = 1.0;
323 shape= new btBoxShape(btVector3(0.5,0.5,0.5));
324 shape->calculateLocalInertia(mass,localInertia);
325 bodyTransform.setIdentity();
326 bodyTransform.setOrigin(btVector3(7,0,0));
327 motionState = new btDefaultMotionState(bodyTransform);
328 m_data->m_ServoMotorBody = new btRigidBody(mass,motionState,shape,localInertia);
329 m_data->m_ServoMotorBody->setActivationState(DISABLE_DEACTIVATION);
330 m_dynamicsWorld->addRigidBody(m_data->m_ServoMotorBody);
331 localA.setIdentity();localA.getOrigin() = btVector3(7,0,0);
332 localB.setIdentity();
333 constraint = new CONSTRAINT_TYPE(*staticBody, *m_data->m_ServoMotorBody, localA, localB EXTRAPARAMS);
334 constraint->setLimit(0, 0, 0);
335 constraint->setLimit(1, 0, 0);
336 constraint->setLimit(2, 0, 0);
337 constraint->setLimit(3, 0, 0);
338 constraint->setLimit(4, 0, 0);
339 constraint->setLimit(5, 1,-1);
340 #ifdef USE_6DOF2
341 constraint->enableMotor(5,true);
342 constraint->setTargetVelocity(5,3.f);
343 constraint->setMaxMotorForce(5,600.f);
344 constraint->setServo(5,true);
345 constraint->setServoTarget(5, M_PI_2);
346 #else
347 constraint->getRotationalLimitMotor(2)->m_enableMotor = true;
348 constraint->getRotationalLimitMotor(2)->m_targetVelocity = 3.f;
349 constraint->getRotationalLimitMotor(2)->m_maxMotorForce = 600.f;
350 //servo motor is not implemented in 6dofspring constraint
351 #endif
352 constraint->setDbgDrawSize(btScalar(2.f));
353 m_dynamicsWorld->addConstraint(constraint, true);
354 m_data->m_ServoMotorConstraint = constraint;
355 }
356
357 ////////// chain of boxes linked together with fully limited rotational and translational constraints
358 ////////// the chain will be pulled to the left and to the right periodically. They should strictly stick together.
359 {
360 btScalar limitConstraintStrength = 0.6;
361 int bodycount = 10;
362 btRigidBody* prevBody = 0;
363 for(int i = 0; i < bodycount; ++i)
364 {
365 mass = 1.0;
366 shape= new btBoxShape(btVector3(0.5,0.5,0.5));
367 shape->calculateLocalInertia(mass,localInertia);
368 bodyTransform.setIdentity();
369 bodyTransform.setOrigin(btVector3(- i,0,3));
370 motionState = new btDefaultMotionState(bodyTransform);
371 btRigidBody* body = new btRigidBody(mass,motionState,shape,localInertia);
372 body->setActivationState(DISABLE_DEACTIVATION);
373 m_dynamicsWorld->addRigidBody(body);
374 if(prevBody != 0)
375 {
376 localB.setIdentity();
377 localB.setOrigin(btVector3(0.5,0,0));
378 btTransform localA;
379 localA.setIdentity();
380 localA.setOrigin(btVector3(-0.5,0,0));
381 CONSTRAINT_TYPE* constraint = new CONSTRAINT_TYPE(*prevBody, *body, localA, localB EXTRAPARAMS);
382 constraint->setLimit(0, -0.01, 0.01);
383 constraint->setLimit(1, 0, 0);
384 constraint->setLimit(2, 0, 0);
385 constraint->setLimit(3, 0, 0);
386 constraint->setLimit(4, 0, 0);
387 constraint->setLimit(5, 0, 0);
388 for(int a = 0; a < 6; ++a)
389 {
390 constraint->setParam(BT_CONSTRAINT_STOP_ERP,0.9,a);
391 constraint->setParam(BT_CONSTRAINT_STOP_CFM,0.0,a);
392 }
393 constraint->setDbgDrawSize(btScalar(1.f));
394 m_dynamicsWorld->addConstraint(constraint, true);
395
396 if(i < bodycount - 1)
397 {
398 localA.setIdentity();localA.getOrigin() = btVector3(0,0,3);
399 localB.setIdentity();
400 CONSTRAINT_TYPE* constraintZY = new CONSTRAINT_TYPE(*staticBody, *body, localA, localB EXTRAPARAMS);
401 constraintZY->setLimit(0, 1, -1);
402 constraintZY->setDbgDrawSize(btScalar(1.f));
403 m_dynamicsWorld->addConstraint(constraintZY, true);
404
405 }
406 }
407 else
408 {
409 localA.setIdentity();localA.getOrigin() = btVector3(bodycount,0,3);
410 localB.setIdentity();
411 localB.setOrigin(btVector3(0,0,0));
412 m_data->m_ChainLeftBody = body;
413 m_data->m_ChainLeftConstraint = new CONSTRAINT_TYPE(*staticBody, *body, localA, localB EXTRAPARAMS);
414 m_data->m_ChainLeftConstraint->setLimit(3,0,0);
415 m_data->m_ChainLeftConstraint->setLimit(4,0,0);
416 m_data->m_ChainLeftConstraint->setLimit(5,0,0);
417 for(int a = 0; a < 6; ++a)
418 {
419 m_data->m_ChainLeftConstraint->setParam(BT_CONSTRAINT_STOP_ERP,limitConstraintStrength,a);
420 m_data->m_ChainLeftConstraint->setParam(BT_CONSTRAINT_STOP_CFM,0.0,a);
421 }
422 m_data->m_ChainLeftConstraint->setDbgDrawSize(btScalar(1.f));
423 m_dynamicsWorld->addConstraint(m_data->m_ChainLeftConstraint, true);
424 }
425 prevBody = body;
426 }
427 m_data->m_ChainRightBody = prevBody;
428 localA.setIdentity();localA.getOrigin() = btVector3(-bodycount,0,3);
429 localB.setIdentity();
430 localB.setOrigin(btVector3(0,0,0));
431 m_data->m_ChainRightConstraint = new CONSTRAINT_TYPE(*staticBody, *m_data->m_ChainRightBody, localA, localB EXTRAPARAMS);
432 m_data->m_ChainRightConstraint->setLimit(3,0,0);
433 m_data->m_ChainRightConstraint->setLimit(4,0,0);
434 m_data->m_ChainRightConstraint->setLimit(5,0,0);
435 for(int a = 0; a < 6; ++a)
436 {
437 m_data->m_ChainRightConstraint->setParam(BT_CONSTRAINT_STOP_ERP,limitConstraintStrength,a);
438 m_data->m_ChainRightConstraint->setParam(BT_CONSTRAINT_STOP_CFM,0.0,a);
439 }
440 }
441 #endif
442 m_guiHelper->autogenerateGraphicsObjects(m_dynamicsWorld);
443 }
444
animate()445 void Dof6ConstraintTutorial::animate()
446 {
447 /////// servo motor: flip its target periodically
448 #ifdef USE_6DOF2
449 static float servoNextFrame = -1;
450 //btScalar pos = m_data->m_ServoMotorConstraint->getRotationalLimitMotor(2)->m_currentPosition;
451 //btScalar target = m_data->m_ServoMotorConstraint->getRotationalLimitMotor(2)->m_servoTarget;
452 if (servoNextFrame < 0)
453 {
454 m_data->m_ServoMotorConstraint->getRotationalLimitMotor(2)->m_servoTarget *= -1;
455 servoNextFrame = 3.0;
456 }
457 servoNextFrame -= m_data->mDt;
458 #endif
459
460 /////// constraint chain: pull the chain left and right periodically
461 static float chainNextFrame = -1;
462 static bool left = true;
463 if (chainNextFrame < 0)
464 {
465 if (!left)
466 {
467 m_data->m_ChainRightBody->setActivationState(ACTIVE_TAG);
468 m_dynamicsWorld->removeConstraint(m_data->m_ChainRightConstraint);
469 m_data->m_ChainLeftConstraint->setDbgDrawSize(btScalar(2.f));
470 m_dynamicsWorld->addConstraint(m_data->m_ChainLeftConstraint, true);
471 }
472 else
473 {
474 m_data->m_ChainLeftBody->setActivationState(ACTIVE_TAG);
475 m_dynamicsWorld->removeConstraint(m_data->m_ChainLeftConstraint);
476 m_data->m_ChainRightConstraint->setDbgDrawSize(btScalar(2.f));
477 m_dynamicsWorld->addConstraint(m_data->m_ChainRightConstraint, true);
478 }
479 chainNextFrame = 3.0;
480 left = !left;
481 }
482 chainNextFrame -= m_data->mDt;
483
484 /////// bouncing constraint: push the box periodically
485 m_data->m_BouncingTranslateBody->setActivationState(ACTIVE_TAG);
486 static float bounceNextFrame = -1;
487 if (bounceNextFrame < 0)
488 {
489 m_data->m_BouncingTranslateBody->applyCentralImpulse(btVector3(10, 0, 0));
490 bounceNextFrame = 3.0;
491 }
492 bounceNextFrame -= m_data->mDt;
493
494 m_data->frameID++;
495 }
496
stepSimulation(float deltaTime)497 void Dof6ConstraintTutorial::stepSimulation(float deltaTime)
498 {
499 //animate();
500
501 //float time = m_data->m_timeSeriesCanvas->getCurrentTime();
502
503 float prevPos = m_data->m_TranslateSpringBody->getWorldTransform().getOrigin().x();
504 m_dynamicsWorld->stepSimulation(deltaTime);
505 float xPos = m_data->m_TranslateSpringBody->getWorldTransform().getOrigin().x();
506
507 m_data->m_timeSeriesCanvas->insertDataAtCurrentTime(xPos, 0, true);
508 m_data->m_timeSeriesCanvas->insertDataAtCurrentTime(m_data->m_TranslateSpringBody->getLinearVelocity().x(), 1, true);
509
510 if (deltaTime > 0)
511 {
512 m_data->m_timeSeriesCanvas->insertDataAtCurrentTime((xPos - prevPos) / deltaTime, 2, true);
513 }
514 prevPos = xPos;
515 m_data->m_timeSeriesCanvas->nextTick();
516 }
517
Dof6ConstraintTutorialCreateFunc(CommonExampleOptions & options)518 class CommonExampleInterface* Dof6ConstraintTutorialCreateFunc(CommonExampleOptions& options)
519 {
520 return new Dof6ConstraintTutorial(options.m_guiHelper);
521 }
522