void ConvexDecompositionDemo::initPhysics(const char* filename) { gContactAddedCallback = &MyContactCallback; setupEmptyDynamicsWorld(); getDynamicsWorld()->setDebugDrawer(&gDebugDrawer); setTexturing(true); setShadows(true); setCameraDistance(26.f); #ifndef NO_OBJ_TO_BULLET ConvexDecomposition::WavefrontObj wo; tcount = 0; const char* prefix[]={"./","../","../../","../../../","../../../../", "ConvexDecompositionDemo/", "Demos/ConvexDecompositionDemo/", "../Demos/ConvexDecompositionDemo/","../../Demos/ConvexDecompositionDemo/"}; int numPrefixes = sizeof(prefix)/sizeof(const char*); char relativeFileName[1024]; for (int i=0;i<numPrefixes;i++) { sprintf(relativeFileName,"%s%s",prefix[i],filename); tcount = wo.loadObj(relativeFileName); if (tcount) break; } btTransform startTransform; startTransform.setIdentity(); startTransform.setOrigin(btVector3(0,-4.5,0)); btCollisionShape* boxShape = new btBoxShape(btVector3(30,2,30)); m_collisionShapes.push_back(boxShape); localCreateRigidBody(0.f,startTransform,boxShape); class MyConvexDecomposition : public ConvexDecomposition::ConvexDecompInterface { ConvexDecompositionDemo* m_convexDemo; public: btAlignedObjectArray<btConvexHullShape*> m_convexShapes; btAlignedObjectArray<btVector3> m_convexCentroids; MyConvexDecomposition (FILE* outputFile,ConvexDecompositionDemo* demo) :m_convexDemo(demo), mBaseCount(0), mHullCount(0), mOutputFile(outputFile) { } virtual void ConvexDecompResult(ConvexDecomposition::ConvexResult &result) { btTriangleMesh* trimesh = new btTriangleMesh(); m_convexDemo->m_trimeshes.push_back(trimesh); btVector3 localScaling(6.f,6.f,6.f); //export data to .obj printf("ConvexResult. "); if (mOutputFile) { fprintf(mOutputFile,"## Hull Piece %d with %d vertices and %d triangles.\r\n", mHullCount, result.mHullVcount, result.mHullTcount ); fprintf(mOutputFile,"usemtl Material%i\r\n",mBaseCount); fprintf(mOutputFile,"o Object%i\r\n",mBaseCount); for (unsigned int i=0; i<result.mHullVcount; i++) { const float *p = &result.mHullVertices[i*3]; fprintf(mOutputFile,"v %0.9f %0.9f %0.9f\r\n", p[0], p[1], p[2] ); } //calc centroid, to shift vertices around center of mass centroid.setValue(0,0,0); btAlignedObjectArray<btVector3> vertices; if ( 1 ) { //const unsigned int *src = result.mHullIndices; for (unsigned int i=0; i<result.mHullVcount; i++) { btVector3 vertex(result.mHullVertices[i*3],result.mHullVertices[i*3+1],result.mHullVertices[i*3+2]); vertex *= localScaling; centroid += vertex; } } centroid *= 1.f/(float(result.mHullVcount) ); if ( 1 ) { //const unsigned int *src = result.mHullIndices; for (unsigned int i=0; i<result.mHullVcount; i++) { btVector3 vertex(result.mHullVertices[i*3],result.mHullVertices[i*3+1],result.mHullVertices[i*3+2]); vertex *= localScaling; vertex -= centroid ; vertices.push_back(vertex); } } if ( 1 ) { const unsigned int *src = result.mHullIndices; for (unsigned int i=0; i<result.mHullTcount; i++) { unsigned int index0 = *src++; unsigned int index1 = *src++; unsigned int index2 = *src++; btVector3 vertex0(result.mHullVertices[index0*3], result.mHullVertices[index0*3+1],result.mHullVertices[index0*3+2]); btVector3 vertex1(result.mHullVertices[index1*3], result.mHullVertices[index1*3+1],result.mHullVertices[index1*3+2]); btVector3 vertex2(result.mHullVertices[index2*3], result.mHullVertices[index2*3+1],result.mHullVertices[index2*3+2]); vertex0 *= localScaling; vertex1 *= localScaling; vertex2 *= localScaling; vertex0 -= centroid; vertex1 -= centroid; vertex2 -= centroid; trimesh->addTriangle(vertex0,vertex1,vertex2); index0+=mBaseCount; index1+=mBaseCount; index2+=mBaseCount; fprintf(mOutputFile,"f %d %d %d\r\n", index0+1, index1+1, index2+1 ); } } // float mass = 1.f; //this is a tools issue: due to collision margin, convex objects overlap, compensate for it here: //#define SHRINK_OBJECT_INWARDS 1 #ifdef SHRINK_OBJECT_INWARDS float collisionMargin = 0.01f; btAlignedObjectArray<btVector3> planeEquations; btGeometryUtil::getPlaneEquationsFromVertices(vertices,planeEquations); btAlignedObjectArray<btVector3> shiftedPlaneEquations; for (int p=0;p<planeEquations.size();p++) { btVector3 plane = planeEquations[p]; plane[3] += collisionMargin; shiftedPlaneEquations.push_back(plane); } btAlignedObjectArray<btVector3> shiftedVertices; btGeometryUtil::getVerticesFromPlaneEquations(shiftedPlaneEquations,shiftedVertices); btConvexHullShape* convexShape = new btConvexHullShape(&(shiftedVertices[0].getX()),shiftedVertices.size()); #else //SHRINK_OBJECT_INWARDS btConvexHullShape* convexShape = new btConvexHullShape(&(vertices[0].getX()),vertices.size()); #endif if (sEnableSAT) convexShape->initializePolyhedralFeatures(); convexShape->setMargin(0.01f); m_convexShapes.push_back(convexShape); m_convexCentroids.push_back(centroid); m_convexDemo->m_collisionShapes.push_back(convexShape); mBaseCount+=result.mHullVcount; // advance the 'base index' counter. } } int mBaseCount; int mHullCount; FILE* mOutputFile; }; if (tcount) { btTriangleMesh* trimesh = new btTriangleMesh(); m_trimeshes.push_back(trimesh); btVector3 localScaling(6.f,6.f,6.f); int i; for ( i=0;i<wo.mTriCount;i++) { int index0 = wo.mIndices[i*3]; int index1 = wo.mIndices[i*3+1]; int index2 = wo.mIndices[i*3+2]; btVector3 vertex0(wo.mVertices[index0*3], wo.mVertices[index0*3+1],wo.mVertices[index0*3+2]); btVector3 vertex1(wo.mVertices[index1*3], wo.mVertices[index1*3+1],wo.mVertices[index1*3+2]); btVector3 vertex2(wo.mVertices[index2*3], wo.mVertices[index2*3+1],wo.mVertices[index2*3+2]); vertex0 *= localScaling; vertex1 *= localScaling; vertex2 *= localScaling; trimesh->addTriangle(vertex0,vertex1,vertex2); } btConvexShape* tmpConvexShape = new btConvexTriangleMeshShape(trimesh); printf("old numTriangles= %d\n",wo.mTriCount); printf("old numIndices = %d\n",wo.mTriCount*3); printf("old numVertices = %d\n",wo.mVertexCount); printf("reducing vertices by creating a convex hull\n"); //create a hull approximation btShapeHull* hull = new btShapeHull(tmpConvexShape); btScalar margin = tmpConvexShape->getMargin(); hull->buildHull(margin); tmpConvexShape->setUserPointer(hull); printf("new numTriangles = %d\n", hull->numTriangles ()); printf("new numIndices = %d\n", hull->numIndices ()); printf("new numVertices = %d\n", hull->numVertices ()); btConvexHullShape* convexShape = new btConvexHullShape(); bool updateLocalAabb = false; for (i=0;i<hull->numVertices();i++) { convexShape->addPoint(hull->getVertexPointer()[i],updateLocalAabb); } convexShape->recalcLocalAabb(); if (sEnableSAT) convexShape->initializePolyhedralFeatures(); delete tmpConvexShape; delete hull; m_collisionShapes.push_back(convexShape); float mass = 1.f; btTransform startTransform; startTransform.setIdentity(); startTransform.setOrigin(btVector3(0,2,14)); localCreateRigidBody(mass, startTransform,convexShape); bool useQuantization = true; btCollisionShape* concaveShape = new btBvhTriangleMeshShape(trimesh,useQuantization); startTransform.setOrigin(convexDecompositionObjectOffset); localCreateRigidBody(0.f,startTransform,concaveShape); m_collisionShapes.push_back (concaveShape); } if (tcount) { //----------------------------------- // Bullet Convex Decomposition //----------------------------------- char outputFileName[512]; strcpy(outputFileName,filename); char *dot = strstr(outputFileName,"."); if ( dot ) *dot = 0; strcat(outputFileName,"_convex.obj"); FILE* outputFile = fopen(outputFileName,"wb"); unsigned int depth = 5; float cpercent = 5; float ppercent = 15; unsigned int maxv = 16; float skinWidth = 0.0; printf("WavefrontObj num triangles read %i\n",tcount); ConvexDecomposition::DecompDesc desc; desc.mVcount = wo.mVertexCount; desc.mVertices = wo.mVertices; desc.mTcount = wo.mTriCount; desc.mIndices = (unsigned int *)wo.mIndices; desc.mDepth = depth; desc.mCpercent = cpercent; desc.mPpercent = ppercent; desc.mMaxVertices = maxv; desc.mSkinWidth = skinWidth; MyConvexDecomposition convexDecomposition(outputFile,this); desc.mCallback = &convexDecomposition; //----------------------------------------------- // HACD //----------------------------------------------- std::vector< HACD::Vec3<HACD::Real> > points; std::vector< HACD::Vec3<long> > triangles; for(int i=0; i<wo.mVertexCount; i++ ) { int index = i*3; HACD::Vec3<HACD::Real> vertex(wo.mVertices[index], wo.mVertices[index+1],wo.mVertices[index+2]); points.push_back(vertex); } for(int i=0;i<wo.mTriCount;i++) { int index = i*3; HACD::Vec3<long> triangle(wo.mIndices[index], wo.mIndices[index+1], wo.mIndices[index+2]); triangles.push_back(triangle); } HACD::HACD myHACD; myHACD.SetPoints(&points[0]); myHACD.SetNPoints(points.size()); myHACD.SetTriangles(&triangles[0]); myHACD.SetNTriangles(triangles.size()); myHACD.SetCompacityWeight(0.1); myHACD.SetVolumeWeight(0.0); // HACD parameters // Recommended parameters: 2 100 0 0 0 0 size_t nClusters = 2; double concavity = 100; bool invert = false; bool addExtraDistPoints = false; bool addNeighboursDistPoints = false; bool addFacesPoints = false; myHACD.SetNClusters(nClusters); // minimum number of clusters myHACD.SetNVerticesPerCH(100); // max of 100 vertices per convex-hull myHACD.SetConcavity(concavity); // maximum concavity myHACD.SetAddExtraDistPoints(addExtraDistPoints); myHACD.SetAddNeighboursDistPoints(addNeighboursDistPoints); myHACD.SetAddFacesPoints(addFacesPoints); myHACD.Compute(); nClusters = myHACD.GetNClusters(); myHACD.Save("output.wrl", false); //convexDecomposition.performConvexDecomposition(desc); // ConvexBuilder cb(desc.mCallback); // cb.process(desc); //now create some bodies if (1) { btCompoundShape* compound = new btCompoundShape(); m_collisionShapes.push_back (compound); btTransform trans; trans.setIdentity(); for (int c=0;c<nClusters;c++) { //generate convex result size_t nPoints = myHACD.GetNPointsCH(c); size_t nTriangles = myHACD.GetNTrianglesCH(c); float* vertices = new float[nPoints*3]; unsigned int* triangles = new unsigned int[nTriangles*3]; HACD::Vec3<HACD::Real> * pointsCH = new HACD::Vec3<HACD::Real>[nPoints]; HACD::Vec3<long> * trianglesCH = new HACD::Vec3<long>[nTriangles]; myHACD.GetCH(c, pointsCH, trianglesCH); // points for(size_t v = 0; v < nPoints; v++) { vertices[3*v] = pointsCH[v].X(); vertices[3*v+1] = pointsCH[v].Y(); vertices[3*v+2] = pointsCH[v].Z(); } // triangles for(size_t f = 0; f < nTriangles; f++) { triangles[3*f] = trianglesCH[f].X(); triangles[3*f+1] = trianglesCH[f].Y(); triangles[3*f+2] = trianglesCH[f].Z(); } delete [] pointsCH; delete [] trianglesCH; ConvexResult r(nPoints, vertices, nTriangles, triangles); convexDecomposition.ConvexDecompResult(r); } for (int i=0;i<convexDecomposition.m_convexShapes.size();i++) { btVector3 centroid = convexDecomposition.m_convexCentroids[i]; trans.setOrigin(centroid); btConvexHullShape* convexShape = convexDecomposition.m_convexShapes[i]; compound->addChildShape(trans,convexShape); btRigidBody* body; body = localCreateRigidBody( 1.0, trans,convexShape); } /* for (int i=0;i<convexDecomposition.m_convexShapes.size();i++) { btVector3 centroid = convexDecomposition.m_convexCentroids[i]; trans.setOrigin(centroid); btConvexHullShape* convexShape = convexDecomposition.m_convexShapes[i]; compound->addChildShape(trans,convexShape); btRigidBody* body; body = localCreateRigidBody( 1.0, trans,convexShape); }*/ #if 1 btScalar mass=10.f; trans.setOrigin(-convexDecompositionObjectOffset); btRigidBody* body = localCreateRigidBody( mass, trans,compound); body->setCollisionFlags(body->getCollisionFlags() | btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK); convexDecompositionObjectOffset.setZ(6); trans.setOrigin(-convexDecompositionObjectOffset); body = localCreateRigidBody( mass, trans,compound); body->setCollisionFlags(body->getCollisionFlags() | btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK); convexDecompositionObjectOffset.setZ(-6); trans.setOrigin(-convexDecompositionObjectOffset); body = localCreateRigidBody( mass, trans,compound); body->setCollisionFlags(body->getCollisionFlags() | btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK); #endif } if (outputFile) fclose(outputFile); } #ifdef TEST_SERIALIZATION //test serializing this int maxSerializeBufferSize = 1024*1024*5; btDefaultSerializer* serializer = new btDefaultSerializer(maxSerializeBufferSize); m_dynamicsWorld->serialize(serializer); FILE* f2 = fopen("testFile.bullet","wb"); fwrite(serializer->getBufferPointer(),serializer->getCurrentBufferSize(),1,f2); fclose(f2); exitPhysics(); //now try again from the loaded file setupEmptyDynamicsWorld(); #endif //TEST_SERIALIZATION #endif //NO_OBJ_TO_BULLET #ifdef TEST_SERIALIZATION btBulletWorldImporter* fileLoader = new btBulletWorldImporter(m_dynamicsWorld); //fileLoader->setVerboseMode(true); fileLoader->loadFile("testFile.bullet"); //fileLoader->loadFile("testFile64Double.bullet"); //fileLoader->loadFile("testFile64Single.bullet"); //fileLoader->loadFile("testFile32Single.bullet"); #endif //TEST_SERIALIZATION }
void PhysicWorld::initGround(const char* filename) { ConvexDecomposition::WavefrontObj wo; btVector3 centroid=btVector3(0,0,0); btVector3 convexDecompositionObjectOffset(10,0,0); unsigned int tcount = wo.loadObj(filename); #ifdef USE_PARALLEL_DISPATCHER m_dynamicsWorld->getDispatchInfo().m_enableSPU = true; #endif //USE_PARALLEL_DISPATCHER class MyConvexDecomposition : public ConvexDecomposition::ConvexDecompInterface { PhysicWorld* world; btVector3 centroid; public: btAlignedObjectArray<btConvexHullShape*> m_convexShapes; btAlignedObjectArray<btVector3> m_convexCentroids; MyConvexDecomposition (FILE* outputFile,PhysicWorld* worldPhysic,btVector3& centre) :world(worldPhysic), mBaseCount(0), mHullCount(0), mOutputFile(outputFile), centroid(centre) { } virtual void ConvexDecompResult(ConvexDecomposition::ConvexResult &result) { btTriangleMesh* trimesh = new btTriangleMesh(); world->m_trimeshes.push_back(trimesh); btVector3 localScaling(6.f,6.f,6.f); //export data to .obj printf("ConvexResult. "); if (mOutputFile) { fprintf(mOutputFile,"## Hull Piece %d with %d vertices and %d triangles.\r\n", mHullCount, result.mHullVcount, result.mHullTcount ); fprintf(mOutputFile,"usemtl Material%i\r\n",mBaseCount); fprintf(mOutputFile,"o Object%i\r\n",mBaseCount); for (unsigned int i=0; i<result.mHullVcount; i++) { const float *p = &result.mHullVertices[i*3]; fprintf(mOutputFile,"v %0.9f %0.9f %0.9f\r\n", p[0], p[1], p[2] ); } //calc centroid, to shift vertices around center of mass centroid.setValue(0,0,0); btAlignedObjectArray<btVector3> vertices; if ( 1 ) { //const unsigned int *src = result.mHullIndices; for (unsigned int i=0; i<result.mHullVcount; i++) { btVector3 vertex(result.mHullVertices[i*3],result.mHullVertices[i*3+1],result.mHullVertices[i*3+2]); vertex *= localScaling; centroid += vertex; } } centroid *= 1.f/(float(result.mHullVcount) ); if ( 1 ) { //const unsigned int *src = result.mHullIndices; for (unsigned int i=0; i<result.mHullVcount; i++) { btVector3 vertex(result.mHullVertices[i*3],result.mHullVertices[i*3+1],result.mHullVertices[i*3+2]); vertex *= localScaling; vertex -= centroid ; vertices.push_back(vertex); } } if ( 1 ) { const unsigned int *src = result.mHullIndices; for (unsigned int i=0; i<result.mHullTcount; i++) { unsigned int index0 = *src++; unsigned int index1 = *src++; unsigned int index2 = *src++; btVector3 vertex0(result.mHullVertices[index0*3], result.mHullVertices[index0*3+1],result.mHullVertices[index0*3+2]); btVector3 vertex1(result.mHullVertices[index1*3], result.mHullVertices[index1*3+1],result.mHullVertices[index1*3+2]); btVector3 vertex2(result.mHullVertices[index2*3], result.mHullVertices[index2*3+1],result.mHullVertices[index2*3+2]); vertex0 *= localScaling; vertex1 *= localScaling; vertex2 *= localScaling; vertex0 -= centroid; vertex1 -= centroid; vertex2 -= centroid; trimesh->addTriangle(vertex0,vertex1,vertex2); index0+=mBaseCount; index1+=mBaseCount; index2+=mBaseCount; fprintf(mOutputFile,"f %d %d %d\r\n", index0+1, index1+1, index2+1 ); } } float mass = 1.f; //float collisionMargin = 0.01f; //this is a tools issue: due to collision margin, convex objects overlap, compensate for it here: //#define SHRINK_OBJECT_INWARDS 1 #ifdef SHRINK_OBJECT_INWARDS std::vector<btVector3> planeEquations; btGeometryUtil::getPlaneEquationsFromVertices(vertices,planeEquations); std::vector<btVector3> shiftedPlaneEquations; for (int p=0;p<planeEquations.size();p++) { btVector3 plane = planeEquations[p]; plane[3] += 5*collisionMargin; shiftedPlaneEquations.push_back(plane); } std::vector<btVector3> shiftedVertices; btGeometryUtil::getVerticesFromPlaneEquations(shiftedPlaneEquations,shiftedVertices); btConvexHullShape* convexShape = new btConvexHullShape(&(shiftedVertices[0].getX()),shiftedVertices.size()); #else //SHRINK_OBJECT_INWARDS btConvexHullShape* convexShape = new btConvexHullShape(&(vertices[0].getX()),vertices.size()); #endif convexShape->setMargin(btScalar(0.01)); m_convexShapes.push_back(convexShape); m_convexCentroids.push_back(centroid); world->m_collisionShapes.push_back(convexShape); mBaseCount+=result.mHullVcount; // advance the 'base index' counter. } } int mBaseCount; int mHullCount; FILE* mOutputFile; }; if (tcount) { btTriangleMesh* trimesh = new btTriangleMesh(); m_trimeshes.push_back(trimesh); btVector3 localScaling(1.f,1.f,1.f); int i; for ( i=0;i<wo.mTriCount;i++) { int index0 = wo.mIndices[i*3]; int index1 = wo.mIndices[i*3+1]; int index2 = wo.mIndices[i*3+2]; btVector3 vertex0(wo.mVertices[index0*3], wo.mVertices[index0*3+1],wo.mVertices[index0*3+2]); btVector3 vertex1(wo.mVertices[index1*3], wo.mVertices[index1*3+1],wo.mVertices[index1*3+2]); btVector3 vertex2(wo.mVertices[index2*3], wo.mVertices[index2*3+1],wo.mVertices[index2*3+2]); vertex0 *= localScaling; vertex1 *= localScaling; vertex2 *= localScaling; trimesh->addTriangle(vertex0,vertex1,vertex2); } btConvexShape* tmpConvexShape = new btConvexTriangleMeshShape(trimesh); printf("old numTriangles= %d\n",wo.mTriCount); printf("old numIndices = %d\n",wo.mTriCount*3); printf("old numVertices = %d\n",wo.mVertexCount); printf("reducing vertices by creating a convex hull\n"); //create a hull approximation btShapeHull* hull = new btShapeHull(tmpConvexShape); btScalar margin = tmpConvexShape->getMargin(); hull->buildHull(margin); tmpConvexShape->setUserPointer(hull); printf("new numTriangles = %d\n", hull->numTriangles ()); printf("new numIndices = %d\n", hull->numIndices ()); printf("new numVertices = %d\n", hull->numVertices ()); btConvexHullShape* convexShape = new btConvexHullShape(); for (i=0;i<hull->numVertices();i++) { convexShape->addPoint(hull->getVertexPointer()[i]); } delete tmpConvexShape; delete hull; m_collisionShapes.push_back(convexShape); float mass = 1.f; /* btTransform startTransform; startTransform.setIdentity(); startTransform.setOrigin(btVector3(0,2,0)); localCreateRigidBody(mass, startTransform,convexShape); bool useQuantization = true; btCollisionShape* concaveShape = new btBvhTriangleMeshShape(trimesh,useQuantization); startTransform.setOrigin(convexDecompositionObjectOffset); localCreateRigidBody(0.f,startTransform,concaveShape); m_collisionShapes.push_back (concaveShape); */ } if (tcount) { char outputFileName[512]; strcpy(outputFileName,filename); char *dot = strstr(outputFileName,"."); if ( dot ) *dot = 0; strcat(outputFileName,"_convex.obj"); FILE* outputFile = fopen(outputFileName,"wb"); unsigned int depth = 5; float cpercent = 5; float ppercent = 15; unsigned int maxv = 16; float skinWidth = 0.0; printf("WavefrontObj num triangles read %i\n",tcount); ConvexDecomposition::DecompDesc desc; desc.mVcount = wo.mVertexCount; desc.mVertices = wo.mVertices; desc.mTcount = wo.mTriCount; desc.mIndices = (unsigned int *)wo.mIndices; desc.mDepth = depth; desc.mCpercent = cpercent; desc.mPpercent = ppercent; desc.mMaxVertices = maxv; desc.mSkinWidth = skinWidth; MyConvexDecomposition convexDecomposition(outputFile,this,centroid); desc.mCallback = &convexDecomposition; //convexDecomposition.performConvexDecomposition(desc); ConvexBuilder cb(desc.mCallback); cb.process(desc); // creation d'un SOL { btCompoundShape* compound = new btCompoundShape(); m_collisionShapes.push_back (compound); btTransform trans; trans.setIdentity(); for (int i=0;i<convexDecomposition.m_convexShapes.size();i++) { btVector3 centroid2 = convexDecomposition.m_convexCentroids[i]; trans.setOrigin(centroid2); btConvexHullShape* convexShape = convexDecomposition.m_convexShapes[i]; compound->addChildShape(trans,convexShape); } trans.setOrigin(-convexDecompositionObjectOffset); btDefaultMotionState* myMotionState = new btDefaultMotionState(trans); btRigidBody::btRigidBodyConstructionInfo rbInfo(0,myMotionState,compound,btVector3(0,0,0)); m_ground = new btRigidBody(rbInfo); this->m_dynamicsWorld->addRigidBody(m_ground); // localCreateRigidBody( btScalar(0.F), trans,compound); } if (outputFile) fclose(outputFile); } }
void ConvexDecompositionDemo::initPhysics(const char* filename) { setTexturing(true); setShadows(true); setCameraDistance(26.f); ConvexDecomposition::WavefrontObj wo; tcount = wo.loadObj(filename); if (!tcount) { //when running this app from visual studio, the default starting folder is different, so make a second attempt... tcount = wo.loadObj("../../file.obj"); } m_collisionConfiguration = new btDefaultCollisionConfiguration(); #ifdef USE_PARALLEL_DISPATCHER #ifdef USE_WIN32_THREADING int maxNumOutstandingTasks = 4;//number of maximum outstanding tasks Win32ThreadSupport* threadSupport = new Win32ThreadSupport(Win32ThreadSupport::Win32ThreadConstructionInfo( "collision", processCollisionTask, createCollisionLocalStoreMemory, maxNumOutstandingTasks)); #else ///@todo other platform threading ///Playstation 3 SPU (SPURS) version is available through PS3 Devnet ///Libspe2 SPU support will be available soon ///pthreads version ///you can hook it up to your custom task scheduler by deriving from btThreadSupportInterface #endif m_dispatcher = new SpuGatheringCollisionDispatcher(threadSupport,maxNumOutstandingTasks,m_collisionConfiguration); #else m_dispatcher = new btCollisionDispatcher(m_collisionConfiguration); #endif//USE_PARALLEL_DISPATCHER convexDecompositionObjectOffset.setValue(10,0,0); btVector3 worldAabbMin(-10000,-10000,-10000); btVector3 worldAabbMax(10000,10000,10000); m_broadphase = new btAxisSweep3(worldAabbMin,worldAabbMax); //m_broadphase = new btSimpleBroadphase(); m_solver = new btSequentialImpulseConstraintSolver(); m_dynamicsWorld = new btDiscreteDynamicsWorld(m_dispatcher,m_broadphase,m_solver,m_collisionConfiguration); #ifdef USE_PARALLEL_DISPATCHER m_dynamicsWorld->getDispatchInfo().m_enableSPU = true; #endif //USE_PARALLEL_DISPATCHER btTransform startTransform; startTransform.setIdentity(); startTransform.setOrigin(btVector3(0,-4.5,0)); btCollisionShape* boxShape = new btBoxShape(btVector3(30,2,30)); m_collisionShapes.push_back(boxShape); localCreateRigidBody(0.f,startTransform,boxShape); class MyConvexDecomposition : public ConvexDecomposition::ConvexDecompInterface { ConvexDecompositionDemo* m_convexDemo; public: btAlignedObjectArray<btConvexHullShape*> m_convexShapes; btAlignedObjectArray<btVector3> m_convexCentroids; MyConvexDecomposition (FILE* outputFile,ConvexDecompositionDemo* demo) :m_convexDemo(demo), mBaseCount(0), mHullCount(0), mOutputFile(outputFile) { } virtual void ConvexDecompResult(ConvexDecomposition::ConvexResult &result) { btTriangleMesh* trimesh = new btTriangleMesh(); m_convexDemo->m_trimeshes.push_back(trimesh); btVector3 localScaling(6.f,6.f,6.f); //export data to .obj printf("ConvexResult. "); if (mOutputFile) { fprintf(mOutputFile,"## Hull Piece %d with %d vertices and %d triangles.\r\n", mHullCount, result.mHullVcount, result.mHullTcount ); fprintf(mOutputFile,"usemtl Material%i\r\n",mBaseCount); fprintf(mOutputFile,"o Object%i\r\n",mBaseCount); for (unsigned int i=0; i<result.mHullVcount; i++) { const float *p = &result.mHullVertices[i*3]; fprintf(mOutputFile,"v %0.9f %0.9f %0.9f\r\n", p[0], p[1], p[2] ); } //calc centroid, to shift vertices around center of mass centroid.setValue(0,0,0); btAlignedObjectArray<btVector3> vertices; if ( 1 ) { //const unsigned int *src = result.mHullIndices; for (unsigned int i=0; i<result.mHullVcount; i++) { btVector3 vertex(result.mHullVertices[i*3],result.mHullVertices[i*3+1],result.mHullVertices[i*3+2]); vertex *= localScaling; centroid += vertex; } } centroid *= 1.f/(float(result.mHullVcount) ); if ( 1 ) { //const unsigned int *src = result.mHullIndices; for (unsigned int i=0; i<result.mHullVcount; i++) { btVector3 vertex(result.mHullVertices[i*3],result.mHullVertices[i*3+1],result.mHullVertices[i*3+2]); vertex *= localScaling; vertex -= centroid ; vertices.push_back(vertex); } } if ( 1 ) { const unsigned int *src = result.mHullIndices; for (unsigned int i=0; i<result.mHullTcount; i++) { unsigned int index0 = *src++; unsigned int index1 = *src++; unsigned int index2 = *src++; btVector3 vertex0(result.mHullVertices[index0*3], result.mHullVertices[index0*3+1],result.mHullVertices[index0*3+2]); btVector3 vertex1(result.mHullVertices[index1*3], result.mHullVertices[index1*3+1],result.mHullVertices[index1*3+2]); btVector3 vertex2(result.mHullVertices[index2*3], result.mHullVertices[index2*3+1],result.mHullVertices[index2*3+2]); vertex0 *= localScaling; vertex1 *= localScaling; vertex2 *= localScaling; vertex0 -= centroid; vertex1 -= centroid; vertex2 -= centroid; trimesh->addTriangle(vertex0,vertex1,vertex2); index0+=mBaseCount; index1+=mBaseCount; index2+=mBaseCount; fprintf(mOutputFile,"f %d %d %d\r\n", index0+1, index1+1, index2+1 ); } } float mass = 1.f; //float collisionMargin = 0.01f; //this is a tools issue: due to collision margin, convex objects overlap, compensate for it here: //#define SHRINK_OBJECT_INWARDS 1 #ifdef SHRINK_OBJECT_INWARDS std::vector<btVector3> planeEquations; btGeometryUtil::getPlaneEquationsFromVertices(vertices,planeEquations); std::vector<btVector3> shiftedPlaneEquations; for (int p=0;p<planeEquations.size();p++) { btVector3 plane = planeEquations[p]; plane[3] += 5*collisionMargin; shiftedPlaneEquations.push_back(plane); } std::vector<btVector3> shiftedVertices; btGeometryUtil::getVerticesFromPlaneEquations(shiftedPlaneEquations,shiftedVertices); btConvexHullShape* convexShape = new btConvexHullShape(&(shiftedVertices[0].getX()),shiftedVertices.size()); #else //SHRINK_OBJECT_INWARDS btConvexHullShape* convexShape = new btConvexHullShape(&(vertices[0].getX()),vertices.size()); #endif convexShape->setMargin(0.01); m_convexShapes.push_back(convexShape); m_convexCentroids.push_back(centroid); m_convexDemo->m_collisionShapes.push_back(convexShape); mBaseCount+=result.mHullVcount; // advance the 'base index' counter. } } int mBaseCount; int mHullCount; FILE* mOutputFile; }; if (tcount) { btTriangleMesh* trimesh = new btTriangleMesh(); m_trimeshes.push_back(trimesh); btVector3 localScaling(6.f,6.f,6.f); int i; for ( i=0;i<wo.mTriCount;i++) { int index0 = wo.mIndices[i*3]; int index1 = wo.mIndices[i*3+1]; int index2 = wo.mIndices[i*3+2]; btVector3 vertex0(wo.mVertices[index0*3], wo.mVertices[index0*3+1],wo.mVertices[index0*3+2]); btVector3 vertex1(wo.mVertices[index1*3], wo.mVertices[index1*3+1],wo.mVertices[index1*3+2]); btVector3 vertex2(wo.mVertices[index2*3], wo.mVertices[index2*3+1],wo.mVertices[index2*3+2]); vertex0 *= localScaling; vertex1 *= localScaling; vertex2 *= localScaling; trimesh->addTriangle(vertex0,vertex1,vertex2); } btConvexShape* tmpConvexShape = new btConvexTriangleMeshShape(trimesh); printf("old numTriangles= %d\n",wo.mTriCount); printf("old numIndices = %d\n",wo.mTriCount*3); printf("old numVertices = %d\n",wo.mVertexCount); printf("reducing vertices by creating a convex hull\n"); //create a hull approximation btShapeHull* hull = new btShapeHull(tmpConvexShape); btScalar margin = tmpConvexShape->getMargin(); hull->buildHull(margin); tmpConvexShape->setUserPointer(hull); printf("new numTriangles = %d\n", hull->numTriangles ()); printf("new numIndices = %d\n", hull->numIndices ()); printf("new numVertices = %d\n", hull->numVertices ()); btConvexHullShape* convexShape = new btConvexHullShape(); for (i=0;i<hull->numVertices();i++) { convexShape->addPoint(hull->getVertexPointer()[i]); } delete tmpConvexShape; delete hull; m_collisionShapes.push_back(convexShape); float mass = 1.f; btTransform startTransform; startTransform.setIdentity(); startTransform.setOrigin(btVector3(0,2,0)); localCreateRigidBody(mass, startTransform,convexShape); bool useQuantization = true; btCollisionShape* concaveShape = new btBvhTriangleMeshShape(trimesh,useQuantization); startTransform.setOrigin(convexDecompositionObjectOffset); localCreateRigidBody(0.f,startTransform,concaveShape); m_collisionShapes.push_back (concaveShape); } if (tcount) { char outputFileName[512]; strcpy(outputFileName,filename); char *dot = strstr(outputFileName,"."); if ( dot ) *dot = 0; strcat(outputFileName,"_convex.obj"); FILE* outputFile = fopen(outputFileName,"wb"); unsigned int depth = 5; float cpercent = 5; float ppercent = 15; unsigned int maxv = 16; float skinWidth = 0.0; printf("WavefrontObj num triangles read %i\n",tcount); ConvexDecomposition::DecompDesc desc; desc.mVcount = wo.mVertexCount; desc.mVertices = wo.mVertices; desc.mTcount = wo.mTriCount; desc.mIndices = (unsigned int *)wo.mIndices; desc.mDepth = depth; desc.mCpercent = cpercent; desc.mPpercent = ppercent; desc.mMaxVertices = maxv; desc.mSkinWidth = skinWidth; MyConvexDecomposition convexDecomposition(outputFile,this); desc.mCallback = &convexDecomposition; //convexDecomposition.performConvexDecomposition(desc); ConvexBuilder cb(desc.mCallback); cb.process(desc); //now create some bodies { btCompoundShape* compound = new btCompoundShape(); m_collisionShapes.push_back (compound); btTransform trans; trans.setIdentity(); for (int i=0;i<convexDecomposition.m_convexShapes.size();i++) { btVector3 centroid = convexDecomposition.m_convexCentroids[i]; trans.setOrigin(centroid); btConvexHullShape* convexShape = convexDecomposition.m_convexShapes[i]; compound->addChildShape(trans,convexShape); } btScalar mass=10.f; trans.setOrigin(-convexDecompositionObjectOffset); localCreateRigidBody( mass, trans,compound); convexDecompositionObjectOffset.setZ(6); trans.setOrigin(-convexDecompositionObjectOffset); localCreateRigidBody( mass, trans,compound); convexDecompositionObjectOffset.setZ(-6); trans.setOrigin(-convexDecompositionObjectOffset); localCreateRigidBody( mass, trans,compound); } if (outputFile) fclose(outputFile); } }
int main(int argc,char** argv) { int i; for (i=0;i<numObjects;i++) { if (i>0) { shapePtr[i] = prebuildShapePtr[1]; shapeIndex[i] = 1;//sphere } else { shapeIndex[i] = 0; shapePtr[i] = prebuildShapePtr[0]; } } ConvexDecomposition::WavefrontObj wo; char* filename = "file.obj"; tcount = wo.loadObj(filename); class MyConvexDecomposition : public ConvexDecomposition::ConvexDecompInterface { public: MyConvexDecomposition (FILE* outputFile) :mBaseCount(0), mHullCount(0), mOutputFile(outputFile) { } virtual void ConvexDecompResult(ConvexDecomposition::ConvexResult &result) { TriangleMesh* trimesh = new TriangleMesh(); SimdVector3 localScaling(6.f,6.f,6.f); //export data to .obj printf("ConvexResult\n"); if (mOutputFile) { fprintf(mOutputFile,"## Hull Piece %d with %d vertices and %d triangles.\r\n", mHullCount, result.mHullVcount, result.mHullTcount ); fprintf(mOutputFile,"usemtl Material%i\r\n",mBaseCount); fprintf(mOutputFile,"o Object%i\r\n",mBaseCount); for (unsigned int i=0; i<result.mHullVcount; i++) { const float *p = &result.mHullVertices[i*3]; fprintf(mOutputFile,"v %0.9f %0.9f %0.9f\r\n", p[0], p[1], p[2] ); } //calc centroid, to shift vertices around center of mass centroids[numObjects] = SimdVector3(0,0,0); if ( 1 ) { const unsigned int *src = result.mHullIndices; for (unsigned int i=0; i<result.mHullTcount; i++) { unsigned int index0 = *src++; unsigned int index1 = *src++; unsigned int index2 = *src++; SimdVector3 vertex0(result.mHullVertices[index0*3], result.mHullVertices[index0*3+1],result.mHullVertices[index0*3+2]); SimdVector3 vertex1(result.mHullVertices[index1*3], result.mHullVertices[index1*3+1],result.mHullVertices[index1*3+2]); SimdVector3 vertex2(result.mHullVertices[index2*3], result.mHullVertices[index2*3+1],result.mHullVertices[index2*3+2]); vertex0 *= localScaling; vertex1 *= localScaling; vertex2 *= localScaling; centroids[numObjects] += vertex0; centroids[numObjects]+= vertex1; centroids[numObjects]+= vertex2; } } centroids[numObjects] *= 1.f/(float(result.mHullTcount) * 3); if ( 1 ) { const unsigned int *src = result.mHullIndices; for (unsigned int i=0; i<result.mHullTcount; i++) { unsigned int index0 = *src++; unsigned int index1 = *src++; unsigned int index2 = *src++; SimdVector3 vertex0(result.mHullVertices[index0*3], result.mHullVertices[index0*3+1],result.mHullVertices[index0*3+2]); SimdVector3 vertex1(result.mHullVertices[index1*3], result.mHullVertices[index1*3+1],result.mHullVertices[index1*3+2]); SimdVector3 vertex2(result.mHullVertices[index2*3], result.mHullVertices[index2*3+1],result.mHullVertices[index2*3+2]); vertex0 *= localScaling; vertex1 *= localScaling; vertex2 *= localScaling; vertex0 -= centroids[numObjects]; vertex1 -= centroids[numObjects]; vertex2 -= centroids[numObjects]; trimesh->AddTriangle(vertex0,vertex1,vertex2); index0+=mBaseCount; index1+=mBaseCount; index2+=mBaseCount; fprintf(mOutputFile,"f %d %d %d\r\n", index0+1, index1+1, index2+1 ); } } shapeIndex[numObjects] = numObjects; shapePtr[numObjects++] = new ConvexTriangleMeshShape(trimesh); mBaseCount+=result.mHullVcount; // advance the 'base index' counter. } } int mBaseCount; int mHullCount; FILE* mOutputFile; }; if (tcount) { numObjects = 1; //always have the ground object first TriangleMesh* trimesh = new TriangleMesh(); SimdVector3 localScaling(6.f,6.f,6.f); for (int i=0;i<wo.mTriCount;i++) { int index0 = wo.mIndices[i*3]; int index1 = wo.mIndices[i*3+1]; int index2 = wo.mIndices[i*3+2]; SimdVector3 vertex0(wo.mVertices[index0*3], wo.mVertices[index0*3+1],wo.mVertices[index0*3+2]); SimdVector3 vertex1(wo.mVertices[index1*3], wo.mVertices[index1*3+1],wo.mVertices[index1*3+2]); SimdVector3 vertex2(wo.mVertices[index2*3], wo.mVertices[index2*3+1],wo.mVertices[index2*3+2]); vertex0 *= localScaling; vertex1 *= localScaling; vertex2 *= localScaling; trimesh->AddTriangle(vertex0,vertex1,vertex2); } shapePtr[numObjects++] = new ConvexTriangleMeshShape(trimesh); } if (tcount) { char outputFileName[512]; strcpy(outputFileName,filename); char *dot = strstr(outputFileName,"."); if ( dot ) *dot = 0; strcat(outputFileName,"_convex.obj"); FILE* outputFile = fopen(outputFileName,"wb"); unsigned int depth = 7; float cpercent = 5; float ppercent = 15; unsigned int maxv = 16; float skinWidth = 0.01; printf("WavefrontObj num triangles read %i",tcount); ConvexDecomposition::DecompDesc desc; desc.mVcount = wo.mVertexCount; desc.mVertices = wo.mVertices; desc.mTcount = wo.mTriCount; desc.mIndices = (unsigned int *)wo.mIndices; desc.mDepth = depth; desc.mCpercent = cpercent; desc.mPpercent = ppercent; desc.mMaxVertices = maxv; desc.mSkinWidth = skinWidth; MyConvexDecomposition convexDecomposition(outputFile); desc.mCallback = &convexDecomposition; //convexDecomposition.performConvexDecomposition(desc); ConvexBuilder cb(desc.mCallback); int ret = cb.process(desc); if (outputFile) fclose(outputFile); } CollisionDispatcher* dispatcher = new CollisionDispatcher(); SimdVector3 worldAabbMin(-10000,-10000,-10000); SimdVector3 worldAabbMax(10000,10000,10000); OverlappingPairCache* broadphase = new AxisSweep3(worldAabbMin,worldAabbMax); //OverlappingPairCache* broadphase = new SimpleBroadphase(); physicsEnvironmentPtr = new CcdPhysicsEnvironment(dispatcher,broadphase); physicsEnvironmentPtr->setDeactivationTime(2.f); physicsEnvironmentPtr->setGravity(0,-10,0); PHY_ShapeProps shapeProps; shapeProps.m_do_anisotropic = false; shapeProps.m_do_fh = false; shapeProps.m_do_rot_fh = false; shapeProps.m_friction_scaling[0] = 1.; shapeProps.m_friction_scaling[1] = 1.; shapeProps.m_friction_scaling[2] = 1.; shapeProps.m_inertia = 1.f; shapeProps.m_lin_drag = 0.2f; shapeProps.m_ang_drag = 0.1f; shapeProps.m_mass = 10.0f; PHY_MaterialProps materialProps; materialProps.m_friction = 10.5f; materialProps.m_restitution = 0.0f; CcdConstructionInfo ccdObjectCi; ccdObjectCi.m_friction = 0.5f; ccdObjectCi.m_linearDamping = shapeProps.m_lin_drag; ccdObjectCi.m_angularDamping = shapeProps.m_ang_drag; SimdTransform tr; tr.setIdentity(); for (i=0;i<numObjects;i++) { shapeProps.m_shape = shapePtr[shapeIndex[i]]; shapeProps.m_shape->SetMargin(0.05f); bool isDyna = i>0; //if (i==1) // isDyna=false; if (0)//i==1) { SimdQuaternion orn(0,0,0.1*SIMD_HALF_PI); ms[i].setWorldOrientation(orn.x(),orn.y(),orn.z(),orn[3]); } if (i>0) { switch (i) { case 1: { ms[i].setWorldPosition(0,10,0); //for testing, rotate the ground cube so the stack has to recover a bit break; } case 2: { ms[i].setWorldPosition(0,8,2); break; } default: ms[i].setWorldPosition(0,i*CUBE_HALF_EXTENTS*2 - CUBE_HALF_EXTENTS,0); } float quatIma0,quatIma1,quatIma2,quatReal; SimdQuaternion quat; SimdVector3 axis(0,0,1); SimdScalar angle=0.5f; quat.setRotation(axis,angle); ms[i].setWorldOrientation(quat.getX(),quat.getY(),quat.getZ(),quat[3]); } else { ms[i].setWorldPosition(0,-10+EXTRA_HEIGHT,0); } ccdObjectCi.m_MotionState = &ms[i]; ccdObjectCi.m_gravity = SimdVector3(0,0,0); ccdObjectCi.m_localInertiaTensor =SimdVector3(0,0,0); if (!isDyna) { shapeProps.m_mass = 0.f; ccdObjectCi.m_mass = shapeProps.m_mass; ccdObjectCi.m_collisionFlags = CollisionObject::isStatic; } else { shapeProps.m_mass = 1.f; ccdObjectCi.m_mass = shapeProps.m_mass; ccdObjectCi.m_collisionFlags = 0; } SimdVector3 localInertia; if (shapePtr[shapeIndex[i]]->GetShapeType() == EMPTY_SHAPE_PROXYTYPE) { //take inertia from first shape shapePtr[1]->CalculateLocalInertia(shapeProps.m_mass,localInertia); } else { shapePtr[shapeIndex[i]]->CalculateLocalInertia(shapeProps.m_mass,localInertia); } ccdObjectCi.m_localInertiaTensor = localInertia; ccdObjectCi.m_collisionShape = shapePtr[shapeIndex[i]]; physObjects[i]= new CcdPhysicsController( ccdObjectCi); // Only do CCD if motion in one timestep (1.f/60.f) exceeds CUBE_HALF_EXTENTS physObjects[i]->GetRigidBody()->m_ccdSquareMotionTreshold = CUBE_HALF_EXTENTS; //Experimental: better estimation of CCD Time of Impact: //physObjects[i]->GetRigidBody()->m_ccdSweptShereRadius = 0.5*CUBE_HALF_EXTENTS; physicsEnvironmentPtr->addCcdPhysicsController( physObjects[i]); if (i==1) { //physObjects[i]->SetAngularVelocity(0,0,-2,true); } physicsEnvironmentPtr->setDebugDrawer(&debugDrawer); } //create a constraint if (createConstraint) { //physObjects[i]->SetAngularVelocity(0,0,-2,true); int constraintId; float pivotX=CUBE_HALF_EXTENTS, pivotY=-CUBE_HALF_EXTENTS, pivotZ=CUBE_HALF_EXTENTS; float axisX=1,axisY=0,axisZ=0; HingeConstraint* hinge = 0; SimdVector3 pivotInA(CUBE_HALF_EXTENTS,-CUBE_HALF_EXTENTS,CUBE_HALF_EXTENTS); SimdVector3 pivotInB(-CUBE_HALF_EXTENTS,-CUBE_HALF_EXTENTS,CUBE_HALF_EXTENTS); SimdVector3 axisInA(0,1,0); SimdVector3 axisInB(0,-1,0); RigidBody* rb0 = physObjects[1]->GetRigidBody(); RigidBody* rb1 = physObjects[2]->GetRigidBody(); hinge = new HingeConstraint( *rb0, *rb1,pivotInA,pivotInB,axisInA,axisInB); physicsEnvironmentPtr->m_constraints.push_back(hinge); hinge->SetUserConstraintId(100); hinge->SetUserConstraintType(PHY_LINEHINGE_CONSTRAINT); } clientResetScene(); setCameraDistance(26.f); return glutmain(argc, argv,640,480,"Bullet Physics Demo. http://www.continuousphysics.com/Bullet/phpBB2/"); }
void ConvexDecompositionDemo::initPhysics(const char* filename) { gContactAddedCallback = &MyContactCallback; setupEmptyDynamicsWorld(); setTexturing(true); setShadows(true); setCameraDistance(26.f); #ifndef NO_OBJ_TO_BULLET ConvexDecomposition::WavefrontObj wo; tcount = wo.loadObj(filename); if (!tcount) { //when running this app from visual studio, the default starting folder is different, so make a second attempt... tcount = wo.loadObj("../../file.obj"); } if (!tcount) { //cmake generated msvc files need 4 levels deep back... so make a 3rd attempt... tcount = wo.loadObj("../../../../file.obj"); } btTransform startTransform; startTransform.setIdentity(); startTransform.setOrigin(btVector3(0,-4.5,0)); btCollisionShape* boxShape = new btBoxShape(btVector3(30,2,30)); m_collisionShapes.push_back(boxShape); localCreateRigidBody(0.f,startTransform,boxShape); class MyConvexDecomposition : public ConvexDecomposition::ConvexDecompInterface { ConvexDecompositionDemo* m_convexDemo; public: btAlignedObjectArray<btConvexHullShape*> m_convexShapes; btAlignedObjectArray<btVector3> m_convexCentroids; MyConvexDecomposition (FILE* outputFile,ConvexDecompositionDemo* demo) :m_convexDemo(demo), mBaseCount(0), mHullCount(0), mOutputFile(outputFile) { } virtual void ConvexDecompResult(ConvexDecomposition::ConvexResult &result) { btTriangleMesh* trimesh = new btTriangleMesh(); m_convexDemo->m_trimeshes.push_back(trimesh); btVector3 localScaling(6.f,6.f,6.f); //export data to .obj printf("ConvexResult. "); if (mOutputFile) { fprintf(mOutputFile,"## Hull Piece %d with %d vertices and %d triangles.\r\n", mHullCount, result.mHullVcount, result.mHullTcount ); fprintf(mOutputFile,"usemtl Material%i\r\n",mBaseCount); fprintf(mOutputFile,"o Object%i\r\n",mBaseCount); for (unsigned int i=0; i<result.mHullVcount; i++) { const float *p = &result.mHullVertices[i*3]; fprintf(mOutputFile,"v %0.9f %0.9f %0.9f\r\n", p[0], p[1], p[2] ); } //calc centroid, to shift vertices around center of mass centroid.setValue(0,0,0); btAlignedObjectArray<btVector3> vertices; if ( 1 ) { //const unsigned int *src = result.mHullIndices; for (unsigned int i=0; i<result.mHullVcount; i++) { btVector3 vertex(result.mHullVertices[i*3],result.mHullVertices[i*3+1],result.mHullVertices[i*3+2]); vertex *= localScaling; centroid += vertex; } } centroid *= 1.f/(float(result.mHullVcount) ); if ( 1 ) { //const unsigned int *src = result.mHullIndices; for (unsigned int i=0; i<result.mHullVcount; i++) { btVector3 vertex(result.mHullVertices[i*3],result.mHullVertices[i*3+1],result.mHullVertices[i*3+2]); vertex *= localScaling; vertex -= centroid ; vertices.push_back(vertex); } } if ( 1 ) { const unsigned int *src = result.mHullIndices; for (unsigned int i=0; i<result.mHullTcount; i++) { unsigned int index0 = *src++; unsigned int index1 = *src++; unsigned int index2 = *src++; btVector3 vertex0(result.mHullVertices[index0*3], result.mHullVertices[index0*3+1],result.mHullVertices[index0*3+2]); btVector3 vertex1(result.mHullVertices[index1*3], result.mHullVertices[index1*3+1],result.mHullVertices[index1*3+2]); btVector3 vertex2(result.mHullVertices[index2*3], result.mHullVertices[index2*3+1],result.mHullVertices[index2*3+2]); vertex0 *= localScaling; vertex1 *= localScaling; vertex2 *= localScaling; vertex0 -= centroid; vertex1 -= centroid; vertex2 -= centroid; trimesh->addTriangle(vertex0,vertex1,vertex2); index0+=mBaseCount; index1+=mBaseCount; index2+=mBaseCount; fprintf(mOutputFile,"f %d %d %d\r\n", index0+1, index1+1, index2+1 ); } } // float mass = 1.f; //this is a tools issue: due to collision margin, convex objects overlap, compensate for it here: //#define SHRINK_OBJECT_INWARDS 1 #ifdef SHRINK_OBJECT_INWARDS float collisionMargin = 0.01f; btAlignedObjectArray<btVector3> planeEquations; btGeometryUtil::getPlaneEquationsFromVertices(vertices,planeEquations); btAlignedObjectArray<btVector3> shiftedPlaneEquations; for (int p=0;p<planeEquations.size();p++) { btVector3 plane = planeEquations[p]; plane[3] += collisionMargin; shiftedPlaneEquations.push_back(plane); } btAlignedObjectArray<btVector3> shiftedVertices; btGeometryUtil::getVerticesFromPlaneEquations(shiftedPlaneEquations,shiftedVertices); btConvexHullShape* convexShape = new btConvexHullShape(&(shiftedVertices[0].getX()),shiftedVertices.size()); #else //SHRINK_OBJECT_INWARDS btConvexHullShape* convexShape = new btConvexHullShape(&(vertices[0].getX()),vertices.size()); #endif convexShape->setMargin(0.01f); m_convexShapes.push_back(convexShape); m_convexCentroids.push_back(centroid); m_convexDemo->m_collisionShapes.push_back(convexShape); mBaseCount+=result.mHullVcount; // advance the 'base index' counter. } } int mBaseCount; int mHullCount; FILE* mOutputFile; }; if (tcount) { btTriangleMesh* trimesh = new btTriangleMesh(); m_trimeshes.push_back(trimesh); btVector3 localScaling(6.f,6.f,6.f); int i; for ( i=0;i<wo.mTriCount;i++) { int index0 = wo.mIndices[i*3]; int index1 = wo.mIndices[i*3+1]; int index2 = wo.mIndices[i*3+2]; btVector3 vertex0(wo.mVertices[index0*3], wo.mVertices[index0*3+1],wo.mVertices[index0*3+2]); btVector3 vertex1(wo.mVertices[index1*3], wo.mVertices[index1*3+1],wo.mVertices[index1*3+2]); btVector3 vertex2(wo.mVertices[index2*3], wo.mVertices[index2*3+1],wo.mVertices[index2*3+2]); vertex0 *= localScaling; vertex1 *= localScaling; vertex2 *= localScaling; trimesh->addTriangle(vertex0,vertex1,vertex2); } btConvexShape* tmpConvexShape = new btConvexTriangleMeshShape(trimesh); printf("old numTriangles= %d\n",wo.mTriCount); printf("old numIndices = %d\n",wo.mTriCount*3); printf("old numVertices = %d\n",wo.mVertexCount); printf("reducing vertices by creating a convex hull\n"); //create a hull approximation btShapeHull* hull = new btShapeHull(tmpConvexShape); btScalar margin = tmpConvexShape->getMargin(); hull->buildHull(margin); tmpConvexShape->setUserPointer(hull); printf("new numTriangles = %d\n", hull->numTriangles ()); printf("new numIndices = %d\n", hull->numIndices ()); printf("new numVertices = %d\n", hull->numVertices ()); btConvexHullShape* convexShape = new btConvexHullShape(); for (i=0;i<hull->numVertices();i++) { convexShape->addPoint(hull->getVertexPointer()[i]); } delete tmpConvexShape; delete hull; m_collisionShapes.push_back(convexShape); float mass = 1.f; btTransform startTransform; startTransform.setIdentity(); startTransform.setOrigin(btVector3(0,2,14)); localCreateRigidBody(mass, startTransform,convexShape); bool useQuantization = true; btCollisionShape* concaveShape = new btBvhTriangleMeshShape(trimesh,useQuantization); startTransform.setOrigin(convexDecompositionObjectOffset); localCreateRigidBody(0.f,startTransform,concaveShape); m_collisionShapes.push_back (concaveShape); } if (tcount) { char outputFileName[512]; strcpy(outputFileName,filename); char *dot = strstr(outputFileName,"."); if ( dot ) *dot = 0; strcat(outputFileName,"_convex.obj"); FILE* outputFile = fopen(outputFileName,"wb"); unsigned int depth = 5; float cpercent = 5; float ppercent = 15; unsigned int maxv = 16; float skinWidth = 0.0; printf("WavefrontObj num triangles read %i\n",tcount); ConvexDecomposition::DecompDesc desc; desc.mVcount = wo.mVertexCount; desc.mVertices = wo.mVertices; desc.mTcount = wo.mTriCount; desc.mIndices = (unsigned int *)wo.mIndices; desc.mDepth = depth; desc.mCpercent = cpercent; desc.mPpercent = ppercent; desc.mMaxVertices = maxv; desc.mSkinWidth = skinWidth; MyConvexDecomposition convexDecomposition(outputFile,this); desc.mCallback = &convexDecomposition; //convexDecomposition.performConvexDecomposition(desc); ConvexBuilder cb(desc.mCallback); cb.process(desc); //now create some bodies if (1) { btCompoundShape* compound = new btCompoundShape(); m_collisionShapes.push_back (compound); btTransform trans; trans.setIdentity(); for (int i=0;i<convexDecomposition.m_convexShapes.size();i++) { btVector3 centroid = convexDecomposition.m_convexCentroids[i]; trans.setOrigin(centroid); btConvexHullShape* convexShape = convexDecomposition.m_convexShapes[i]; compound->addChildShape(trans,convexShape); btRigidBody* body; body = localCreateRigidBody( 1.0, trans,convexShape); } #if 1 btScalar mass=10.f; trans.setOrigin(-convexDecompositionObjectOffset); btRigidBody* body = localCreateRigidBody( mass, trans,compound); body->setCollisionFlags(body->getCollisionFlags() | btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK); convexDecompositionObjectOffset.setZ(6); trans.setOrigin(-convexDecompositionObjectOffset); body = localCreateRigidBody( mass, trans,compound); body->setCollisionFlags(body->getCollisionFlags() | btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK); convexDecompositionObjectOffset.setZ(-6); trans.setOrigin(-convexDecompositionObjectOffset); body = localCreateRigidBody( mass, trans,compound); body->setCollisionFlags(body->getCollisionFlags() | btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK); #endif } if (outputFile) fclose(outputFile); } #ifdef TEST_SERIALIZATION //test serializing this int maxSerializeBufferSize = 1024*1024*5; btDefaultSerializer* serializer = new btDefaultSerializer(maxSerializeBufferSize); m_dynamicsWorld->serialize(serializer); FILE* f2 = fopen("testFile.bullet","wb"); fwrite(serializer->getBufferPointer(),serializer->getCurrentBufferSize(),1,f2); fclose(f2); exitPhysics(); //now try again from the loaded file setupEmptyDynamicsWorld(); #endif //TEST_SERIALIZATION #endif //NO_OBJ_TO_BULLET #ifdef TEST_SERIALIZATION btBulletWorldImporter* fileLoader = new btBulletWorldImporter(m_dynamicsWorld); //fileLoader->setVerboseMode(true); fileLoader->loadFile("testFile.bullet"); //fileLoader->loadFile("testFile64Double.bullet"); //fileLoader->loadFile("testFile64Single.bullet"); //fileLoader->loadFile("testFile32Single.bullet"); #endif //TEST_SERIALIZATION }
void ConvexDecompositionDemo::initPhysics(const char* filename) { ConvexDecomposition::WavefrontObj wo; tcount = wo.loadObj(filename); CollisionDispatcher* dispatcher = new CollisionDispatcher(); SimdVector3 worldAabbMin(-10000,-10000,-10000); SimdVector3 worldAabbMax(10000,10000,10000); OverlappingPairCache* broadphase = new AxisSweep3(worldAabbMin,worldAabbMax); //OverlappingPairCache* broadphase = new SimpleBroadphase(); m_physicsEnvironmentPtr = new CcdPhysicsEnvironment(dispatcher,broadphase); m_physicsEnvironmentPtr->setDeactivationTime(2.f); m_physicsEnvironmentPtr->setGravity(0,-10,0); SimdTransform startTransform; startTransform.setIdentity(); startTransform.setOrigin(SimdVector3(0,-4,0)); LocalCreatePhysicsObject(false,0,startTransform,new BoxShape(SimdVector3(30,2,30))); class MyConvexDecomposition : public ConvexDecomposition::ConvexDecompInterface { ConvexDecompositionDemo* m_convexDemo; public: MyConvexDecomposition (FILE* outputFile,ConvexDecompositionDemo* demo) :m_convexDemo(demo), mBaseCount(0), mHullCount(0), mOutputFile(outputFile) { } virtual void ConvexDecompResult(ConvexDecomposition::ConvexResult &result) { TriangleMesh* trimesh = new TriangleMesh(); SimdVector3 localScaling(6.f,6.f,6.f); //export data to .obj printf("ConvexResult\n"); if (mOutputFile) { fprintf(mOutputFile,"## Hull Piece %d with %d vertices and %d triangles.\r\n", mHullCount, result.mHullVcount, result.mHullTcount ); fprintf(mOutputFile,"usemtl Material%i\r\n",mBaseCount); fprintf(mOutputFile,"o Object%i\r\n",mBaseCount); for (unsigned int i=0; i<result.mHullVcount; i++) { const float *p = &result.mHullVertices[i*3]; fprintf(mOutputFile,"v %0.9f %0.9f %0.9f\r\n", p[0], p[1], p[2] ); } //calc centroid, to shift vertices around center of mass centroid.setValue(0,0,0); if ( 1 ) { const unsigned int *src = result.mHullIndices; for (unsigned int i=0; i<result.mHullTcount; i++) { unsigned int index0 = *src++; unsigned int index1 = *src++; unsigned int index2 = *src++; SimdVector3 vertex0(result.mHullVertices[index0*3], result.mHullVertices[index0*3+1],result.mHullVertices[index0*3+2]); SimdVector3 vertex1(result.mHullVertices[index1*3], result.mHullVertices[index1*3+1],result.mHullVertices[index1*3+2]); SimdVector3 vertex2(result.mHullVertices[index2*3], result.mHullVertices[index2*3+1],result.mHullVertices[index2*3+2]); vertex0 *= localScaling; vertex1 *= localScaling; vertex2 *= localScaling; centroid += vertex0; centroid += vertex1; centroid += vertex2; } } centroid *= 1.f/(float(result.mHullTcount) * 3); if ( 1 ) { const unsigned int *src = result.mHullIndices; for (unsigned int i=0; i<result.mHullTcount; i++) { unsigned int index0 = *src++; unsigned int index1 = *src++; unsigned int index2 = *src++; SimdVector3 vertex0(result.mHullVertices[index0*3], result.mHullVertices[index0*3+1],result.mHullVertices[index0*3+2]); SimdVector3 vertex1(result.mHullVertices[index1*3], result.mHullVertices[index1*3+1],result.mHullVertices[index1*3+2]); SimdVector3 vertex2(result.mHullVertices[index2*3], result.mHullVertices[index2*3+1],result.mHullVertices[index2*3+2]); vertex0 *= localScaling; vertex1 *= localScaling; vertex2 *= localScaling; vertex0 -= centroid; vertex1 -= centroid; vertex2 -= centroid; trimesh->AddTriangle(vertex0,vertex1,vertex2); index0+=mBaseCount; index1+=mBaseCount; index2+=mBaseCount; fprintf(mOutputFile,"f %d %d %d\r\n", index0+1, index1+1, index2+1 ); } } bool isDynamic = true; float mass = 1.f; CollisionShape* convexShape = new ConvexTriangleMeshShape(trimesh); SimdTransform trans; trans.setIdentity(); trans.setOrigin(centroid); m_convexDemo->LocalCreatePhysicsObject(isDynamic, mass, trans,convexShape); mBaseCount+=result.mHullVcount; // advance the 'base index' counter. } } int mBaseCount; int mHullCount; FILE* mOutputFile; }; if (tcount) { TriangleMesh* trimesh = new TriangleMesh(); SimdVector3 localScaling(6.f,6.f,6.f); for (int i=0;i<wo.mTriCount;i++) { int index0 = wo.mIndices[i*3]; int index1 = wo.mIndices[i*3+1]; int index2 = wo.mIndices[i*3+2]; SimdVector3 vertex0(wo.mVertices[index0*3], wo.mVertices[index0*3+1],wo.mVertices[index0*3+2]); SimdVector3 vertex1(wo.mVertices[index1*3], wo.mVertices[index1*3+1],wo.mVertices[index1*3+2]); SimdVector3 vertex2(wo.mVertices[index2*3], wo.mVertices[index2*3+1],wo.mVertices[index2*3+2]); vertex0 *= localScaling; vertex1 *= localScaling; vertex2 *= localScaling; trimesh->AddTriangle(vertex0,vertex1,vertex2); } CollisionShape* convexShape = new ConvexTriangleMeshShape(trimesh); bool isDynamic = true; float mass = 1.f; SimdTransform startTransform; startTransform.setIdentity(); startTransform.setOrigin(SimdVector3(20,2,0)); LocalCreatePhysicsObject(isDynamic, mass, startTransform,convexShape); } if (tcount) { char outputFileName[512]; strcpy(outputFileName,filename); char *dot = strstr(outputFileName,"."); if ( dot ) *dot = 0; strcat(outputFileName,"_convex.obj"); FILE* outputFile = fopen(outputFileName,"wb"); unsigned int depth = 7; float cpercent = 5; float ppercent = 15; unsigned int maxv = 16; float skinWidth = 0.01; printf("WavefrontObj num triangles read %i",tcount); ConvexDecomposition::DecompDesc desc; desc.mVcount = wo.mVertexCount; desc.mVertices = wo.mVertices; desc.mTcount = wo.mTriCount; desc.mIndices = (unsigned int *)wo.mIndices; desc.mDepth = depth; desc.mCpercent = cpercent; desc.mPpercent = ppercent; desc.mMaxVertices = maxv; desc.mSkinWidth = skinWidth; MyConvexDecomposition convexDecomposition(outputFile,this); desc.mCallback = &convexDecomposition; //convexDecomposition.performConvexDecomposition(desc); ConvexBuilder cb(desc.mCallback); cb.process(desc); if (outputFile) fclose(outputFile); } m_physicsEnvironmentPtr->setDebugDrawer(&debugDrawer); }