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.
16 #include "hacdCircularList.h"
17 #include "hacdVector.h"
18 #include "hacdICHull.h"
19 #include "hacdGraph.h"
22 #include "cd_wavefront.h"
23 #include "ConvexBuilder.h"
25 #include "btBulletDynamicsCommon.h"
27 #include "LinearMath/btQuickprof.h"
28 #include "LinearMath/btIDebugDraw.h"
29 #include "LinearMath/btGeometryUtil.h"
30 #include "BulletCollision/CollisionShapes/btShapeHull.h"
32 //#define TEST_SERIALIZATION
33 //#define NO_OBJ_TO_BULLET
35 #ifdef TEST_SERIALIZATION
36 #include "LinearMath/btSerializer.h"
37 #include "btBulletFile.h"
38 #include "btBulletWorldImporter.h"
41 //#define USE_PARALLEL_DISPATCHER 1
42 #ifdef USE_PARALLEL_DISPATCHER
43 #include "../../Extras/BulletMultiThreaded/SpuGatheringCollisionDispatcher.h"
44 #include "../../Extras/BulletMultiThreaded/Win32ThreadSupport.h"
45 #include "../../Extras/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuGatheringCollisionTask.h"
46 #endif//USE_PARALLEL_DISPATCHER
52 #include "GLDebugFont.h"
53 #include <stdio.h> //printf debugging
56 #include "ConvexDecompositionDemo.h"
57 #include "GL_ShapeDrawer.h"
59 #include "GlutStuff.h"
62 btVector3 centroid=btVector3(0,0,0);
63 btVector3 convexDecompositionObjectOffset(10,0,0);
65 #define CUBE_HALF_EXTENTS 4
68 ////////////////////////////////////
70 unsigned int tcount = 0;
73 void ConvexDecompositionDemo::initPhysics()
75 initPhysics("file.obj");
80 ///MyContactCallback is just an example to show how to get access to the child shape that collided
81 bool MyContactCallback (
83 const btCollisionObjectWrapper* colObj0Wrap,
86 const btCollisionObjectWrapper* colObj1Wrap,
91 if (colObj0Wrap->getCollisionObject()->getCollisionShape()->getShapeType()==COMPOUND_SHAPE_PROXYTYPE)
93 btCompoundShape* compound = (btCompoundShape*)colObj0Wrap->getCollisionObject()->getCollisionShape();
94 btCollisionShape* childShape;
95 childShape = compound->getChildShape(index0);
98 if (colObj1Wrap->getCollisionObject()->getCollisionShape()->getShapeType()==COMPOUND_SHAPE_PROXYTYPE)
100 btCompoundShape* compound = (btCompoundShape*)colObj1Wrap->getCollisionObject()->getCollisionShape();
101 btCollisionShape* childShape;
102 childShape = compound->getChildShape(index1);
109 void ConvexDecompositionDemo::setupEmptyDynamicsWorld()
111 m_collisionConfiguration = new btDefaultCollisionConfiguration();
113 #ifdef USE_PARALLEL_DISPATCHER
114 #ifdef USE_WIN32_THREADING
116 int maxNumOutstandingTasks = 4;//number of maximum outstanding tasks
117 Win32ThreadSupport* threadSupport = new Win32ThreadSupport(Win32ThreadSupport::Win32ThreadConstructionInfo(
119 processCollisionTask,
120 createCollisionLocalStoreMemory,
121 maxNumOutstandingTasks));
123 ///@todo other platform threading
124 ///Playstation 3 SPU (SPURS) version is available through PS3 Devnet
125 ///Libspe2 SPU support will be available soon
127 ///you can hook it up to your custom task scheduler by deriving from btThreadSupportInterface
130 m_dispatcher = new SpuGatheringCollisionDispatcher(threadSupport,maxNumOutstandingTasks,m_collisionConfiguration);
132 m_dispatcher = new btCollisionDispatcher(m_collisionConfiguration);
133 #endif//USE_PARALLEL_DISPATCHER
136 convexDecompositionObjectOffset.setValue(10,0,0);
138 btVector3 worldAabbMin(-10000,-10000,-10000);
139 btVector3 worldAabbMax(10000,10000,10000);
141 m_broadphase = new btAxisSweep3(worldAabbMin,worldAabbMax);
142 //m_broadphase = new btSimpleBroadphase();
144 m_solver = new btSequentialImpulseConstraintSolver();
145 m_dynamicsWorld = new btDiscreteDynamicsWorld(m_dispatcher,m_broadphase,m_solver,m_collisionConfiguration);
147 #ifdef USE_PARALLEL_DISPATCHER
148 m_dynamicsWorld->getDispatchInfo().m_enableSPU = true;
149 #endif //USE_PARALLEL_DISPATCHER
153 void ConvexDecompositionDemo::initPhysics(const char* filename)
157 gContactAddedCallback = &MyContactCallback;
159 setupEmptyDynamicsWorld();
164 setCameraDistance(26.f);
167 #ifndef NO_OBJ_TO_BULLET
169 ConvexDecomposition::WavefrontObj wo;
171 tcount = wo.loadObj(filename);
175 //when running this app from visual studio, the default starting folder is different, so make a second attempt...
176 tcount = wo.loadObj("../../file.obj");
180 //cmake generated msvc files need 4 levels deep back... so make a 3rd attempt...
181 tcount = wo.loadObj("../../../../file.obj");
188 btTransform startTransform;
189 startTransform.setIdentity();
190 startTransform.setOrigin(btVector3(0,-4.5,0));
192 btCollisionShape* boxShape = new btBoxShape(btVector3(30,2,30));
193 m_collisionShapes.push_back(boxShape);
194 localCreateRigidBody(0.f,startTransform,boxShape);
196 class MyConvexDecomposition : public ConvexDecomposition::ConvexDecompInterface
198 ConvexDecompositionDemo* m_convexDemo;
202 btAlignedObjectArray<btConvexHullShape*> m_convexShapes;
203 btAlignedObjectArray<btVector3> m_convexCentroids;
205 MyConvexDecomposition (FILE* outputFile,ConvexDecompositionDemo* demo)
209 mOutputFile(outputFile)
214 virtual void ConvexDecompResult(ConvexDecomposition::ConvexResult &result)
217 btTriangleMesh* trimesh = new btTriangleMesh();
218 m_convexDemo->m_trimeshes.push_back(trimesh);
220 btVector3 localScaling(6.f,6.f,6.f);
222 //export data to .obj
223 printf("ConvexResult. ");
226 fprintf(mOutputFile,"## Hull Piece %d with %d vertices and %d triangles.\r\n", mHullCount, result.mHullVcount, result.mHullTcount );
228 fprintf(mOutputFile,"usemtl Material%i\r\n",mBaseCount);
229 fprintf(mOutputFile,"o Object%i\r\n",mBaseCount);
231 for (unsigned int i=0; i<result.mHullVcount; i++)
233 const float *p = &result.mHullVertices[i*3];
234 fprintf(mOutputFile,"v %0.9f %0.9f %0.9f\r\n", p[0], p[1], p[2] );
237 //calc centroid, to shift vertices around center of mass
238 centroid.setValue(0,0,0);
240 btAlignedObjectArray<btVector3> vertices;
243 //const unsigned int *src = result.mHullIndices;
244 for (unsigned int i=0; i<result.mHullVcount; i++)
246 btVector3 vertex(result.mHullVertices[i*3],result.mHullVertices[i*3+1],result.mHullVertices[i*3+2]);
247 vertex *= localScaling;
253 centroid *= 1.f/(float(result.mHullVcount) );
257 //const unsigned int *src = result.mHullIndices;
258 for (unsigned int i=0; i<result.mHullVcount; i++)
260 btVector3 vertex(result.mHullVertices[i*3],result.mHullVertices[i*3+1],result.mHullVertices[i*3+2]);
261 vertex *= localScaling;
263 vertices.push_back(vertex);
271 const unsigned int *src = result.mHullIndices;
272 for (unsigned int i=0; i<result.mHullTcount; i++)
274 unsigned int index0 = *src++;
275 unsigned int index1 = *src++;
276 unsigned int index2 = *src++;
279 btVector3 vertex0(result.mHullVertices[index0*3], result.mHullVertices[index0*3+1],result.mHullVertices[index0*3+2]);
280 btVector3 vertex1(result.mHullVertices[index1*3], result.mHullVertices[index1*3+1],result.mHullVertices[index1*3+2]);
281 btVector3 vertex2(result.mHullVertices[index2*3], result.mHullVertices[index2*3+1],result.mHullVertices[index2*3+2]);
282 vertex0 *= localScaling;
283 vertex1 *= localScaling;
284 vertex2 *= localScaling;
291 trimesh->addTriangle(vertex0,vertex1,vertex2);
297 fprintf(mOutputFile,"f %d %d %d\r\n", index0+1, index1+1, index2+1 );
304 //this is a tools issue: due to collision margin, convex objects overlap, compensate for it here:
305 //#define SHRINK_OBJECT_INWARDS 1
306 #ifdef SHRINK_OBJECT_INWARDS
308 float collisionMargin = 0.01f;
310 btAlignedObjectArray<btVector3> planeEquations;
311 btGeometryUtil::getPlaneEquationsFromVertices(vertices,planeEquations);
313 btAlignedObjectArray<btVector3> shiftedPlaneEquations;
314 for (int p=0;p<planeEquations.size();p++)
316 btVector3 plane = planeEquations[p];
317 plane[3] += collisionMargin;
318 shiftedPlaneEquations.push_back(plane);
320 btAlignedObjectArray<btVector3> shiftedVertices;
321 btGeometryUtil::getVerticesFromPlaneEquations(shiftedPlaneEquations,shiftedVertices);
324 btConvexHullShape* convexShape = new btConvexHullShape(&(shiftedVertices[0].getX()),shiftedVertices.size());
326 #else //SHRINK_OBJECT_INWARDS
328 btConvexHullShape* convexShape = new btConvexHullShape(&(vertices[0].getX()),vertices.size());
331 convexShape->setMargin(0.01f);
332 m_convexShapes.push_back(convexShape);
333 m_convexCentroids.push_back(centroid);
334 m_convexDemo->m_collisionShapes.push_back(convexShape);
335 mBaseCount+=result.mHullVcount; // advance the 'base index' counter.
349 btTriangleMesh* trimesh = new btTriangleMesh();
350 m_trimeshes.push_back(trimesh);
352 btVector3 localScaling(6.f,6.f,6.f);
355 for ( i=0;i<wo.mTriCount;i++)
357 int index0 = wo.mIndices[i*3];
358 int index1 = wo.mIndices[i*3+1];
359 int index2 = wo.mIndices[i*3+2];
361 btVector3 vertex0(wo.mVertices[index0*3], wo.mVertices[index0*3+1],wo.mVertices[index0*3+2]);
362 btVector3 vertex1(wo.mVertices[index1*3], wo.mVertices[index1*3+1],wo.mVertices[index1*3+2]);
363 btVector3 vertex2(wo.mVertices[index2*3], wo.mVertices[index2*3+1],wo.mVertices[index2*3+2]);
365 vertex0 *= localScaling;
366 vertex1 *= localScaling;
367 vertex2 *= localScaling;
369 trimesh->addTriangle(vertex0,vertex1,vertex2);
373 btConvexShape* tmpConvexShape = new btConvexTriangleMeshShape(trimesh);
375 printf("old numTriangles= %d\n",wo.mTriCount);
376 printf("old numIndices = %d\n",wo.mTriCount*3);
377 printf("old numVertices = %d\n",wo.mVertexCount);
379 printf("reducing vertices by creating a convex hull\n");
381 //create a hull approximation
382 btShapeHull* hull = new btShapeHull(tmpConvexShape);
383 btScalar margin = tmpConvexShape->getMargin();
384 hull->buildHull(margin);
385 tmpConvexShape->setUserPointer(hull);
388 printf("new numTriangles = %d\n", hull->numTriangles ());
389 printf("new numIndices = %d\n", hull->numIndices ());
390 printf("new numVertices = %d\n", hull->numVertices ());
392 btConvexHullShape* convexShape = new btConvexHullShape();
393 for (i=0;i<hull->numVertices();i++)
395 convexShape->addPoint(hull->getVertexPointer()[i]);
398 delete tmpConvexShape;
403 m_collisionShapes.push_back(convexShape);
407 btTransform startTransform;
408 startTransform.setIdentity();
409 startTransform.setOrigin(btVector3(0,2,14));
411 localCreateRigidBody(mass, startTransform,convexShape);
413 bool useQuantization = true;
414 btCollisionShape* concaveShape = new btBvhTriangleMeshShape(trimesh,useQuantization);
415 startTransform.setOrigin(convexDecompositionObjectOffset);
416 localCreateRigidBody(0.f,startTransform,concaveShape);
418 m_collisionShapes.push_back (concaveShape);
425 //-----------------------------------
426 // Bullet Convex Decomposition
427 //-----------------------------------
429 char outputFileName[512];
430 strcpy(outputFileName,filename);
431 char *dot = strstr(outputFileName,".");
434 strcat(outputFileName,"_convex.obj");
435 FILE* outputFile = fopen(outputFileName,"wb");
437 unsigned int depth = 5;
440 unsigned int maxv = 16;
441 float skinWidth = 0.0;
443 printf("WavefrontObj num triangles read %i\n",tcount);
444 ConvexDecomposition::DecompDesc desc;
445 desc.mVcount = wo.mVertexCount;
446 desc.mVertices = wo.mVertices;
447 desc.mTcount = wo.mTriCount;
448 desc.mIndices = (unsigned int *)wo.mIndices;
450 desc.mCpercent = cpercent;
451 desc.mPpercent = ppercent;
452 desc.mMaxVertices = maxv;
453 desc.mSkinWidth = skinWidth;
455 MyConvexDecomposition convexDecomposition(outputFile,this);
456 desc.mCallback = &convexDecomposition;
459 //-----------------------------------------------
461 //-----------------------------------------------
463 std::vector< HACD::Vec3<HACD::Real> > points;
464 std::vector< HACD::Vec3<long> > triangles;
466 for(int i=0; i<wo.mVertexCount; i++ )
469 HACD::Vec3<HACD::Real> vertex(wo.mVertices[index], wo.mVertices[index+1],wo.mVertices[index+2]);
470 points.push_back(vertex);
473 for(int i=0;i<wo.mTriCount;i++)
476 HACD::Vec3<long> triangle(wo.mIndices[index], wo.mIndices[index+1], wo.mIndices[index+2]);
477 triangles.push_back(triangle);
482 myHACD.SetPoints(&points[0]);
483 myHACD.SetNPoints(points.size());
484 myHACD.SetTriangles(&triangles[0]);
485 myHACD.SetNTriangles(triangles.size());
486 myHACD.SetCompacityWeight(0.1);
487 myHACD.SetVolumeWeight(0.0);
490 // Recommended parameters: 2 100 0 0 0 0
491 size_t nClusters = 2;
492 double concavity = 100;
494 bool addExtraDistPoints = false;
495 bool addNeighboursDistPoints = false;
496 bool addFacesPoints = false;
498 myHACD.SetNClusters(nClusters); // minimum number of clusters
499 myHACD.SetNVerticesPerCH(100); // max of 100 vertices per convex-hull
500 myHACD.SetConcavity(concavity); // maximum concavity
501 myHACD.SetAddExtraDistPoints(addExtraDistPoints);
502 myHACD.SetAddNeighboursDistPoints(addNeighboursDistPoints);
503 myHACD.SetAddFacesPoints(addFacesPoints);
506 nClusters = myHACD.GetNClusters();
508 myHACD.Save("output.wrl", false);
511 //convexDecomposition.performConvexDecomposition(desc);
513 // ConvexBuilder cb(desc.mCallback);
515 //now create some bodies
519 btCompoundShape* compound = new btCompoundShape();
520 m_collisionShapes.push_back (compound);
525 for (int c=0;c<nClusters;c++)
527 //generate convex result
528 size_t nPoints = myHACD.GetNPointsCH(c);
529 size_t nTriangles = myHACD.GetNTrianglesCH(c);
531 float* vertices = new float[nPoints*3];
532 unsigned int* triangles = new unsigned int[nTriangles*3];
534 HACD::Vec3<HACD::Real> * pointsCH = new HACD::Vec3<HACD::Real>[nPoints];
535 HACD::Vec3<long> * trianglesCH = new HACD::Vec3<long>[nTriangles];
536 myHACD.GetCH(c, pointsCH, trianglesCH);
539 for(size_t v = 0; v < nPoints; v++)
541 vertices[3*v] = pointsCH[v].X();
542 vertices[3*v+1] = pointsCH[v].Y();
543 vertices[3*v+2] = pointsCH[v].Z();
546 for(size_t f = 0; f < nTriangles; f++)
548 triangles[3*f] = trianglesCH[f].X();
549 triangles[3*f+1] = trianglesCH[f].Y();
550 triangles[3*f+2] = trianglesCH[f].Z();
554 delete [] trianglesCH;
556 ConvexResult r(nPoints, vertices, nTriangles, triangles);
557 convexDecomposition.ConvexDecompResult(r);
560 for (int i=0;i<convexDecomposition.m_convexShapes.size();i++)
562 btVector3 centroid = convexDecomposition.m_convexCentroids[i];
563 trans.setOrigin(centroid);
564 btConvexHullShape* convexShape = convexDecomposition.m_convexShapes[i];
565 compound->addChildShape(trans,convexShape);
568 body = localCreateRigidBody( 1.0, trans,convexShape);
570 /* for (int i=0;i<convexDecomposition.m_convexShapes.size();i++)
573 btVector3 centroid = convexDecomposition.m_convexCentroids[i];
574 trans.setOrigin(centroid);
575 btConvexHullShape* convexShape = convexDecomposition.m_convexShapes[i];
576 compound->addChildShape(trans,convexShape);
579 body = localCreateRigidBody( 1.0, trans,convexShape);
584 trans.setOrigin(-convexDecompositionObjectOffset);
585 btRigidBody* body = localCreateRigidBody( mass, trans,compound);
586 body->setCollisionFlags(body->getCollisionFlags() | btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK);
588 convexDecompositionObjectOffset.setZ(6);
589 trans.setOrigin(-convexDecompositionObjectOffset);
590 body = localCreateRigidBody( mass, trans,compound);
591 body->setCollisionFlags(body->getCollisionFlags() | btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK);
593 convexDecompositionObjectOffset.setZ(-6);
594 trans.setOrigin(-convexDecompositionObjectOffset);
595 body = localCreateRigidBody( mass, trans,compound);
596 body->setCollisionFlags(body->getCollisionFlags() | btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK);
609 #ifdef TEST_SERIALIZATION
610 //test serializing this
612 int maxSerializeBufferSize = 1024*1024*5;
614 btDefaultSerializer* serializer = new btDefaultSerializer(maxSerializeBufferSize);
615 m_dynamicsWorld->serialize(serializer);
617 FILE* f2 = fopen("testFile.bullet","wb");
618 fwrite(serializer->getBufferPointer(),serializer->getCurrentBufferSize(),1,f2);
623 //now try again from the loaded file
624 setupEmptyDynamicsWorld();
625 #endif //TEST_SERIALIZATION
627 #endif //NO_OBJ_TO_BULLET
629 #ifdef TEST_SERIALIZATION
631 btBulletWorldImporter* fileLoader = new btBulletWorldImporter(m_dynamicsWorld);
632 //fileLoader->setVerboseMode(true);
634 fileLoader->loadFile("testFile.bullet");
635 //fileLoader->loadFile("testFile64Double.bullet");
636 //fileLoader->loadFile("testFile64Single.bullet");
637 //fileLoader->loadFile("testFile32Single.bullet");
642 #endif //TEST_SERIALIZATION
646 void ConvexDecompositionDemo::clientMoveAndDisplay()
648 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
650 float dt = getDeltaTimeMicroseconds() * 0.000001f;
652 m_dynamicsWorld->stepSimulation(dt);
654 //optional but useful: debug drawing
655 m_dynamicsWorld->debugDrawWorld();
666 void ConvexDecompositionDemo::displayCallback(void) {
668 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
672 m_dynamicsWorld->debugDrawWorld();
684 void ConvexDecompositionDemo::exitPhysics()
688 //cleanup in the reverse order of creation/initialization
690 //remove the rigidbodies from the dynamics world and delete them
692 for (i=m_dynamicsWorld->getNumCollisionObjects()-1; i>=0 ;i--)
694 btCollisionObject* obj = m_dynamicsWorld->getCollisionObjectArray()[i];
695 btRigidBody* body = btRigidBody::upcast(obj);
696 if (body && body->getMotionState())
698 delete body->getMotionState();
700 m_dynamicsWorld->removeCollisionObject( obj );
704 //delete collision shapes
705 for (i=0;i<m_collisionShapes.size();i++)
707 btCollisionShape* shape = m_collisionShapes[i];
711 m_collisionShapes.clear();
713 for (i=0;i<m_trimeshes.size();i++)
715 btTriangleMesh* mesh = m_trimeshes[i];
722 //delete dynamics world
723 delete m_dynamicsWorld;
734 delete m_collisionConfiguration;