VoronoiFractureDemo.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830
  1. /*
  2. Bullet Continuous Collision Detection and Physics Library
  3. Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
  4. This software is provided 'as-is', without any express or implied warranty.
  5. In no event will the authors be held liable for any damages arising from the use of this software.
  6. Permission is granted to anyone to use this software for any purpose,
  7. including commercial applications, and to alter it and redistribute it freely,
  8. subject to the following restrictions:
  9. 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.
  10. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
  11. 3. This notice may not be removed or altered from any source distribution.
  12. */
  13. /*
  14. Voronoi fracture and shatter code and demo copyright (c) 2011 Alain Ducharme
  15. - Reset scene (press spacebar) to generate new random voronoi shattered cuboids
  16. - Check console for total time required to: compute and mesh all 3D shards, calculate volumes and centers of mass and create rigid bodies
  17. - Modify VORONOIPOINTS define below to change number of potential voronoi shards
  18. - Note that demo's visual cracks between voronoi shards are NOT present in the internally generated voronoi mesh!
  19. */
  20. //Number of random voronoi points to generate for shattering
  21. #define VORONOIPOINTS 100
  22. //maximum number of objects (and allow user to shoot additional boxes)
  23. #define MAX_PROXIES (2048)
  24. #define BREAKING_THRESHOLD 3
  25. #define CONVEX_MARGIN 0.04
  26. static int useMpr = 0;
  27. #include "VoronoiFractureDemo.h"
  28. ///btBulletDynamicsCommon.h is the main Bullet include file, contains most common include files.
  29. #include "btBulletDynamicsCommon.h"
  30. #include <stdio.h> //printf debugging
  31. static bool useGenericConstraint = false;
  32. #include "btConvexConvexMprAlgorithm.h"
  33. #include "LinearMath/btAlignedObjectArray.h"
  34. #include "LinearMath/btConvexHullComputer.h"
  35. #include "LinearMath/btQuaternion.h"
  36. #include <set>
  37. #include <time.h>
  38. class btBroadphaseInterface;
  39. class btCollisionShape;
  40. class btOverlappingPairCache;
  41. class btCollisionDispatcher;
  42. class btConstraintSolver;
  43. struct btCollisionAlgorithmCreateFunc;
  44. class btDefaultCollisionConfiguration;
  45. #include "../CommonInterfaces/CommonRigidBodyBase.h"
  46. class VoronoiFractureDemo : public CommonRigidBodyBase
  47. {
  48. //keep the collision shapes, for deletion/cleanup
  49. btAlignedObjectArray<btCollisionShape*> m_collisionShapes;
  50. btBroadphaseInterface* m_broadphase;
  51. btCollisionDispatcher* m_dispatcher;
  52. btConstraintSolver* m_solver;
  53. btDefaultCollisionConfiguration* m_collisionConfiguration;
  54. btClock m_perfmTimer;
  55. public:
  56. VoronoiFractureDemo(struct GUIHelperInterface* helper)
  57. :CommonRigidBodyBase(helper)
  58. {
  59. srand((unsigned)time(NULL)); // Seed it...
  60. }
  61. virtual ~VoronoiFractureDemo()
  62. {
  63. btAssert(m_dynamicsWorld==0);
  64. }
  65. void initPhysics();
  66. void exitPhysics();
  67. //virtual void renderme();
  68. void getVerticesInsidePlanes(const btAlignedObjectArray<btVector3>& planes, btAlignedObjectArray<btVector3>& verticesOut, std::set<int>& planeIndicesOut);
  69. void voronoiBBShatter(const btAlignedObjectArray<btVector3>& points, const btVector3& bbmin, const btVector3& bbmax, const btQuaternion& bbq, const btVector3& bbt, btScalar matDensity);
  70. void voronoiConvexHullShatter(const btAlignedObjectArray<btVector3>& points, const btAlignedObjectArray<btVector3>& verts, const btQuaternion& bbq, const btVector3& bbt, btScalar matDensity);
  71. //virtual void clientMoveAndDisplay();
  72. //virtual void displayCallback();
  73. //virtual void clientResetScene();
  74. //virtual void keyboardCallback(unsigned char key, int x, int y);
  75. void attachFixedConstraints();
  76. virtual void resetCamera()
  77. {
  78. float dist = 18;
  79. float pitch = 129;
  80. float yaw = 30;
  81. float targetPos[3]={-1.5,4.7,-2};
  82. m_guiHelper->resetCamera(dist,pitch,yaw,targetPos[0],targetPos[1],targetPos[2]);
  83. }
  84. };
  85. void VoronoiFractureDemo::attachFixedConstraints()
  86. {
  87. btAlignedObjectArray<btRigidBody*> bodies;
  88. int numManifolds = m_dynamicsWorld->getDispatcher()->getNumManifolds();
  89. for (int i=0;i<numManifolds;i++)
  90. {
  91. btPersistentManifold* manifold = m_dynamicsWorld->getDispatcher()->getManifoldByIndexInternal(i);
  92. if (!manifold->getNumContacts())
  93. continue;
  94. btScalar minDist = 1e30f;
  95. int minIndex = -1;
  96. for (int v=0;v<manifold->getNumContacts();v++)
  97. {
  98. if (minDist >manifold->getContactPoint(v).getDistance())
  99. {
  100. minDist = manifold->getContactPoint(v).getDistance();
  101. minIndex = v;
  102. }
  103. }
  104. if (minDist>0.)
  105. continue;
  106. btCollisionObject* colObj0 = (btCollisionObject*)manifold->getBody0();
  107. btCollisionObject* colObj1 = (btCollisionObject*)manifold->getBody1();
  108. // int tag0 = (colObj0)->getIslandTag();
  109. // int tag1 = (colObj1)->getIslandTag();
  110. btRigidBody* body0 = btRigidBody::upcast(colObj0);
  111. btRigidBody* body1 = btRigidBody::upcast(colObj1);
  112. if (bodies.findLinearSearch(body0)==bodies.size())
  113. bodies.push_back(body0);
  114. if (bodies.findLinearSearch(body1)==bodies.size())
  115. bodies.push_back(body1);
  116. if (body0 && body1)
  117. {
  118. if (!colObj0->isStaticOrKinematicObject() && !colObj1->isStaticOrKinematicObject())
  119. {
  120. if (body0->checkCollideWithOverride(body1))
  121. {
  122. {
  123. btTransform trA,trB;
  124. trA.setIdentity();
  125. trB.setIdentity();
  126. btVector3 contactPosWorld = manifold->getContactPoint(minIndex).m_positionWorldOnA;
  127. btTransform globalFrame;
  128. globalFrame.setIdentity();
  129. globalFrame.setOrigin(contactPosWorld);
  130. trA = body0->getWorldTransform().inverse()*globalFrame;
  131. trB = body1->getWorldTransform().inverse()*globalFrame;
  132. float totalMass = 1.f/body0->getInvMass() + 1.f/body1->getInvMass();
  133. if (useGenericConstraint)
  134. {
  135. btGeneric6DofConstraint* dof6 = new btGeneric6DofConstraint(*body0,*body1,trA,trB,true);
  136. dof6->setOverrideNumSolverIterations(30);
  137. dof6->setBreakingImpulseThreshold(BREAKING_THRESHOLD*totalMass);
  138. for (int i=0;i<6;i++)
  139. dof6->setLimit(i,0,0);
  140. m_dynamicsWorld->addConstraint(dof6,true);
  141. } else
  142. {
  143. btFixedConstraint* fixed = new btFixedConstraint(*body0,*body1,trA,trB);
  144. fixed->setBreakingImpulseThreshold(BREAKING_THRESHOLD*totalMass);
  145. fixed ->setOverrideNumSolverIterations(30);
  146. m_dynamicsWorld->addConstraint(fixed,true);
  147. }
  148. }
  149. }
  150. }
  151. }
  152. }
  153. for (int i=0;i<bodies.size();i++)
  154. {
  155. m_dynamicsWorld->removeRigidBody(bodies[i]);
  156. m_dynamicsWorld->addRigidBody(bodies[i]);
  157. }
  158. }
  159. /*
  160. void VoronoiFractureDemo::keyboardCallback(unsigned char key, int x, int y)
  161. {
  162. if (key == 'g')
  163. {
  164. attachFixedConstraints();
  165. }else
  166. {
  167. PlatformDemoApplication::keyboardCallback(key,x,y);
  168. }
  169. }
  170. */
  171. void VoronoiFractureDemo::getVerticesInsidePlanes(const btAlignedObjectArray<btVector3>& planes, btAlignedObjectArray<btVector3>& verticesOut, std::set<int>& planeIndicesOut)
  172. {
  173. // Based on btGeometryUtil.cpp (Gino van den Bergen / Erwin Coumans)
  174. verticesOut.resize(0);
  175. planeIndicesOut.clear();
  176. const int numPlanes = planes.size();
  177. int i, j, k, l;
  178. for (i=0;i<numPlanes;i++)
  179. {
  180. const btVector3& N1 = planes[i];
  181. for (j=i+1;j<numPlanes;j++)
  182. {
  183. const btVector3& N2 = planes[j];
  184. btVector3 n1n2 = N1.cross(N2);
  185. if (n1n2.length2() > btScalar(0.0001))
  186. {
  187. for (k=j+1;k<numPlanes;k++)
  188. {
  189. const btVector3& N3 = planes[k];
  190. btVector3 n2n3 = N2.cross(N3);
  191. btVector3 n3n1 = N3.cross(N1);
  192. if ((n2n3.length2() > btScalar(0.0001)) && (n3n1.length2() > btScalar(0.0001) ))
  193. {
  194. btScalar quotient = (N1.dot(n2n3));
  195. if (btFabs(quotient) > btScalar(0.0001))
  196. {
  197. btVector3 potentialVertex = (n2n3 * N1[3] + n3n1 * N2[3] + n1n2 * N3[3]) * (btScalar(-1.) / quotient);
  198. for (l=0; l<numPlanes; l++)
  199. {
  200. const btVector3& NP = planes[l];
  201. if (btScalar(NP.dot(potentialVertex))+btScalar(NP[3]) > btScalar(0.000001))
  202. break;
  203. }
  204. if (l == numPlanes)
  205. {
  206. // vertex (three plane intersection) inside all planes
  207. verticesOut.push_back(potentialVertex);
  208. planeIndicesOut.insert(i);
  209. planeIndicesOut.insert(j);
  210. planeIndicesOut.insert(k);
  211. }
  212. }
  213. }
  214. }
  215. }
  216. }
  217. }
  218. }
  219. static btVector3 curVoronoiPoint;
  220. struct pointCmp
  221. {
  222. bool operator()(const btVector3& p1, const btVector3& p2) const
  223. {
  224. float v1 = (p1-curVoronoiPoint).length2();
  225. float v2 = (p2-curVoronoiPoint).length2();
  226. bool result0 = v1 < v2;
  227. //bool result1 = ((btScalar)(p1-curVoronoiPoint).length2()) < ((btScalar)(p2-curVoronoiPoint).length2());
  228. //apparently result0 is not always result1, because extended precision used in registered is different from precision when values are stored in memory
  229. return result0;
  230. }
  231. };
  232. void VoronoiFractureDemo::voronoiBBShatter(const btAlignedObjectArray<btVector3>& points, const btVector3& bbmin, const btVector3& bbmax, const btQuaternion& bbq, const btVector3& bbt, btScalar matDensity) {
  233. // points define voronoi cells in world space (avoid duplicates)
  234. // bbmin & bbmax = bounding box min and max in local space
  235. // bbq & bbt = bounding box quaternion rotation and translation
  236. // matDensity = Material density for voronoi shard mass calculation
  237. btVector3 bbvx = quatRotate(bbq, btVector3(1.0, 0.0, 0.0));
  238. btVector3 bbvy = quatRotate(bbq, btVector3(0.0, 1.0, 0.0));
  239. btVector3 bbvz = quatRotate(bbq, btVector3(0.0, 0.0, 1.0));
  240. btQuaternion bbiq = bbq.inverse();
  241. btConvexHullComputer* convexHC = new btConvexHullComputer();
  242. btAlignedObjectArray<btVector3> vertices;
  243. btVector3 rbb, nrbb;
  244. btScalar nlength, maxDistance, distance;
  245. btAlignedObjectArray<btVector3> sortedVoronoiPoints;
  246. sortedVoronoiPoints.copyFromArray(points);
  247. btVector3 normal, plane;
  248. btAlignedObjectArray<btVector3> planes;
  249. std::set<int> planeIndices;
  250. std::set<int>::iterator planeIndicesIter;
  251. int numplaneIndices;
  252. int cellnum = 0;
  253. int i, j, k;
  254. int numpoints = points.size();
  255. for (i=0; i < numpoints ;i++) {
  256. curVoronoiPoint = points[i];
  257. btVector3 icp = quatRotate(bbiq, curVoronoiPoint - bbt);
  258. rbb = icp - bbmax;
  259. nrbb = bbmin - icp;
  260. planes.resize(6);
  261. planes[0] = bbvx; planes[0][3] = rbb.x();
  262. planes[1] = bbvy; planes[1][3] = rbb.y();
  263. planes[2] = bbvz; planes[2][3] = rbb.z();
  264. planes[3] = -bbvx; planes[3][3] = nrbb.x();
  265. planes[4] = -bbvy; planes[4][3] = nrbb.y();
  266. planes[5] = -bbvz; planes[5][3] = nrbb.z();
  267. maxDistance = SIMD_INFINITY;
  268. sortedVoronoiPoints.heapSort(pointCmp());
  269. for (j=1; j < numpoints; j++) {
  270. normal = sortedVoronoiPoints[j] - curVoronoiPoint;
  271. nlength = normal.length();
  272. if (nlength > maxDistance)
  273. break;
  274. plane = normal.normalized();
  275. plane[3] = -nlength / btScalar(2.);
  276. planes.push_back(plane);
  277. getVerticesInsidePlanes(planes, vertices, planeIndices);
  278. if (vertices.size() == 0)
  279. break;
  280. numplaneIndices = planeIndices.size();
  281. if (numplaneIndices != planes.size()) {
  282. planeIndicesIter = planeIndices.begin();
  283. for (k=0; k < numplaneIndices; k++) {
  284. if (k != *planeIndicesIter)
  285. planes[k] = planes[*planeIndicesIter];
  286. planeIndicesIter++;
  287. }
  288. planes.resize(numplaneIndices);
  289. }
  290. maxDistance = vertices[0].length();
  291. for (k=1; k < vertices.size(); k++) {
  292. distance = vertices[k].length();
  293. if (maxDistance < distance)
  294. maxDistance = distance;
  295. }
  296. maxDistance *= btScalar(2.);
  297. }
  298. if (vertices.size() == 0)
  299. continue;
  300. // Clean-up voronoi convex shard vertices and generate edges & faces
  301. convexHC->compute(&vertices[0].getX(), sizeof(btVector3), vertices.size(),CONVEX_MARGIN,0.0);
  302. // At this point we have a complete 3D voronoi shard mesh contained in convexHC
  303. // Calculate volume and center of mass (Stan Melax volume integration)
  304. int numFaces = convexHC->faces.size();
  305. int v0, v1, v2; // Triangle vertices
  306. btScalar volume = btScalar(0.);
  307. btVector3 com(0., 0., 0.);
  308. for (j=0; j < numFaces; j++) {
  309. const btConvexHullComputer::Edge* edge = &convexHC->edges[convexHC->faces[j]];
  310. v0 = edge->getSourceVertex();
  311. v1 = edge->getTargetVertex();
  312. edge = edge->getNextEdgeOfFace();
  313. v2 = edge->getTargetVertex();
  314. while (v2 != v0) {
  315. // Counter-clockwise triangulated voronoi shard mesh faces (v0-v1-v2) and edges here...
  316. btScalar vol = convexHC->vertices[v0].triple(convexHC->vertices[v1], convexHC->vertices[v2]);
  317. volume += vol;
  318. com += vol * (convexHC->vertices[v0] + convexHC->vertices[v1] + convexHC->vertices[v2]);
  319. edge = edge->getNextEdgeOfFace();
  320. v1 = v2;
  321. v2 = edge->getTargetVertex();
  322. }
  323. }
  324. com /= volume * btScalar(4.);
  325. volume /= btScalar(6.);
  326. // Shift all vertices relative to center of mass
  327. int numVerts = convexHC->vertices.size();
  328. for (j=0; j < numVerts; j++)
  329. {
  330. convexHC->vertices[j] -= com;
  331. }
  332. // Note:
  333. // At this point convex hulls contained in convexHC should be accurate (line up flush with other pieces, no cracks),
  334. // ...however Bullet Physics rigid bodies demo visualizations appear to produce some visible cracks.
  335. // Use the mesh in convexHC for visual display or to perform boolean operations with.
  336. // Create Bullet Physics rigid body shards
  337. btCollisionShape* shardShape = new btConvexHullShape(&(convexHC->vertices[0].getX()), convexHC->vertices.size());
  338. shardShape->setMargin(CONVEX_MARGIN); // for this demo; note convexHC has optional margin parameter for this
  339. m_collisionShapes.push_back(shardShape);
  340. btTransform shardTransform;
  341. shardTransform.setIdentity();
  342. shardTransform.setOrigin(curVoronoiPoint + com); // Shard's adjusted location
  343. btDefaultMotionState* shardMotionState = new btDefaultMotionState(shardTransform);
  344. btScalar shardMass(volume * matDensity);
  345. btVector3 shardInertia(0.,0.,0.);
  346. shardShape->calculateLocalInertia(shardMass, shardInertia);
  347. btRigidBody::btRigidBodyConstructionInfo shardRBInfo(shardMass, shardMotionState, shardShape, shardInertia);
  348. btRigidBody* shardBody = new btRigidBody(shardRBInfo);
  349. m_dynamicsWorld->addRigidBody(shardBody);
  350. cellnum ++;
  351. }
  352. printf("Generated %d voronoi btRigidBody shards\n", cellnum);
  353. }
  354. void VoronoiFractureDemo::voronoiConvexHullShatter(const btAlignedObjectArray<btVector3>& points, const btAlignedObjectArray<btVector3>& verts, const btQuaternion& bbq, const btVector3& bbt, btScalar matDensity) {
  355. // points define voronoi cells in world space (avoid duplicates)
  356. // verts = source (convex hull) mesh vertices in local space
  357. // bbq & bbt = source (convex hull) mesh quaternion rotation and translation
  358. // matDensity = Material density for voronoi shard mass calculation
  359. btConvexHullComputer* convexHC = new btConvexHullComputer();
  360. btAlignedObjectArray<btVector3> vertices, chverts;
  361. btVector3 rbb, nrbb;
  362. btScalar nlength, maxDistance, distance;
  363. btAlignedObjectArray<btVector3> sortedVoronoiPoints;
  364. sortedVoronoiPoints.copyFromArray(points);
  365. btVector3 normal, plane;
  366. btAlignedObjectArray<btVector3> planes, convexPlanes;
  367. std::set<int> planeIndices;
  368. std::set<int>::iterator planeIndicesIter;
  369. int numplaneIndices;
  370. int cellnum = 0;
  371. int i, j, k;
  372. // Convert verts to world space and get convexPlanes
  373. int numverts = verts.size();
  374. chverts.resize(verts.size());
  375. for (i=0; i < numverts ;i++) {
  376. chverts[i] = quatRotate(bbq, verts[i]) + bbt;
  377. }
  378. //btGeometryUtil::getPlaneEquationsFromVertices(chverts, convexPlanes);
  379. // Using convexHullComputer faster than getPlaneEquationsFromVertices for large meshes...
  380. convexHC->compute(&chverts[0].getX(), sizeof(btVector3), numverts, 0.0, 0.0);
  381. int numFaces = convexHC->faces.size();
  382. int v0, v1, v2; // vertices
  383. for (i=0; i < numFaces; i++) {
  384. const btConvexHullComputer::Edge* edge = &convexHC->edges[convexHC->faces[i]];
  385. v0 = edge->getSourceVertex();
  386. v1 = edge->getTargetVertex();
  387. edge = edge->getNextEdgeOfFace();
  388. v2 = edge->getTargetVertex();
  389. plane = (convexHC->vertices[v1]-convexHC->vertices[v0]).cross(convexHC->vertices[v2]-convexHC->vertices[v0]).normalize();
  390. plane[3] = -plane.dot(convexHC->vertices[v0]);
  391. convexPlanes.push_back(plane);
  392. }
  393. const int numconvexPlanes = convexPlanes.size();
  394. int numpoints = points.size();
  395. for (i=0; i < numpoints ;i++) {
  396. curVoronoiPoint = points[i];
  397. planes.copyFromArray(convexPlanes);
  398. for (j=0; j < numconvexPlanes ;j++) {
  399. planes[j][3] += planes[j].dot(curVoronoiPoint);
  400. }
  401. maxDistance = SIMD_INFINITY;
  402. sortedVoronoiPoints.heapSort(pointCmp());
  403. for (j=1; j < numpoints; j++) {
  404. normal = sortedVoronoiPoints[j] - curVoronoiPoint;
  405. nlength = normal.length();
  406. if (nlength > maxDistance)
  407. break;
  408. plane = normal.normalized();
  409. plane[3] = -nlength / btScalar(2.);
  410. planes.push_back(plane);
  411. getVerticesInsidePlanes(planes, vertices, planeIndices);
  412. if (vertices.size() == 0)
  413. break;
  414. numplaneIndices = planeIndices.size();
  415. if (numplaneIndices != planes.size()) {
  416. planeIndicesIter = planeIndices.begin();
  417. for (k=0; k < numplaneIndices; k++) {
  418. if (k != *planeIndicesIter)
  419. planes[k] = planes[*planeIndicesIter];
  420. planeIndicesIter++;
  421. }
  422. planes.resize(numplaneIndices);
  423. }
  424. maxDistance = vertices[0].length();
  425. for (k=1; k < vertices.size(); k++) {
  426. distance = vertices[k].length();
  427. if (maxDistance < distance)
  428. maxDistance = distance;
  429. }
  430. maxDistance *= btScalar(2.);
  431. }
  432. if (vertices.size() == 0)
  433. continue;
  434. // Clean-up voronoi convex shard vertices and generate edges & faces
  435. convexHC->compute(&vertices[0].getX(), sizeof(btVector3), vertices.size(),0.0,0.0);
  436. // At this point we have a complete 3D voronoi shard mesh contained in convexHC
  437. // Calculate volume and center of mass (Stan Melax volume integration)
  438. numFaces = convexHC->faces.size();
  439. btScalar volume = btScalar(0.);
  440. btVector3 com(0., 0., 0.);
  441. for (j=0; j < numFaces; j++) {
  442. const btConvexHullComputer::Edge* edge = &convexHC->edges[convexHC->faces[j]];
  443. v0 = edge->getSourceVertex();
  444. v1 = edge->getTargetVertex();
  445. edge = edge->getNextEdgeOfFace();
  446. v2 = edge->getTargetVertex();
  447. while (v2 != v0) {
  448. // Counter-clockwise triangulated voronoi shard mesh faces (v0-v1-v2) and edges here...
  449. btScalar vol = convexHC->vertices[v0].triple(convexHC->vertices[v1], convexHC->vertices[v2]);
  450. volume += vol;
  451. com += vol * (convexHC->vertices[v0] + convexHC->vertices[v1] + convexHC->vertices[v2]);
  452. edge = edge->getNextEdgeOfFace();
  453. v1 = v2;
  454. v2 = edge->getTargetVertex();
  455. }
  456. }
  457. com /= volume * btScalar(4.);
  458. volume /= btScalar(6.);
  459. // Shift all vertices relative to center of mass
  460. int numVerts = convexHC->vertices.size();
  461. for (j=0; j < numVerts; j++)
  462. {
  463. convexHC->vertices[j] -= com;
  464. }
  465. // Note:
  466. // At this point convex hulls contained in convexHC should be accurate (line up flush with other pieces, no cracks),
  467. // ...however Bullet Physics rigid bodies demo visualizations appear to produce some visible cracks.
  468. // Use the mesh in convexHC for visual display or to perform boolean operations with.
  469. // Create Bullet Physics rigid body shards
  470. btCollisionShape* shardShape = new btConvexHullShape(&(convexHC->vertices[0].getX()), convexHC->vertices.size());
  471. shardShape->setMargin(CONVEX_MARGIN); // for this demo; note convexHC has optional margin parameter for this
  472. m_collisionShapes.push_back(shardShape);
  473. btTransform shardTransform;
  474. shardTransform.setIdentity();
  475. shardTransform.setOrigin(curVoronoiPoint + com); // Shard's adjusted location
  476. btDefaultMotionState* shardMotionState = new btDefaultMotionState(shardTransform);
  477. btScalar shardMass(volume * matDensity);
  478. btVector3 shardInertia(0.,0.,0.);
  479. shardShape->calculateLocalInertia(shardMass, shardInertia);
  480. btRigidBody::btRigidBodyConstructionInfo shardRBInfo(shardMass, shardMotionState, shardShape, shardInertia);
  481. btRigidBody* shardBody = new btRigidBody(shardRBInfo);
  482. m_dynamicsWorld->addRigidBody(shardBody);
  483. cellnum ++;
  484. }
  485. printf("Generated %d voronoi btRigidBody shards\n", cellnum);
  486. }
  487. /*
  488. void VoronoiFractureDemo::clientMoveAndDisplay()
  489. {
  490. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  491. //simple dynamics world doesn't handle fixed-time-stepping
  492. float ms = getDeltaTimeMicroseconds();
  493. ///step the simulation
  494. if (m_dynamicsWorld)
  495. {
  496. m_dynamicsWorld->stepSimulation(1. / 60., 0);// ms / 1000000.f);
  497. //optional but useful: debug drawing
  498. m_dynamicsWorld->debugDrawWorld();
  499. }
  500. renderme();
  501. glFlush();
  502. swapBuffers();
  503. }
  504. */
  505. /*
  506. void VoronoiFractureDemo::displayCallback(void) {
  507. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  508. renderme();
  509. //optional but useful: debug drawing to detect problems
  510. if (m_dynamicsWorld)
  511. m_dynamicsWorld->debugDrawWorld();
  512. glFlush();
  513. swapBuffers();
  514. }
  515. */
  516. /*
  517. void VoronoiFractureDemo::renderme()
  518. {
  519. DemoApplication::renderme();
  520. char buf[124];
  521. int lineWidth = 200;
  522. int xStart = m_glutScreenWidth - lineWidth;
  523. if (useMpr)
  524. {
  525. sprintf(buf, "Using GJK+MPR");
  526. }
  527. else
  528. {
  529. sprintf(buf, "Using GJK+EPA");
  530. }
  531. GLDebugDrawString(xStart, 20, buf);
  532. }
  533. */
  534. void VoronoiFractureDemo::initPhysics()
  535. {
  536. m_guiHelper->setUpAxis(1);
  537. srand(13);
  538. useGenericConstraint = !useGenericConstraint;
  539. printf("useGenericConstraint = %d\n", useGenericConstraint);
  540. ///collision configuration contains default setup for memory, collision setup
  541. m_collisionConfiguration = new btDefaultCollisionConfiguration();
  542. //m_collisionConfiguration->setConvexConvexMultipointIterations();
  543. ///use the default collision dispatcher. For parallel processing you can use a diffent dispatcher (see Extras/BulletMultiThreaded)
  544. m_dispatcher = new btCollisionDispatcher(m_collisionConfiguration);
  545. useMpr = 1 - useMpr;
  546. if (useMpr)
  547. {
  548. printf("using GJK+MPR convex-convex collision detection\n");
  549. btConvexConvexMprAlgorithm::CreateFunc* cf = new btConvexConvexMprAlgorithm::CreateFunc;
  550. m_dispatcher->registerCollisionCreateFunc(CONVEX_HULL_SHAPE_PROXYTYPE, CONVEX_HULL_SHAPE_PROXYTYPE, cf);
  551. m_dispatcher->registerCollisionCreateFunc(CONVEX_HULL_SHAPE_PROXYTYPE, BOX_SHAPE_PROXYTYPE, cf);
  552. m_dispatcher->registerCollisionCreateFunc(BOX_SHAPE_PROXYTYPE, CONVEX_HULL_SHAPE_PROXYTYPE, cf);
  553. }
  554. else
  555. {
  556. printf("using default (GJK+EPA) convex-convex collision detection\n");
  557. }
  558. m_broadphase = new btDbvtBroadphase();
  559. ///the default constraint solver. For parallel processing you can use a different solver (see Extras/BulletMultiThreaded)
  560. btSequentialImpulseConstraintSolver* sol = new btSequentialImpulseConstraintSolver;
  561. m_solver = sol;
  562. m_dynamicsWorld = new btDiscreteDynamicsWorld(m_dispatcher,m_broadphase,m_solver,m_collisionConfiguration);
  563. m_dynamicsWorld->getSolverInfo().m_splitImpulse = true;
  564. m_guiHelper->createPhysicsDebugDrawer(m_dynamicsWorld);
  565. m_dynamicsWorld->setGravity(btVector3(0,-10,0));
  566. ///create a few basic rigid bodies
  567. btCollisionShape* groundShape = new btBoxShape(btVector3(btScalar(50.),btScalar(50.),btScalar(50.)));
  568. // btCollisionShape* groundShape = new btStaticPlaneShape(btVector3(0,1,0),50);
  569. m_collisionShapes.push_back(groundShape);
  570. btTransform groundTransform;
  571. groundTransform.setIdentity();
  572. groundTransform.setOrigin(btVector3(0,-50,0));
  573. //We can also use DemoApplication::localCreateRigidBody, but for clarity it is provided here:
  574. {
  575. btScalar mass(0.);
  576. //rigidbody is dynamic if and only if mass is non zero, otherwise static
  577. bool isDynamic = (mass != 0.f);
  578. btVector3 localInertia(0,0,0);
  579. if (isDynamic)
  580. groundShape->calculateLocalInertia(mass,localInertia);
  581. //using motionstate is recommended, it provides interpolation capabilities, and only synchronizes 'active' objects
  582. btDefaultMotionState* myMotionState = new btDefaultMotionState(groundTransform);
  583. btRigidBody::btRigidBodyConstructionInfo rbInfo(mass,myMotionState,groundShape,localInertia);
  584. btRigidBody* body = new btRigidBody(rbInfo);
  585. //add the body to the dynamics world
  586. m_dynamicsWorld->addRigidBody(body);
  587. }
  588. {
  589. btCollisionShape* groundShape = new btBoxShape(btVector3(btScalar(10.),btScalar(8.),btScalar(1.)));
  590. btScalar mass(0.);
  591. //rigidbody is dynamic if and only if mass is non zero, otherwise static
  592. bool isDynamic = (mass != 0.f);
  593. btVector3 localInertia(0,0,0);
  594. if (isDynamic)
  595. groundShape->calculateLocalInertia(mass,localInertia);
  596. groundTransform.setOrigin(btVector3(0,0,0));
  597. //using motionstate is recommended, it provides interpolation capabilities, and only synchronizes 'active' objects
  598. btDefaultMotionState* myMotionState = new btDefaultMotionState(groundTransform);
  599. btRigidBody::btRigidBodyConstructionInfo rbInfo(mass,myMotionState,groundShape,localInertia);
  600. btRigidBody* body = new btRigidBody(rbInfo);
  601. //add the body to the dynamics world
  602. m_dynamicsWorld->addRigidBody(body);
  603. }
  604. // ==> Voronoi Shatter Basic Demo: Random Cuboid
  605. // Random size cuboid (defined by bounding box max and min)
  606. btVector3 bbmax(btScalar(rand() / btScalar(RAND_MAX)) * 12. +0.5, btScalar(rand() / btScalar(RAND_MAX)) * 1. +0.5, btScalar(rand() / btScalar(RAND_MAX)) * 1. +0.5);
  607. btVector3 bbmin = -bbmax;
  608. // Place it 10 units above ground
  609. btVector3 bbt(0,15,0);
  610. // Use an arbitrary material density for shards (should be consitent/relative with/to rest of RBs in world)
  611. btScalar matDensity = 1;
  612. // Using random rotation
  613. btQuaternion bbq(btScalar(rand() / btScalar(RAND_MAX)) * 2. -1.,btScalar(rand() / btScalar(RAND_MAX)) * 2. -1.,btScalar(rand() / btScalar(RAND_MAX)) * 2. -1.,btScalar(rand() / btScalar(RAND_MAX)) * 2. -1.);
  614. bbq.normalize();
  615. // Generate random points for voronoi cells
  616. btAlignedObjectArray<btVector3> points;
  617. btVector3 point;
  618. btVector3 diff = bbmax - bbmin;
  619. for (int i=0; i < VORONOIPOINTS; i++) {
  620. // Place points within box area (points are in world coordinates)
  621. point = quatRotate(bbq, btVector3(btScalar(rand() / btScalar(RAND_MAX)) * diff.x() -diff.x()/2., btScalar(rand() / btScalar(RAND_MAX)) * diff.y() -diff.y()/2., btScalar(rand() / btScalar(RAND_MAX)) * diff.z() -diff.z()/2.)) + bbt;
  622. points.push_back(point);
  623. }
  624. m_perfmTimer.reset();
  625. voronoiBBShatter(points, bbmin, bbmax, bbq, bbt, matDensity);
  626. printf("Total Time: %f seconds\n", m_perfmTimer.getTimeMilliseconds()/1000.);
  627. for (int i=m_dynamicsWorld->getNumCollisionObjects()-1; i>=0 ;i--)
  628. {
  629. btCollisionObject* obj = m_dynamicsWorld->getCollisionObjectArray()[i];
  630. obj->getCollisionShape()->setMargin(CONVEX_MARGIN+0.01);
  631. }
  632. m_dynamicsWorld->performDiscreteCollisionDetection();
  633. for (int i=m_dynamicsWorld->getNumCollisionObjects()-1; i>=0 ;i--)
  634. {
  635. btCollisionObject* obj = m_dynamicsWorld->getCollisionObjectArray()[i];
  636. obj->getCollisionShape()->setMargin(CONVEX_MARGIN);
  637. }
  638. attachFixedConstraints();
  639. m_guiHelper->autogenerateGraphicsObjects(m_dynamicsWorld);
  640. }
  641. void VoronoiFractureDemo::exitPhysics()
  642. {
  643. //cleanup in the reverse order of creation/initialization
  644. int i;
  645. //remove all constraints
  646. for (i=m_dynamicsWorld->getNumConstraints()-1;i>=0;i--)
  647. {
  648. btTypedConstraint* constraint = m_dynamicsWorld->getConstraint(i);
  649. m_dynamicsWorld->removeConstraint(constraint);
  650. delete constraint;
  651. }
  652. //remove the rigidbodies from the dynamics world and delete them
  653. for (i=m_dynamicsWorld->getNumCollisionObjects()-1; i>=0 ;i--)
  654. {
  655. btCollisionObject* obj = m_dynamicsWorld->getCollisionObjectArray()[i];
  656. btRigidBody* body = btRigidBody::upcast(obj);
  657. if (body && body->getMotionState())
  658. {
  659. delete body->getMotionState();
  660. }
  661. m_dynamicsWorld->removeCollisionObject( obj );
  662. delete obj;
  663. }
  664. //delete collision shapes
  665. for (int j=0;j<m_collisionShapes.size();j++)
  666. {
  667. btCollisionShape* shape = m_collisionShapes[j];
  668. delete shape;
  669. }
  670. m_collisionShapes.clear();
  671. delete m_dynamicsWorld;
  672. m_dynamicsWorld = 0;
  673. delete m_solver;
  674. m_solver=0;
  675. delete m_broadphase;
  676. m_broadphase=0;
  677. delete m_dispatcher;
  678. m_dispatcher=0;
  679. delete m_collisionConfiguration;
  680. m_collisionConfiguration=0;
  681. }
  682. /*
  683. static DemoApplication* Create()
  684. {
  685. VoronoiFractureDemo* demo = new VoronoiFractureDemo;
  686. demo->myinit();
  687. demo->initPhysics();
  688. return demo;
  689. }
  690. */
  691. CommonExampleInterface* VoronoiFractureCreateFunc(struct CommonExampleOptions& options)
  692. {
  693. return new VoronoiFractureDemo(options.m_guiHelper);
  694. }