MultiMaterial.cpp

Go to the documentation of this file.
00001 /*
00002 Bullet Continuous Collision Detection and Physics Library
00003 Copyright (c) 2003-2006 Erwin Coumans  http://continuousphysics.com/Bullet/
00004 
00005 This software is provided 'as-is', without any express or implied warranty.
00006 In no event will the authors be held liable for any damages arising from the use of this software.
00007 Permission is granted to anyone to use this software for any purpose, 
00008 including commercial applications, and to alter it and redistribute it freely, 
00009 subject to the following restrictions:
00010 
00011 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.
00012 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
00013 3. This notice may not be removed or altered from any source distribution.
00014 */
00015 
00016 #include "DemoApplication.h"
00017 #include "LinearMath/btAlignedObjectArray.h"
00018 
00019 class btBroadphaseInterface;
00020 class btCollisionShape;
00021 class btOverlappingPairCache;
00022 class btCollisionDispatcher;
00023 class btConstraintSolver;
00024 struct btCollisionAlgorithmCreateFunc;
00025 class btDefaultCollisionConfiguration;
00026 class btTriangleIndexVertexArray;
00027 
00028 ///MultiMaterialDemo shows usage of static concave triangle meshes
00029 ///It also shows per-triangle material (friction/restitution) through CustomMaterialCombinerCallback
00030 class MultiMaterialDemo : public DemoApplication
00031 {
00032 
00033         //keep the collision shapes, for deletion/cleanup
00034         btAlignedObjectArray<btCollisionShape*> m_collisionShapes;
00035 
00036         btTriangleIndexVertexArray* m_indexVertexArrays;
00037 
00038         btBroadphaseInterface*  m_broadphase;
00039 
00040         btCollisionDispatcher*  m_dispatcher;
00041 
00042         btConstraintSolver*     m_solver;
00043 
00044         btDefaultCollisionConfiguration* m_collisionConfiguration;
00045 
00046         bool    m_animatedMesh;
00047 
00048         public:
00049 
00050         MultiMaterialDemo() : m_animatedMesh(true)
00051         {
00052 
00053         }
00054         void    initPhysics();
00055 
00056         void    exitPhysics();
00057 
00058         virtual ~MultiMaterialDemo()
00059         {
00060                 exitPhysics();
00061         }
00062 
00063         virtual void clientMoveAndDisplay();
00064 
00065         virtual void displayCallback();
00066         
00067         //to show refit works
00068         void    setVertexPositions(float waveheight, float offset);
00069         
00070         virtual void keyboardCallback(unsigned char key, int x, int y);
00071         
00072         static DemoApplication* Create()
00073         {
00074                 MultiMaterialDemo* demo = new MultiMaterialDemo();
00075                 demo->myinit();
00076                 demo->initPhysics();
00077                 return demo;
00078         };
00079 };
00080 
00081 #include "btBulletDynamicsCommon.h"
00082 #include "LinearMath/btIDebugDraw.h"
00083 #include "GLDebugDrawer.h"
00084 #include "GL_ShapeDrawer.h"
00085 #include "GlutStuff.h"
00086 
00087 #include "BulletCollision/CollisionShapes/btTriangleShape.h"
00088 #include "BulletCollision/CollisionShapes/btTriangleIndexVertexMaterialArray.h"
00089 #include "BulletCollision/CollisionShapes/btMultimaterialTriangleMeshShape.h"
00090 #include "BulletCollision/CollisionShapes/btMaterial.h"
00091 
00092 // Create a custom material, just because we can
00093 class CustomMaterial : public btMaterial
00094 {
00095 public:
00096     int foo1;
00097     int foo2;
00098     CustomMaterial(){}
00099     CustomMaterial(int a, int b) {foo1 = a; foo2 = b;}
00100 };
00101 
00102 // Storage for the vertex data
00103 static btVector3*       gVertices = 0;
00104 // Storage for the face data
00105 static int*     gIndices = 0;
00106 // Storage for the material data
00107 static CustomMaterial* gMaterials = 0;
00108 // Storage for the face -> material index data
00109 static int* gFaceMaterialIndices = 0;
00110 
00111 static btBvhTriangleMeshShape* trimeshShape =0;
00112 static btRigidBody* staticBody = 0;
00113 static float waveheight = 0.5;
00114 
00115 const float TRIANGLE_SIZE=1.f;
00116 
00117 
00118 ///User can override this material combiner by implementing gContactAddedCallback and setting body0->m_collisionFlags |= btCollisionObject::customMaterialCallback;
00119 inline btScalar calculateCombinedFriction(float friction0,float friction1)
00120 {
00121     btScalar friction = friction0 * friction1;
00122 
00123     const btScalar MAX_FRICTION  = 10.f;
00124     if (friction < -MAX_FRICTION)
00125         friction = -MAX_FRICTION;
00126     if (friction > MAX_FRICTION)
00127         friction = MAX_FRICTION;
00128     return friction;
00129 
00130 }
00131 
00132 inline btScalar calculateCombinedRestitution(float restitution0,float restitution1)
00133 {
00134     return restitution0 * restitution1;
00135 }
00136 
00137 
00138 
00139 static bool CustomMaterialCombinerCallback(btManifoldPoint& cp, const btCollisionObject* colObj0,int partId0,int index0,const btCollisionObject* colObj1,int partId1,int index1)
00140 {
00141     
00142     // Apply material properties
00143     if (colObj0->getCollisionShape()->getShapeType() == TRIANGLE_SHAPE_PROXYTYPE)
00144     {
00145         const btCollisionShape* parent0 = colObj0->getRootCollisionShape();
00146         if(parent0 != 0 && parent0->getShapeType() == MULTIMATERIAL_TRIANGLE_MESH_PROXYTYPE)
00147         {
00148             btMultimaterialTriangleMeshShape* shape = (btMultimaterialTriangleMeshShape*)parent0;
00149             const btMaterial * props = shape->getMaterialProperties(partId0, index0);
00150             cp.m_combinedFriction = calculateCombinedFriction(props->m_friction, colObj1->getFriction());
00151             cp.m_combinedRestitution = props->m_restitution * colObj1->getRestitution();
00152         }
00153     }
00154     else if (colObj1->getCollisionShape()->getShapeType() == TRIANGLE_SHAPE_PROXYTYPE)
00155     {
00156         const btCollisionShape* parent1 = colObj1->getRootCollisionShape();
00157         if(parent1 != 0 && parent1->getShapeType() == MULTIMATERIAL_TRIANGLE_MESH_PROXYTYPE)
00158         {
00159             btMultimaterialTriangleMeshShape* shape = (btMultimaterialTriangleMeshShape*)parent1;
00160             const btMaterial * props = shape->getMaterialProperties(partId1, index1);
00161             cp.m_combinedFriction = calculateCombinedFriction(props->m_friction, colObj0->getFriction());
00162             cp.m_combinedRestitution = props->m_restitution * colObj0->getRestitution();
00163         }
00164     }
00165 
00166     //this return value is currently ignored, but to be on the safe side: return false if you don't calculate friction
00167     return true;
00168 }
00169 
00170 extern ContactAddedCallback             gContactAddedCallback;
00171 
00172 const int NUM_VERTS_X = 20;
00173 const int NUM_VERTS_Y = 50;
00174 const int totalVerts = NUM_VERTS_X*NUM_VERTS_Y;
00175 
00176 void MultiMaterialDemo::setVertexPositions(float waveheight, float offset)
00177 {
00178     int i;
00179     int j;
00180 
00181     for ( i=0;i<NUM_VERTS_X;i++)
00182     {
00183         for (j=0;j<NUM_VERTS_Y;j++)
00184         {
00185             gVertices[i+j*NUM_VERTS_X].setValue((i-NUM_VERTS_X*0.5f)*TRIANGLE_SIZE,
00186                 //0.f,
00187                 waveheight*sinf((float)i+offset)*cosf((float)j+offset),
00188                 (j-NUM_VERTS_Y*0.5f)*TRIANGLE_SIZE);
00189         }
00190     }
00191 }
00192 
00193 void MultiMaterialDemo::keyboardCallback(unsigned char key, int x, int y)
00194 {
00195     if (key == 'g')
00196     {
00197         m_animatedMesh = !m_animatedMesh;
00198         if (m_animatedMesh)
00199         {
00200             staticBody->setCollisionFlags( staticBody->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT);
00201             staticBody->setActivationState(DISABLE_DEACTIVATION);
00202         } else
00203         {
00204             staticBody->setCollisionFlags( staticBody->getCollisionFlags() & ~btCollisionObject::CF_KINEMATIC_OBJECT);
00205             staticBody->forceActivationState(ACTIVE_TAG);
00206         }
00207     }
00208 
00209     DemoApplication::keyboardCallback(key,x,y);
00210 
00211 }
00212 
00213 void    MultiMaterialDemo::initPhysics()
00214 {
00215 #define TRISIZE 50.f
00216 
00217     gContactAddedCallback = CustomMaterialCombinerCallback;
00218 
00219     // The number of triangles
00220     const int totalTriangles = 2*(NUM_VERTS_X-1)*(NUM_VERTS_Y-1);
00221     // The number of materials
00222     const int totalMaterials = 2;
00223 
00224     int vertStride = sizeof(btVector3);
00225     int indexStride = 3*sizeof(int);
00226     int materialStride = sizeof(CustomMaterial);
00227     int triangleMaterialStride = sizeof(int);
00228 
00229     gVertices = new btVector3[totalVerts];
00230     gIndices = new int[totalTriangles*3];
00231     gMaterials = new CustomMaterial[totalMaterials];
00232     gFaceMaterialIndices = new int[totalTriangles];
00233 
00234     // Explicitly set up the materials.  It's a small array so let's do it bit by bit.
00235     gMaterials[0].m_friction = 0;
00236     gMaterials[0].m_restitution = 0.9;
00237     gMaterials[0].foo1 = 5;
00238     gMaterials[0].foo2 = 7;
00239     gMaterials[1].m_friction = 0.9;
00240     gMaterials[1].m_restitution = 0.1;
00241     gMaterials[1].foo1 = 53;
00242     gMaterials[1].foo2 = 15;
00243 
00244     int i;
00245     // Set up the vertex data
00246     setVertexPositions(waveheight,0.f);
00247     int index=0;
00248     // Set up the face data
00249     for ( i=0;i<NUM_VERTS_X-1;i++)
00250     {
00251         for (int j=0;j<NUM_VERTS_Y-1;j++)
00252         {
00253             gIndices[index++] = j*NUM_VERTS_X+i;
00254             gIndices[index++] = j*NUM_VERTS_X+i+1;
00255             gIndices[index++] = (j+1)*NUM_VERTS_X+i+1;
00256 
00257             gIndices[index++] = j*NUM_VERTS_X+i;
00258             gIndices[index++] = (j+1)*NUM_VERTS_X+i+1;
00259             gIndices[index++] = (j+1)*NUM_VERTS_X+i;
00260         }
00261     }
00262 
00263     // Set up the face->material index data
00264     for(int a = 0; a < totalTriangles; a++)
00265     {
00266         // This will give the first half of the faces low friction and high restitution
00267         // and the second half of the faces high friction and low restitution
00268         if(a > totalTriangles*0.5f)
00269             gFaceMaterialIndices[a] = 0;
00270         else
00271             gFaceMaterialIndices[a] = 1;
00272     }
00273 
00274     // Create the array structure
00275     m_indexVertexArrays = new btTriangleIndexVertexMaterialArray(
00276         totalTriangles, gIndices, indexStride,
00277         totalVerts,(btScalar*) &gVertices[0].x(),vertStride,
00278         totalMaterials, (unsigned char *)gMaterials, sizeof(CustomMaterial),
00279         gFaceMaterialIndices, sizeof(int));
00280 
00281     bool useQuantizedAabbCompression = true;
00282     // Create the multimaterial mesh shape
00283     trimeshShape  = new btMultimaterialTriangleMeshShape((btTriangleIndexVertexMaterialArray*)m_indexVertexArrays,useQuantizedAabbCompression);
00284     m_collisionShapes.push_back(trimeshShape);
00285 
00286     btCollisionShape* groundShape = trimeshShape;
00287 
00288     m_collisionConfiguration = new btDefaultCollisionConfiguration();
00289 
00290     m_dispatcher = new  btCollisionDispatcher(m_collisionConfiguration);
00291 
00292     btVector3 worldMin(-1000,-1000,-1000);
00293     btVector3 worldMax(1000,1000,1000);
00294     m_broadphase = new btAxisSweep3(worldMin,worldMax);
00295     m_solver = new btSequentialImpulseConstraintSolver();
00296     m_dynamicsWorld = new btDiscreteDynamicsWorld(m_dispatcher,m_broadphase,m_solver,m_collisionConfiguration);
00297 
00298     float mass = 0.f;
00299     btTransform startTransform;
00300     startTransform.setIdentity();
00301     startTransform.setOrigin(btVector3(0,-2,0));
00302 
00303     btCollisionShape* colShape = new btBoxShape(btVector3(0.5f,0.5f,0.5f));
00304     m_collisionShapes.push_back(colShape);
00305 
00306     {
00307         for (int i=0;i<1;i++)
00308         {
00309             startTransform.setOrigin(btVector3(10,10,-20));
00310             btRigidBody* body = localCreateRigidBody(1, startTransform,colShape);
00311             body->setCollisionFlags(body->getCollisionFlags()  | btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK);
00312             body->setFriction(0.9f);
00313             body->setGravity(btVector3(0,-20.f,0));
00314             body->applyCentralImpulse(btVector3(-7.7f,0,0));
00315         }
00316     }
00317 
00318     startTransform.setIdentity();
00319     staticBody = localCreateRigidBody(mass, startTransform,groundShape);
00320 
00321     staticBody->setCollisionFlags(staticBody->getCollisionFlags() | btCollisionObject::CF_STATIC_OBJECT);
00322 
00323     //enable custom material callback
00324     staticBody->setCollisionFlags(staticBody->getCollisionFlags()  | btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK);
00325 }
00326 
00327 void MultiMaterialDemo::clientMoveAndDisplay()
00328 {
00329     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 
00330 
00331     float dt = getDeltaTimeMicroseconds() * 0.000001f;
00332 
00333     if (m_animatedMesh)
00334     {
00335         static float offset=0.f;
00336         offset+=0.01f;
00337 
00338         //      setVertexPositions(waveheight,offset);
00339 
00340         int i;
00341         int j;
00342         btVector3 aabbMin(1e30,1e30,1e30);
00343         btVector3 aabbMax(-1e30,-1e30,-1e30);
00344 
00345         for ( i=NUM_VERTS_X/2-3;i<NUM_VERTS_X/2+2;i++)
00346         {
00347             for (j=NUM_VERTS_X/2-3;j<NUM_VERTS_Y/2+2;j++)
00348             {
00349 
00350                 aabbMax.setMax(gVertices[i+j*NUM_VERTS_X]);
00351                 aabbMin.setMin(gVertices[i+j*NUM_VERTS_X]);
00352 
00353                 gVertices[i+j*NUM_VERTS_X].setValue((i-NUM_VERTS_X*0.5f)*TRIANGLE_SIZE,
00354                     0.f,
00355                     (j-NUM_VERTS_Y*0.5f)*TRIANGLE_SIZE);
00356 
00357                 aabbMin.setMin(gVertices[i+j*NUM_VERTS_X]);
00358                 aabbMax.setMax(gVertices[i+j*NUM_VERTS_X]);
00359 
00360             }
00361         }
00362 
00363         trimeshShape->partialRefitTree(aabbMin,aabbMax);
00364 
00365         //clear all contact points involving mesh proxy. Note: this is a slow/unoptimized operation.
00366         m_dynamicsWorld->getBroadphase()->getOverlappingPairCache()->cleanProxyFromPairs(staticBody->getBroadphaseHandle(),getDynamicsWorld()->getDispatcher());
00367     }
00368 
00369     m_dynamicsWorld->stepSimulation(dt);
00370 
00371     //optional but useful: debug drawing
00372     m_dynamicsWorld->debugDrawWorld();
00373 
00374     renderme();
00375 
00376     glFlush();
00377     glutSwapBuffers();
00378 
00379 }
00380 
00381 
00382 
00383 
00384 void MultiMaterialDemo::displayCallback(void) {
00385 
00386     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 
00387 
00388     renderme();
00389 
00390     glFlush();
00391     glutSwapBuffers();
00392 }
00393 
00394 
00395 
00396 void    MultiMaterialDemo::exitPhysics()
00397 {
00398 
00399 
00400 
00401     //cleanup in the reverse order of creation/initialization
00402 
00403     //remove the rigidbodies from the dynamics world and delete them
00404     int i;
00405     for (i=m_dynamicsWorld->getNumCollisionObjects()-1; i>=0 ;i--)
00406     {
00407         btCollisionObject* obj = m_dynamicsWorld->getCollisionObjectArray()[i];
00408         btRigidBody* body = btRigidBody::upcast(obj);
00409         if (body && body->getMotionState())
00410         {
00411             delete body->getMotionState();
00412         }
00413         m_dynamicsWorld->removeCollisionObject( obj );
00414         delete obj;
00415     }
00416 
00417     //delete collision shapes
00418     for (int j=0;j<m_collisionShapes.size();j++)
00419     {
00420         btCollisionShape* shape = m_collisionShapes[j];
00421         delete shape;
00422     }
00423 
00424     //delete dynamics world
00425     delete m_dynamicsWorld;
00426 
00427     if (m_indexVertexArrays)
00428         delete m_indexVertexArrays;
00429 
00430     //delete solver
00431     delete m_solver;
00432 
00433     //delete broadphase
00434     delete m_broadphase;
00435 
00436     //delete dispatcher
00437     delete m_dispatcher;
00438 
00439     delete m_collisionConfiguration;
00440 
00441 
00442 }
00443 
00444 
00445 
00446 GLDebugDrawer   gDebugDrawer;
00447 
00448 int main(int argc,char** argv)
00449 {
00450 
00451         MultiMaterialDemo* multiMaterialDemo = new MultiMaterialDemo();
00452         multiMaterialDemo->initPhysics();
00453         multiMaterialDemo->setCameraDistance(30.f);
00454         
00455         multiMaterialDemo->getDynamicsWorld()->setDebugDrawer(&gDebugDrawer);
00456 
00457         return glutmain(argc, argv,640,480,"Multimaterial Mesh Demo",multiMaterialDemo);
00458 }
00459