2 Bullet Continuous Collision Detection and Physics Library
3 Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
5 This software is provided 'as-is', without any express or implied warranty.
6 In no event will the authors be held liable for any damages arising from the use of this software.
7 Permission is granted to anyone to use this software for any purpose,
8 including commercial applications, and to alter it and redistribute it freely,
9 subject to the following restrictions:
11 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.
12 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13 3. This notice may not be removed or altered from any source distribution.
19 #define COLLISION_RADIUS 0.0f
21 #include "BenchmarkDemo.h"
22 #ifdef USE_GRAPHICAL_BENCHMARK
23 #include "GlutStuff.h"
24 #endif //USE_GRAPHICAL_BENCHMARK
26 ///btBulletDynamicsCommon.h is the main Bullet include file, contains most common include files.
27 #include "btBulletDynamicsCommon.h"
28 #include <stdio.h> //printf debugging
30 #include "landscape.mdl"
31 #include "BulletCollision/BroadphaseCollision/btDbvtBroadphase.h"
32 #ifdef USE_PARALLEL_DISPATCHER_BENCHMARK
33 #include "BulletMultiThreaded/SpuGatheringCollisionDispatcher.h"
34 #include "BulletMultiThreaded/SequentialThreadSupport.h"
35 #include "BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuGatheringCollisionTask.h"
38 #include "BulletCollision/CollisionDispatch/btSimulationIslandManager.h"
41 #ifdef USE_PARALLEL_DISPATCHER_BENCHMARK
43 #include "BulletMultiThreaded/Win32ThreadSupport.h"
44 #elif defined (USE_PTHREADS)
45 #include "BulletMultiThreaded/PosixThreadSupport.h"
47 #include "BulletMultiThreaded/SpuGatheringCollisionDispatcher.h"
48 #include "BulletMultiThreaded/btParallelConstraintSolver.h"
53 btThreadSupportInterface* createSolverThreadSupport(int maxNumThreads)
57 SequentialThreadSupport::SequentialThreadConstructionInfo tci("solverThreads",SolverThreadFunc,SolverlsMemoryFunc);
58 SequentialThreadSupport* threadSupport = new SequentialThreadSupport(tci);
59 threadSupport->startSPU();
63 Win32ThreadSupport::Win32ThreadConstructionInfo threadConstructionInfo("solverThreads",SolverThreadFunc,SolverlsMemoryFunc,maxNumThreads);
64 Win32ThreadSupport* threadSupport = new Win32ThreadSupport(threadConstructionInfo);
65 threadSupport->startSPU();
66 #elif defined (USE_PTHREADS)
67 PosixThreadSupport::ThreadConstructionInfo solverConstructionInfo("solver", SolverThreadFunc,
68 SolverlsMemoryFunc, maxNumThreads);
70 PosixThreadSupport* threadSupport = new PosixThreadSupport(solverConstructionInfo);
73 SequentialThreadSupport::SequentialThreadConstructionInfo tci("solverThreads",SolverThreadFunc,SolverlsMemoryFunc);
74 SequentialThreadSupport* threadSupport = new SequentialThreadSupport(tci);
75 threadSupport->startSPU();
87 btVector3 source[NUMRAYS];
88 btVector3 dest[NUMRAYS];
89 btVector3 direction[NUMRAYS];
90 btVector3 hit[NUMRAYS];
91 btVector3 normal[NUMRAYS];
102 #endif //USE_BT_CLOCK
121 btRaycastBar2 (btScalar ray_length, btScalar z,btScalar max_y)
134 btScalar dalpha = 2*SIMD_2_PI/NUMRAYS;
135 for (int i = 0; i < NUMRAYS; i++)
137 btScalar alpha = dalpha * i;
138 // rotate around by alpha degrees y
139 btQuaternion q(btVector3(0.0, 1.0, 0.0), alpha);
140 direction[i] = btVector3(1.0, 0.0, 0.0);
141 direction[i] = quatRotate(q , direction[i]);
142 direction[i] = direction[i] * ray_length;
145 source[i] = btVector3(min_x, max_y, z);
146 dest[i] = source[i] + direction[i];
148 normal[i] = btVector3(1.0, 0.0, 0.0);
152 void move (btScalar dt)
154 if (dt > btScalar(1.0/60.0))
155 dt = btScalar(1.0/60.0);
156 for (int i = 0; i < NUMRAYS; i++)
158 source[i][0] += dx * dt * sign;
159 dest[i][0] += dx * dt * sign;
161 if (source[0][0] < min_x)
163 else if (source[0][0] > max_x)
167 void cast (btCollisionWorld* cw)
170 frame_timer.reset ();
171 #endif //USE_BT_CLOCK
173 #ifdef BATCH_RAYCASTER
174 if (!gBatchRaycaster)
177 gBatchRaycaster->clearRays ();
178 for (int i = 0; i < NUMRAYS; i++)
180 gBatchRaycaster->addRay (source[i], dest[i]);
182 gBatchRaycaster->performBatchRaycast ();
183 for (int i = 0; i < gBatchRaycaster->getNumRays (); i++)
185 const SpuRaycastTaskWorkUnitOut& out = (*gBatchRaycaster)[i];
186 hit[i].setInterpolate3(source[i],dest[i],out.hitFraction);
187 normal[i] = out.hitNormal;
188 normal[i].normalize ();
191 for (int i = 0; i < NUMRAYS; i++)
193 btCollisionWorld::ClosestRayResultCallback cb(source[i], dest[i]);
195 cw->rayTest (source[i], dest[i], cb);
198 hit[i] = cb.m_hitPointWorld;
199 normal[i] = cb.m_hitNormalWorld;
200 normal[i].normalize ();
203 normal[i] = btVector3(1.0, 0.0, 0.0);
208 ms += frame_timer.getTimeMilliseconds ();
209 #endif //USE_BT_CLOCK
211 if (frame_counter > 50)
213 min_ms = ms < min_ms ? ms : min_ms;
214 max_ms = ms > max_ms ? ms : max_ms;
217 btScalar mean_ms = (btScalar)sum_ms/(btScalar)sum_ms_samples;
218 printf("%d rays in %d ms %d %d %f\n", NUMRAYS * frame_counter, ms, min_ms, max_ms, mean_ms);
227 #ifdef USE_GRAPHICAL_BENCHMARK
228 glDisable (GL_LIGHTING);
229 glColor3f (0.0, 1.0, 0.0);
233 for (i = 0; i < NUMRAYS; i++)
235 glVertex3f (source[i][0], source[i][1], source[i][2]);
236 glVertex3f (hit[i][0], hit[i][1], hit[i][2]);
239 glColor3f (1.0, 1.0, 1.0);
241 for (i = 0; i < NUMRAYS; i++)
243 glVertex3f (hit[i][0], hit[i][1], hit[i][2]);
244 glVertex3f (hit[i][0] + normal[i][0], hit[i][1] + normal[i][1], hit[i][2] + normal[i][2]);
247 glColor3f (0.0, 1.0, 1.0);
249 for ( i = 0; i < NUMRAYS; i++)
251 glVertex3f (hit[i][0], hit[i][1], hit[i][2]);
254 glEnable (GL_LIGHTING);
255 #endif //USE_GRAPHICAL_BENCHMARK
261 static btRaycastBar2 raycastBar;
264 void BenchmarkDemo::clientMoveAndDisplay()
266 #ifdef USE_GRAPHICAL_BENCHMARK
267 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
268 #endif //USE_GRAPHICAL_BENCHMARK
270 //simple dynamics world doesn't handle fixed-time-stepping
271 //float ms = getDeltaTimeMicroseconds();
273 ///step the simulation
276 m_dynamicsWorld->stepSimulation(btScalar(1./60.));
277 //optional but useful: debug drawing
278 m_dynamicsWorld->debugDrawWorld();
291 #ifdef USE_GRAPHICAL_BENCHMARK
295 #endif //USE_GRAPHICAL_BENCHMARK
301 void BenchmarkDemo::displayCallback(void)
304 #ifdef USE_GRAPHICAL_BENCHMARK
305 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
309 //optional but useful: debug drawing to detect problems
311 m_dynamicsWorld->debugDrawWorld();
315 #endif //USE_GRAPHICAL_BENCHMARK
321 void BenchmarkDemo::initPhysics()
324 setCameraDistance(btScalar(100.));
326 ///collision configuration contains default setup for memory, collision setup
327 btDefaultCollisionConstructionInfo cci;
328 cci.m_defaultMaxPersistentManifoldPoolSize = 32768;
329 m_collisionConfiguration = new btDefaultCollisionConfiguration(cci);
331 ///use the default collision dispatcher. For parallel processing you can use a diffent dispatcher (see Extras/BulletMultiThreaded)
332 m_dispatcher = new btCollisionDispatcher(m_collisionConfiguration);
334 m_dispatcher->setDispatcherFlags(btCollisionDispatcher::CD_DISABLE_CONTACTPOOL_DYNAMIC_ALLOCATION);
336 #if USE_PARALLEL_DISPATCHER_BENCHMARK
338 int maxNumOutstandingTasks = 4;
340 Win32ThreadSupport* threadSupportCollision = new Win32ThreadSupport(Win32ThreadSupport::Win32ThreadConstructionInfo( "collision",processCollisionTask, createCollisionLocalStoreMemory,maxNumOutstandingTasks));
341 #elif defined (USE_PTHREADS)
342 PosixThreadSupport::ThreadConstructionInfo collisionConstructionInfo( "collision",processCollisionTask, createCollisionLocalStoreMemory,maxNumOutstandingTasks);
343 PosixThreadSupport* threadSupportCollision = new PosixThreadSupport(collisionConstructionInfo);
345 //SequentialThreadSupport::SequentialThreadConstructionInfo sci("spuCD", processCollisionTask, createCollisionLocalStoreMemory);
346 //SequentialThreadSupport* seq = new SequentialThreadSupport(sci);
347 m_dispatcher = new SpuGatheringCollisionDispatcher(threadSupportCollision,1,m_collisionConfiguration);
351 ///the maximum size of the collision world. Make sure objects stay within these boundaries
352 ///Don't make the world AABB size too large, it will harm simulation quality and performance
353 btVector3 worldAabbMin(-1000,-1000,-1000);
354 btVector3 worldAabbMax(1000,1000,1000);
356 btHashedOverlappingPairCache* pairCache = new btHashedOverlappingPairCache();
357 m_overlappingPairCache = new btAxisSweep3(worldAabbMin,worldAabbMax,3500,pairCache);
358 // m_overlappingPairCache = new btSimpleBroadphase();
359 // m_overlappingPairCache = new btDbvtBroadphase();
362 ///the default constraint solver. For parallel processing you can use a different solver (see Extras/BulletMultiThreaded)
363 #ifdef USE_PARALLEL_DISPATCHER_BENCHMARK
365 btThreadSupportInterface* thread = createSolverThreadSupport(4);
366 btConstraintSolver* sol = new btParallelConstraintSolver(thread);
368 btSequentialImpulseConstraintSolver* sol = new btSequentialImpulseConstraintSolver;
369 #endif //USE_PARALLEL_DISPATCHER_BENCHMARK
374 btDiscreteDynamicsWorld* dynamicsWorld;
375 m_dynamicsWorld = dynamicsWorld = new btDiscreteDynamicsWorld(m_dispatcher,m_overlappingPairCache,m_solver,m_collisionConfiguration);
377 #ifdef USE_PARALLEL_DISPATCHER_BENCHMARK
378 dynamicsWorld->getSimulationIslandManager()->setSplitIslands(false);
379 #endif //USE_PARALLEL_DISPATCHER_BENCHMARK
381 ///the following 3 lines increase the performance dramatically, with a little bit of loss of quality
382 m_dynamicsWorld->getSolverInfo().m_solverMode |=SOLVER_ENABLE_FRICTION_DIRECTION_CACHING; //don't recalculate friction values each frame
383 dynamicsWorld->getSolverInfo().m_numIterations = 5; //few solver iterations
384 m_defaultContactProcessingThreshold = 0.f;//used when creating bodies: body->setContactProcessingThreshold(...);
387 m_dynamicsWorld->setGravity(btVector3(0,-10,0));
391 ///create a few basic rigid bodies
392 btCollisionShape* groundShape = new btBoxShape(btVector3(btScalar(250.),btScalar(50.),btScalar(250.)));
393 // btCollisionShape* groundShape = new btStaticPlaneShape(btVector3(0,1,0),0);
395 m_collisionShapes.push_back(groundShape);
397 btTransform groundTransform;
398 groundTransform.setIdentity();
399 groundTransform.setOrigin(btVector3(0,-50,0));
401 //We can also use DemoApplication::localCreateRigidBody, but for clarity it is provided here:
405 //rigidbody is dynamic if and only if mass is non zero, otherwise static
406 bool isDynamic = (mass != 0.f);
408 btVector3 localInertia(0,0,0);
410 groundShape->calculateLocalInertia(mass,localInertia);
412 //using motionstate is recommended, it provides interpolation capabilities, and only synchronizes 'active' objects
413 btDefaultMotionState* myMotionState = new btDefaultMotionState(groundTransform);
414 btRigidBody::btRigidBodyConstructionInfo rbInfo(mass,myMotionState,groundShape,localInertia);
415 btRigidBody* body = new btRigidBody(rbInfo);
417 //add the body to the dynamics world
418 m_dynamicsWorld->addRigidBody(body);
471 void BenchmarkDemo::createTest1()
475 const float cubeSize = 1.0f;
476 float spacing = cubeSize;
477 btVector3 pos(0.0f, cubeSize * 2,0.f);
478 float offset = -size * (cubeSize * 2.0f + spacing) * 0.5f;
480 btBoxShape* blockShape = new btBoxShape(btVector3(cubeSize-COLLISION_RADIUS,cubeSize-COLLISION_RADIUS,cubeSize-COLLISION_RADIUS));
481 btVector3 localInertia(0,0,0);
483 blockShape->calculateLocalInertia(mass,localInertia);
488 for(int k=0;k<47;k++) {
489 for(int j=0;j<size;j++) {
490 pos[2] = offset + (float)j * (cubeSize * 2.0f + spacing);
491 for(int i=0;i<size;i++) {
492 pos[0] = offset + (float)i * (cubeSize * 2.0f + spacing);
494 trans.setOrigin(pos);
496 cmbody= localCreateRigidBody(mass,trans,blockShape);
499 offset -= 0.05f * spacing * (size-1);
501 pos[1] += (cubeSize * 2.0f + spacing);
506 ///////////////////////////////////////////////////////////////////////////////
509 void BenchmarkDemo::createWall(const btVector3& offsetPosition,int stackSize,const btVector3& boxSize)
512 btBoxShape* blockShape = new btBoxShape(btVector3(boxSize[0]-COLLISION_RADIUS,boxSize[1]-COLLISION_RADIUS,boxSize[2]-COLLISION_RADIUS));
515 btVector3 localInertia(0,0,0);
516 blockShape->calculateLocalInertia(mass,localInertia);
518 // btScalar diffX = boxSize[0] * 1.0f;
519 btScalar diffY = boxSize[1] * 1.0f;
520 btScalar diffZ = boxSize[2] * 1.0f;
522 btScalar offset = -stackSize * (diffZ * 2.0f) * 0.5f;
523 btVector3 pos(0.0f, diffY, 0.0f);
529 for(int i=0;i<stackSize;i++) {
530 pos[2] = offset + (float)i * (diffZ * 2.0f);
532 trans.setOrigin(offsetPosition + pos);
533 localCreateRigidBody(mass,trans,blockShape);
537 pos[1] += (diffY * 2.0f);
542 void BenchmarkDemo::createPyramid(const btVector3& offsetPosition,int stackSize,const btVector3& boxSize)
544 btScalar space = 0.0001f;
546 btVector3 pos(0.0f, boxSize[1], 0.0f);
548 btBoxShape* blockShape = new btBoxShape(btVector3(boxSize[0]-COLLISION_RADIUS,boxSize[1]-COLLISION_RADIUS,boxSize[2]-COLLISION_RADIUS));
553 btVector3 localInertia(0,0,0);
554 blockShape->calculateLocalInertia(mass,localInertia);
557 btScalar diffX = boxSize[0]*1.02f;
558 btScalar diffY = boxSize[1]*1.02f;
559 btScalar diffZ = boxSize[2]*1.02f;
561 btScalar offsetX = -stackSize * (diffX * 2.0f + space) * 0.5f;
562 btScalar offsetZ = -stackSize * (diffZ * 2.0f + space) * 0.5f;
564 for(int j=0;j<stackSize;j++) {
565 pos[2] = offsetZ + (float)j * (diffZ * 2.0f + space);
566 for(int i=0;i<stackSize;i++) {
567 pos[0] = offsetX + (float)i * (diffX * 2.0f + space);
568 trans.setOrigin(offsetPosition + pos);
569 this->localCreateRigidBody(mass,trans,blockShape);
576 pos[1] += (diffY * 2.0f + space);
582 const btVector3 rotate( const btQuaternion& quat, const btVector3 & vec )
584 float tmpX, tmpY, tmpZ, tmpW;
585 tmpX = ( ( ( quat.getW() * vec.getX() ) + ( quat.getY() * vec.getZ() ) ) - ( quat.getZ() * vec.getY() ) );
586 tmpY = ( ( ( quat.getW() * vec.getY() ) + ( quat.getZ() * vec.getX() ) ) - ( quat.getX() * vec.getZ() ) );
587 tmpZ = ( ( ( quat.getW() * vec.getZ() ) + ( quat.getX() * vec.getY() ) ) - ( quat.getY() * vec.getX() ) );
588 tmpW = ( ( ( quat.getX() * vec.getX() ) + ( quat.getY() * vec.getY() ) ) + ( quat.getZ() * vec.getZ() ) );
590 ( ( ( ( tmpW * quat.getX() ) + ( tmpX * quat.getW() ) ) - ( tmpY * quat.getZ() ) ) + ( tmpZ * quat.getY() ) ),
591 ( ( ( ( tmpW * quat.getY() ) + ( tmpY * quat.getW() ) ) - ( tmpZ * quat.getX() ) ) + ( tmpX * quat.getZ() ) ),
592 ( ( ( ( tmpW * quat.getZ() ) + ( tmpZ * quat.getW() ) ) - ( tmpX * quat.getY() ) ) + ( tmpY * quat.getX() ) )
596 void BenchmarkDemo::createTowerCircle(const btVector3& offsetPosition,int stackSize,int rotSize,const btVector3& boxSize)
599 btBoxShape* blockShape = new btBoxShape(btVector3(boxSize[0]-COLLISION_RADIUS,boxSize[1]-COLLISION_RADIUS,boxSize[2]-COLLISION_RADIUS));
605 btVector3 localInertia(0,0,0);
606 blockShape->calculateLocalInertia(mass,localInertia);
609 float radius = 1.3f * rotSize * boxSize[0] / SIMD_PI;
611 // create active boxes
612 btQuaternion rotY(0,1,0,0);
613 float posY = boxSize[1];
615 for(int i=0;i<stackSize;i++) {
616 for(int j=0;j<rotSize;j++) {
619 trans.setOrigin(offsetPosition+ rotate(rotY,btVector3(0.0f , posY, radius)));
620 trans.setRotation(rotY);
621 localCreateRigidBody(mass,trans,blockShape);
623 rotY *= btQuaternion(btVector3(0,1,0),SIMD_PI/(rotSize*btScalar(0.5)));
626 posY += boxSize[1] * 2.0f;
627 rotY *= btQuaternion(btVector3(0,1,0),SIMD_PI/(float)rotSize);
632 void BenchmarkDemo::createTest2()
634 setCameraDistance(btScalar(50.));
635 const float cubeSize = 1.0f;
637 createPyramid(btVector3(-20.0f,0.0f,0.0f),12,btVector3(cubeSize,cubeSize,cubeSize));
638 createWall(btVector3(-2.0f,0.0f,0.0f),12,btVector3(cubeSize,cubeSize,cubeSize));
639 createWall(btVector3(4.0f,0.0f,0.0f),12,btVector3(cubeSize,cubeSize,cubeSize));
640 createWall(btVector3(10.0f,0.0f,0.0f),12,btVector3(cubeSize,cubeSize,cubeSize));
641 createTowerCircle(btVector3(25.0f,0.0f,0.0f),8,24,btVector3(cubeSize,cubeSize,cubeSize));
648 // Enrico: Shouldn't these three variables be real constants and not defines?
651 #define M_PI btScalar(3.14159265358979323846)
655 #define M_PI_2 btScalar(1.57079632679489661923)
659 #define M_PI_4 btScalar(0.785398163397448309616)
670 BODYPART_LEFT_UPPER_LEG,
671 BODYPART_LEFT_LOWER_LEG,
673 BODYPART_RIGHT_UPPER_LEG,
674 BODYPART_RIGHT_LOWER_LEG,
676 BODYPART_LEFT_UPPER_ARM,
677 BODYPART_LEFT_LOWER_ARM,
679 BODYPART_RIGHT_UPPER_ARM,
680 BODYPART_RIGHT_LOWER_ARM,
687 JOINT_PELVIS_SPINE = 0,
699 JOINT_RIGHT_SHOULDER,
705 btDynamicsWorld* m_ownerWorld;
706 btCollisionShape* m_shapes[BODYPART_COUNT];
707 btRigidBody* m_bodies[BODYPART_COUNT];
708 btTypedConstraint* m_joints[JOINT_COUNT];
710 btRigidBody* localCreateRigidBody (btScalar mass, const btTransform& startTransform, btCollisionShape* shape)
712 bool isDynamic = (mass != 0.f);
714 btVector3 localInertia(0,0,0);
716 shape->calculateLocalInertia(mass,localInertia);
718 btDefaultMotionState* myMotionState = new btDefaultMotionState(startTransform);
720 btRigidBody::btRigidBodyConstructionInfo rbInfo(mass,myMotionState,shape,localInertia);
721 btRigidBody* body = new btRigidBody(rbInfo);
723 m_ownerWorld->addRigidBody(body);
729 RagDoll (btDynamicsWorld* ownerWorld, const btVector3& positionOffset,btScalar scale)
730 : m_ownerWorld (ownerWorld)
732 // Setup the geometry
733 m_shapes[BODYPART_PELVIS] = new btCapsuleShape(btScalar(0.15)*scale, btScalar(0.20)*scale);
734 m_shapes[BODYPART_SPINE] = new btCapsuleShape(btScalar(0.15)*scale, btScalar(0.28)*scale);
735 m_shapes[BODYPART_HEAD] = new btCapsuleShape(btScalar(0.10)*scale, btScalar(0.05)*scale);
736 m_shapes[BODYPART_LEFT_UPPER_LEG] = new btCapsuleShape(btScalar(0.07)*scale, btScalar(0.45)*scale);
737 m_shapes[BODYPART_LEFT_LOWER_LEG] = new btCapsuleShape(btScalar(0.05)*scale, btScalar(0.37)*scale);
738 m_shapes[BODYPART_RIGHT_UPPER_LEG] = new btCapsuleShape(btScalar(0.07)*scale, btScalar(0.45)*scale);
739 m_shapes[BODYPART_RIGHT_LOWER_LEG] = new btCapsuleShape(btScalar(0.05)*scale, btScalar(0.37)*scale);
740 m_shapes[BODYPART_LEFT_UPPER_ARM] = new btCapsuleShape(btScalar(0.05)*scale, btScalar(0.33)*scale);
741 m_shapes[BODYPART_LEFT_LOWER_ARM] = new btCapsuleShape(btScalar(0.04)*scale, btScalar(0.25)*scale);
742 m_shapes[BODYPART_RIGHT_UPPER_ARM] = new btCapsuleShape(btScalar(0.05)*scale, btScalar(0.33)*scale);
743 m_shapes[BODYPART_RIGHT_LOWER_ARM] = new btCapsuleShape(btScalar(0.04)*scale, btScalar(0.25)*scale);
745 // Setup all the rigid bodies
746 btTransform offset; offset.setIdentity();
747 offset.setOrigin(positionOffset);
749 btTransform transform;
750 transform.setIdentity();
751 transform.setOrigin(scale*btVector3(btScalar(0.), btScalar(1.), btScalar(0.)));
752 m_bodies[BODYPART_PELVIS] = localCreateRigidBody(btScalar(1.), offset*transform, m_shapes[BODYPART_PELVIS]);
754 transform.setIdentity();
755 transform.setOrigin(scale*btVector3(btScalar(0.), btScalar(1.2), btScalar(0.)));
756 m_bodies[BODYPART_SPINE] = localCreateRigidBody(btScalar(1.), offset*transform, m_shapes[BODYPART_SPINE]);
758 transform.setIdentity();
759 transform.setOrigin(scale*btVector3(btScalar(0.), btScalar(1.6), btScalar(0.)));
760 m_bodies[BODYPART_HEAD] = localCreateRigidBody(btScalar(1.), offset*transform, m_shapes[BODYPART_HEAD]);
762 transform.setIdentity();
763 transform.setOrigin(scale*btVector3(btScalar(-0.18), btScalar(0.65), btScalar(0.)));
764 m_bodies[BODYPART_LEFT_UPPER_LEG] = localCreateRigidBody(btScalar(1.), offset*transform, m_shapes[BODYPART_LEFT_UPPER_LEG]);
766 transform.setIdentity();
767 transform.setOrigin(scale*btVector3(btScalar(-0.18), btScalar(0.2), btScalar(0.)));
768 m_bodies[BODYPART_LEFT_LOWER_LEG] = localCreateRigidBody(btScalar(1.), offset*transform, m_shapes[BODYPART_LEFT_LOWER_LEG]);
770 transform.setIdentity();
771 transform.setOrigin(scale*btVector3(btScalar(0.18), btScalar(0.65), btScalar(0.)));
772 m_bodies[BODYPART_RIGHT_UPPER_LEG] = localCreateRigidBody(btScalar(1.), offset*transform, m_shapes[BODYPART_RIGHT_UPPER_LEG]);
774 transform.setIdentity();
775 transform.setOrigin(scale*btVector3(btScalar(0.18), btScalar(0.2), btScalar(0.)));
776 m_bodies[BODYPART_RIGHT_LOWER_LEG] = localCreateRigidBody(btScalar(1.), offset*transform, m_shapes[BODYPART_RIGHT_LOWER_LEG]);
778 transform.setIdentity();
779 transform.setOrigin(scale*btVector3(btScalar(-0.35), btScalar(1.45), btScalar(0.)));
780 transform.getBasis().setEulerZYX(0,0,M_PI_2);
781 m_bodies[BODYPART_LEFT_UPPER_ARM] = localCreateRigidBody(btScalar(1.), offset*transform, m_shapes[BODYPART_LEFT_UPPER_ARM]);
783 transform.setIdentity();
784 transform.setOrigin(scale*btVector3(btScalar(-0.7), btScalar(1.45), btScalar(0.)));
785 transform.getBasis().setEulerZYX(0,0,M_PI_2);
786 m_bodies[BODYPART_LEFT_LOWER_ARM] = localCreateRigidBody(btScalar(1.), offset*transform, m_shapes[BODYPART_LEFT_LOWER_ARM]);
788 transform.setIdentity();
789 transform.setOrigin(scale*btVector3(btScalar(0.35), btScalar(1.45), btScalar(0.)));
790 transform.getBasis().setEulerZYX(0,0,-M_PI_2);
791 m_bodies[BODYPART_RIGHT_UPPER_ARM] = localCreateRigidBody(btScalar(1.), offset*transform, m_shapes[BODYPART_RIGHT_UPPER_ARM]);
793 transform.setIdentity();
794 transform.setOrigin(scale*btVector3(btScalar(0.7), btScalar(1.45), btScalar(0.)));
795 transform.getBasis().setEulerZYX(0,0,-M_PI_2);
796 m_bodies[BODYPART_RIGHT_LOWER_ARM] = localCreateRigidBody(btScalar(1.), offset*transform, m_shapes[BODYPART_RIGHT_LOWER_ARM]);
798 // Setup some damping on the m_bodies
799 for (int i = 0; i < BODYPART_COUNT; ++i)
801 m_bodies[i]->setDamping(btScalar(0.05), btScalar(0.85));
802 m_bodies[i]->setDeactivationTime(btScalar(0.8));
803 m_bodies[i]->setSleepingThresholds(btScalar(1.6), btScalar(2.5));
806 // Now setup the constraints
807 btHingeConstraint* hingeC;
808 btConeTwistConstraint* coneC;
810 btTransform localA, localB;
812 localA.setIdentity(); localB.setIdentity();
813 localA.getBasis().setEulerZYX(0,M_PI_2,0); localA.setOrigin(scale*btVector3(btScalar(0.), btScalar(0.15), btScalar(0.)));
814 localB.getBasis().setEulerZYX(0,M_PI_2,0); localB.setOrigin(scale*btVector3(btScalar(0.), btScalar(-0.15), btScalar(0.)));
815 hingeC = new btHingeConstraint(*m_bodies[BODYPART_PELVIS], *m_bodies[BODYPART_SPINE], localA, localB);
816 hingeC->setLimit(btScalar(-M_PI_4), btScalar(M_PI_2));
817 m_joints[JOINT_PELVIS_SPINE] = hingeC;
818 m_ownerWorld->addConstraint(m_joints[JOINT_PELVIS_SPINE], true);
821 localA.setIdentity(); localB.setIdentity();
822 localA.getBasis().setEulerZYX(0,0,M_PI_2); localA.setOrigin(scale*btVector3(btScalar(0.), btScalar(0.30), btScalar(0.)));
823 localB.getBasis().setEulerZYX(0,0,M_PI_2); localB.setOrigin(scale*btVector3(btScalar(0.), btScalar(-0.14), btScalar(0.)));
824 coneC = new btConeTwistConstraint(*m_bodies[BODYPART_SPINE], *m_bodies[BODYPART_HEAD], localA, localB);
825 coneC->setLimit(M_PI_4, M_PI_4, M_PI_2);
826 m_joints[JOINT_SPINE_HEAD] = coneC;
827 m_ownerWorld->addConstraint(m_joints[JOINT_SPINE_HEAD], true);
830 localA.setIdentity(); localB.setIdentity();
831 localA.getBasis().setEulerZYX(0,0,-M_PI_4*5); localA.setOrigin(scale*btVector3(btScalar(-0.18), btScalar(-0.10), btScalar(0.)));
832 localB.getBasis().setEulerZYX(0,0,-M_PI_4*5); localB.setOrigin(scale*btVector3(btScalar(0.), btScalar(0.225), btScalar(0.)));
833 coneC = new btConeTwistConstraint(*m_bodies[BODYPART_PELVIS], *m_bodies[BODYPART_LEFT_UPPER_LEG], localA, localB);
834 coneC->setLimit(M_PI_4, M_PI_4, 0);
835 m_joints[JOINT_LEFT_HIP] = coneC;
836 m_ownerWorld->addConstraint(m_joints[JOINT_LEFT_HIP], true);
838 localA.setIdentity(); localB.setIdentity();
839 localA.getBasis().setEulerZYX(0,M_PI_2,0); localA.setOrigin(scale*btVector3(btScalar(0.), btScalar(-0.225), btScalar(0.)));
840 localB.getBasis().setEulerZYX(0,M_PI_2,0); localB.setOrigin(scale*btVector3(btScalar(0.), btScalar(0.185), btScalar(0.)));
841 hingeC = new btHingeConstraint(*m_bodies[BODYPART_LEFT_UPPER_LEG], *m_bodies[BODYPART_LEFT_LOWER_LEG], localA, localB);
842 hingeC->setLimit(btScalar(0), btScalar(M_PI_2));
843 m_joints[JOINT_LEFT_KNEE] = hingeC;
844 m_ownerWorld->addConstraint(m_joints[JOINT_LEFT_KNEE], true);
847 localA.setIdentity(); localB.setIdentity();
848 localA.getBasis().setEulerZYX(0,0,M_PI_4); localA.setOrigin(scale*btVector3(btScalar(0.18), btScalar(-0.10), btScalar(0.)));
849 localB.getBasis().setEulerZYX(0,0,M_PI_4); localB.setOrigin(scale*btVector3(btScalar(0.), btScalar(0.225), btScalar(0.)));
850 coneC = new btConeTwistConstraint(*m_bodies[BODYPART_PELVIS], *m_bodies[BODYPART_RIGHT_UPPER_LEG], localA, localB);
851 coneC->setLimit(M_PI_4, M_PI_4, 0);
852 m_joints[JOINT_RIGHT_HIP] = coneC;
853 m_ownerWorld->addConstraint(m_joints[JOINT_RIGHT_HIP], true);
855 localA.setIdentity(); localB.setIdentity();
856 localA.getBasis().setEulerZYX(0,M_PI_2,0); localA.setOrigin(scale*btVector3(btScalar(0.), btScalar(-0.225), btScalar(0.)));
857 localB.getBasis().setEulerZYX(0,M_PI_2,0); localB.setOrigin(scale*btVector3(btScalar(0.), btScalar(0.185), btScalar(0.)));
858 hingeC = new btHingeConstraint(*m_bodies[BODYPART_RIGHT_UPPER_LEG], *m_bodies[BODYPART_RIGHT_LOWER_LEG], localA, localB);
859 hingeC->setLimit(btScalar(0), btScalar(M_PI_2));
860 m_joints[JOINT_RIGHT_KNEE] = hingeC;
861 m_ownerWorld->addConstraint(m_joints[JOINT_RIGHT_KNEE], true);
864 localA.setIdentity(); localB.setIdentity();
865 localA.getBasis().setEulerZYX(0,0,M_PI); localA.setOrigin(scale*btVector3(btScalar(-0.2), btScalar(0.15), btScalar(0.)));
866 localB.getBasis().setEulerZYX(0,0,M_PI_2); localB.setOrigin(scale*btVector3(btScalar(0.), btScalar(-0.18), btScalar(0.)));
867 coneC = new btConeTwistConstraint(*m_bodies[BODYPART_SPINE], *m_bodies[BODYPART_LEFT_UPPER_ARM], localA, localB);
868 coneC->setLimit(M_PI_2, M_PI_2, 0);
869 m_joints[JOINT_LEFT_SHOULDER] = coneC;
870 m_ownerWorld->addConstraint(m_joints[JOINT_LEFT_SHOULDER], true);
872 localA.setIdentity(); localB.setIdentity();
873 localA.getBasis().setEulerZYX(0,M_PI_2,0); localA.setOrigin(scale*btVector3(btScalar(0.), btScalar(0.18), btScalar(0.)));
874 localB.getBasis().setEulerZYX(0,M_PI_2,0); localB.setOrigin(scale*btVector3(btScalar(0.), btScalar(-0.14), btScalar(0.)));
875 hingeC = new btHingeConstraint(*m_bodies[BODYPART_LEFT_UPPER_ARM], *m_bodies[BODYPART_LEFT_LOWER_ARM], localA, localB);
876 hingeC->setLimit(btScalar(-M_PI_2), btScalar(0));
877 m_joints[JOINT_LEFT_ELBOW] = hingeC;
878 m_ownerWorld->addConstraint(m_joints[JOINT_LEFT_ELBOW], true);
882 localA.setIdentity(); localB.setIdentity();
883 localA.getBasis().setEulerZYX(0,0,0); localA.setOrigin(scale*btVector3(btScalar(0.2), btScalar(0.15), btScalar(0.)));
884 localB.getBasis().setEulerZYX(0,0,M_PI_2); localB.setOrigin(scale*btVector3(btScalar(0.), btScalar(-0.18), btScalar(0.)));
885 coneC = new btConeTwistConstraint(*m_bodies[BODYPART_SPINE], *m_bodies[BODYPART_RIGHT_UPPER_ARM], localA, localB);
886 coneC->setLimit(M_PI_2, M_PI_2, 0);
887 m_joints[JOINT_RIGHT_SHOULDER] = coneC;
888 m_ownerWorld->addConstraint(m_joints[JOINT_RIGHT_SHOULDER], true);
890 localA.setIdentity(); localB.setIdentity();
891 localA.getBasis().setEulerZYX(0,M_PI_2,0); localA.setOrigin(scale*btVector3(btScalar(0.), btScalar(0.18), btScalar(0.)));
892 localB.getBasis().setEulerZYX(0,M_PI_2,0); localB.setOrigin(scale*btVector3(btScalar(0.), btScalar(-0.14), btScalar(0.)));
893 hingeC = new btHingeConstraint(*m_bodies[BODYPART_RIGHT_UPPER_ARM], *m_bodies[BODYPART_RIGHT_LOWER_ARM], localA, localB);
894 hingeC->setLimit(btScalar(-M_PI_2), btScalar(0));
895 m_joints[JOINT_RIGHT_ELBOW] = hingeC;
896 m_ownerWorld->addConstraint(m_joints[JOINT_RIGHT_ELBOW], true);
903 // Remove all constraints
904 for ( i = 0; i < JOINT_COUNT; ++i)
906 m_ownerWorld->removeConstraint(m_joints[i]);
907 delete m_joints[i]; m_joints[i] = 0;
910 // Remove all bodies and shapes
911 for ( i = 0; i < BODYPART_COUNT; ++i)
913 m_ownerWorld->removeRigidBody(m_bodies[i]);
915 delete m_bodies[i]->getMotionState();
917 delete m_bodies[i]; m_bodies[i] = 0;
918 delete m_shapes[i]; m_shapes[i] = 0;
923 void BenchmarkDemo::createTest3()
925 setCameraDistance(btScalar(50.));
935 btVector3 pos(0.0f, sizeY, 0.0f);
937 float offset = -size * (sizeX * 6.0f) * 0.5f;
938 for(int i=0;i<size;i++) {
939 pos[0] = offset + (float)i * (sizeX * 6.0f);
941 RagDoll* ragDoll = new RagDoll (m_dynamicsWorld,pos,scale);
942 m_ragdolls.push_back(ragDoll);
946 pos[1] += (sizeY * 7.0f);
947 pos[2] -= sizeX * 2.0f;
952 void BenchmarkDemo::createTest4()
954 setCameraDistance(btScalar(50.));
957 const float cubeSize = 1.5f;
958 float spacing = cubeSize;
959 btVector3 pos(0.0f, cubeSize * 2, 0.0f);
960 float offset = -size * (cubeSize * 2.0f + spacing) * 0.5f;
962 btConvexHullShape* convexHullShape = new btConvexHullShape();
966 convexHullShape->setLocalScaling(btVector3(scaling,scaling,scaling));
968 for (int i=0;i<TaruVtxCount;i++)
970 btVector3 vtx(TaruVtx[i*3],TaruVtx[i*3+1],TaruVtx[i*3+2]);
971 convexHullShape->addPoint(vtx*btScalar(1./scaling));
974 //this will enable polyhedral contact clipping, better quality, slightly slower
975 //convexHullShape->initializePolyhedralFeatures();
981 btVector3 localInertia(0,0,0);
982 convexHullShape->calculateLocalInertia(mass,localInertia);
984 for(int k=0;k<15;k++) {
985 for(int j=0;j<size;j++) {
986 pos[2] = offset + (float)j * (cubeSize * 2.0f + spacing);
987 for(int i=0;i<size;i++) {
988 pos[0] = offset + (float)i * (cubeSize * 2.0f + spacing);
989 trans.setOrigin(pos);
990 localCreateRigidBody(mass,trans,convexHullShape);
993 offset -= 0.05f * spacing * (size-1);
995 pos[1] += (cubeSize * 2.0f + spacing);
1000 ///////////////////////////////////////////////////////////////////////////////
1003 int LandscapeVtxCount[] = {
1004 Landscape01VtxCount,
1005 Landscape02VtxCount,
1006 Landscape03VtxCount,
1007 Landscape04VtxCount,
1008 Landscape05VtxCount,
1009 Landscape06VtxCount,
1010 Landscape07VtxCount,
1011 Landscape08VtxCount,
1014 int LandscapeIdxCount[] = {
1015 Landscape01IdxCount,
1016 Landscape02IdxCount,
1017 Landscape03IdxCount,
1018 Landscape04IdxCount,
1019 Landscape05IdxCount,
1020 Landscape06IdxCount,
1021 Landscape07IdxCount,
1022 Landscape08IdxCount,
1025 btScalar *LandscapeVtx[] = {
1036 btScalar *LandscapeNml[] = {
1047 btScalar* LandscapeTex[] = {
1058 unsigned short *LandscapeIdx[] = {
1069 void BenchmarkDemo::createLargeMeshBody()
1072 trans.setIdentity();
1074 for(int i=0;i<8;i++) {
1076 btTriangleIndexVertexArray* meshInterface = new btTriangleIndexVertexArray();
1079 part.m_vertexBase = (const unsigned char*)LandscapeVtx[i];
1080 part.m_vertexStride = sizeof(btScalar) * 3;
1081 part.m_numVertices = LandscapeVtxCount[i];
1082 part.m_triangleIndexBase = (const unsigned char*)LandscapeIdx[i];
1083 part.m_triangleIndexStride = sizeof( short) * 3;
1084 part.m_numTriangles = LandscapeIdxCount[i]/3;
1085 part.m_indexType = PHY_SHORT;
1087 meshInterface->addIndexedMesh(part,PHY_SHORT);
1089 bool useQuantizedAabbCompression = true;
1090 btBvhTriangleMeshShape* trimeshShape = new btBvhTriangleMeshShape(meshInterface,useQuantizedAabbCompression);
1091 btVector3 localInertia(0,0,0);
1092 trans.setOrigin(btVector3(0,-25,0));
1094 btRigidBody* body = localCreateRigidBody(0,trans,trimeshShape);
1095 body->setFriction (btScalar(0.9));
1102 void BenchmarkDemo::createTest5()
1104 setCameraDistance(btScalar(250.));
1105 btVector3 boxSize(1.5f,1.5f,1.5f);
1106 float boxMass = 1.0f;
1107 float sphereRadius = 1.5f;
1108 float sphereMass = 1.0f;
1109 float capsuleHalf = 2.0f;
1110 float capsuleRadius = 1.0f;
1111 float capsuleMass = 1.0f;
1117 const float cubeSize = boxSize[0];
1118 float spacing = 2.0f;
1119 btVector3 pos(0.0f, 20.0f, 0.0f);
1120 float offset = -size * (cubeSize * 2.0f + spacing) * 0.5f;
1124 for(int k=0;k<height;k++) {
1125 for(int j=0;j<size;j++) {
1126 pos[2] = offset + (float)j * (cubeSize * 2.0f + spacing);
1127 for(int i=0;i<size;i++) {
1128 pos[0] = offset + (float)i * (cubeSize * 2.0f + spacing);
1129 btVector3 bpos = btVector3(0,25,0) + btVector3(5.0f,1.0f,5.0f)*pos;
1130 int idx = rand() % 9;
1132 trans.setIdentity();
1133 trans.setOrigin(bpos);
1136 case 0:case 1:case 2:
1138 float r = 0.5f * (idx+1);
1139 btBoxShape* boxShape = new btBoxShape(boxSize*r);
1140 localCreateRigidBody(boxMass*r,trans,boxShape);
1144 case 3:case 4:case 5:
1146 float r = 0.5f * (idx-3+1);
1147 btSphereShape* sphereShape = new btSphereShape(sphereRadius*r);
1148 localCreateRigidBody(sphereMass*r,trans,sphereShape);
1152 case 6:case 7:case 8:
1154 float r = 0.5f * (idx-6+1);
1155 btCapsuleShape* capsuleShape = new btCapsuleShape(capsuleRadius*r,capsuleHalf*r);
1156 localCreateRigidBody(capsuleMass*r,trans,capsuleShape);
1164 offset -= 0.05f * spacing * (size-1);
1166 pos[1] += (cubeSize * 2.0f + spacing);
1170 createLargeMeshBody();
1172 void BenchmarkDemo::createTest6()
1174 setCameraDistance(btScalar(250.));
1176 btVector3 boxSize(1.5f,1.5f,1.5f);
1178 btConvexHullShape* convexHullShape = new btConvexHullShape();
1180 for (int i=0;i<TaruVtxCount;i++)
1182 btVector3 vtx(TaruVtx[i*3],TaruVtx[i*3+1],TaruVtx[i*3+2]);
1183 convexHullShape->addPoint(vtx);
1187 trans.setIdentity();
1190 btVector3 localInertia(0,0,0);
1191 convexHullShape->calculateLocalInertia(mass,localInertia);
1198 const float cubeSize = boxSize[0];
1199 float spacing = 2.0f;
1200 btVector3 pos(0.0f, 20.0f, 0.0f);
1201 float offset = -size * (cubeSize * 2.0f + spacing) * 0.5f;
1204 for(int k=0;k<height;k++) {
1205 for(int j=0;j<size;j++) {
1206 pos[2] = offset + (float)j * (cubeSize * 2.0f + spacing);
1207 for(int i=0;i<size;i++) {
1208 pos[0] = offset + (float)i * (cubeSize * 2.0f + spacing);
1209 btVector3 bpos = btVector3(0,25,0) + btVector3(5.0f,1.0f,5.0f)*pos;
1210 trans.setOrigin(bpos);
1212 localCreateRigidBody(mass,trans,convexHullShape);
1215 offset -= 0.05f * spacing * (size-1);
1217 pos[1] += (cubeSize * 2.0f + spacing);
1222 createLargeMeshBody();
1228 void BenchmarkDemo::initRays()
1230 raycastBar = btRaycastBar2 (2500.0, 0,50.0);
1233 void BenchmarkDemo::castRays()
1235 raycastBar.cast (m_dynamicsWorld);
1238 void BenchmarkDemo::createTest7()
1242 setCameraDistance(btScalar(150.));
1246 void BenchmarkDemo::exitPhysics()
1250 for (i=0;i<m_ragdolls.size();i++)
1252 RagDoll* doll = m_ragdolls[i];
1257 //cleanup in the reverse order of creation/initialization
1258 if (m_dynamicsWorld)
1260 //remove the rigidbodies from the dynamics world and delete them
1261 for (i=m_dynamicsWorld->getNumCollisionObjects()-1; i>=0 ;i--)
1263 btCollisionObject* obj = m_dynamicsWorld->getCollisionObjectArray()[i];
1264 btRigidBody* body = btRigidBody::upcast(obj);
1265 if (body && body->getMotionState())
1267 delete body->getMotionState();
1269 m_dynamicsWorld->removeCollisionObject( obj );
1274 //delete collision shapes
1275 for (int j=0;j<m_collisionShapes.size();j++)
1277 btCollisionShape* shape = m_collisionShapes[j];
1280 m_collisionShapes.clear();
1282 //delete dynamics world
1283 delete m_dynamicsWorld;
1291 delete m_overlappingPairCache;
1292 m_overlappingPairCache=0;
1295 delete m_dispatcher;
1298 delete m_collisionConfiguration;
1299 m_collisionConfiguration=0;
1306 #ifndef USE_GRAPHICAL_BENCHMARK
1308 btRigidBody* DemoApplication::localCreateRigidBody(float mass, const btTransform& startTransform,btCollisionShape* shape)
1310 btAssert((!shape || shape->getShapeType() != INVALID_SHAPE_PROXYTYPE));
1312 //rigidbody is dynamic if and only if mass is non zero, otherwise static
1313 bool isDynamic = (mass != 0.f);
1315 btVector3 localInertia(0,0,0);
1317 shape->calculateLocalInertia(mass,localInertia);
1319 //using motionstate is recommended, it provides interpolation capabilities, and only synchronizes 'active' objects
1321 btRigidBody* body = new btRigidBody(mass,0,shape,localInertia);
1322 body->setWorldTransform(startTransform);
1323 body->setContactProcessingThreshold(m_defaultContactProcessingThreshold);
1324 m_dynamicsWorld->addRigidBody(body);
1328 #endif //USE_GRAPHICAL_BENCHMARK