2 Bullet Continuous Collision Detection and Physics Library
\r
3 Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
\r
5 This software is provided 'as-is', without any express or implied warranty.
\r
6 In no event will the authors be held liable for any damages arising from the use of this software.
\r
7 Permission is granted to anyone to use this software for any purpose,
\r
8 including commercial applications, and to alter it and redistribute it freely,
\r
9 subject to the following restrictions:
\r
11 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
\r
12 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
\r
13 3. This notice may not be removed or altered from any source distribution.
\r
16 Voronoi fracture and shatter code and demo copyright (c) 2011 Alain Ducharme
\r
17 - Reset scene (press spacebar) to generate new random voronoi shattered cuboids
\r
18 - Check console for total time required to: compute and mesh all 3D shards, calculate volumes and centers of mass and create rigid bodies
\r
19 - Modify VORONOIPOINTS define below to change number of potential voronoi shards
\r
20 - Note that demo's visual cracks between voronoi shards are NOT present in the internally generated voronoi mesh!
\r
23 //Number of random voronoi points to generate for shattering
\r
24 #define VORONOIPOINTS 100
\r
26 //maximum number of objects (and allow user to shoot additional boxes)
\r
27 #define MAX_PROXIES (2048)
\r
28 #define BREAKING_THRESHOLD 2
\r
29 #define CONVEX_MARGIN 0.04
\r
31 #include "VoronoiFractureDemo.h"
\r
32 #include "GlutStuff.h"
\r
33 ///btBulletDynamicsCommon.h is the main Bullet include file, contains most common include files.
\r
34 #include "btBulletDynamicsCommon.h"
\r
36 #include <stdio.h> //printf debugging
\r
38 #include "GLDebugDrawer.h"
\r
39 static GLDebugDrawer sDebugDraw;
\r
41 void VoronoiFractureDemo::attachFixedConstraints()
\r
43 btAlignedObjectArray<btRigidBody*> bodies;
\r
45 int numManifolds = getDynamicsWorld()->getDispatcher()->getNumManifolds();
\r
47 for (int i=0;i<numManifolds;i++)
\r
49 btPersistentManifold* manifold = getDynamicsWorld()->getDispatcher()->getManifoldByIndexInternal(i);
\r
50 if (!manifold->getNumContacts())
\r
53 btScalar minDist = 1e30f;
\r
55 for (int v=0;v<manifold->getNumContacts();v++)
\r
57 if (minDist >manifold->getContactPoint(v).getDistance())
\r
59 minDist = manifold->getContactPoint(v).getDistance();
\r
66 btCollisionObject* colObj0 = (btCollisionObject*)manifold->getBody0();
\r
67 btCollisionObject* colObj1 = (btCollisionObject*)manifold->getBody1();
\r
68 int tag0 = (colObj0)->getIslandTag();
\r
69 int tag1 = (colObj1)->getIslandTag();
\r
70 btRigidBody* body0 = btRigidBody::upcast(colObj0);
\r
71 btRigidBody* body1 = btRigidBody::upcast(colObj1);
\r
72 if (bodies.findLinearSearch(body0)==bodies.size())
\r
73 bodies.push_back(body0);
\r
74 if (bodies.findLinearSearch(body1)==bodies.size())
\r
75 bodies.push_back(body1);
\r
79 if (!colObj0->isStaticOrKinematicObject() && !colObj1->isStaticOrKinematicObject())
\r
81 if (body0->checkCollideWithOverride(body1))
\r
84 btTransform trA,trB;
\r
87 btVector3 contactPosWorld = manifold->getContactPoint(minIndex).m_positionWorldOnA;
\r
88 btTransform globalFrame;
\r
89 globalFrame.setIdentity();
\r
90 globalFrame.setOrigin(contactPosWorld);
\r
92 trA = body0->getWorldTransform().inverse()*globalFrame;
\r
93 trB = body1->getWorldTransform().inverse()*globalFrame;
\r
95 btGeneric6DofConstraint* dof6 = new btGeneric6DofConstraint(*body0,*body1,trA,trB,true);
\r
96 dof6->setOverrideNumSolverIterations(100);
\r
98 float totalMass = 1.f/body0->getInvMass() + 1.f/body1->getInvMass();
\r
100 dof6->setBreakingImpulseThreshold(BREAKING_THRESHOLD*totalMass);
\r
102 for (int i=0;i<6;i++)
\r
103 dof6->setLimit(i,0,0);
\r
104 getDynamicsWorld()->addConstraint(dof6,true);
\r
113 for (int i=0;i<bodies.size();i++)
\r
115 getDynamicsWorld()->removeRigidBody(bodies[i]);
\r
116 getDynamicsWorld()->addRigidBody(bodies[i]);
\r
120 void VoronoiFractureDemo::keyboardCallback(unsigned char key, int x, int y)
\r
124 attachFixedConstraints();
\r
127 PlatformDemoApplication::keyboardCallback(key,x,y);
\r
132 void VoronoiFractureDemo::getVerticesInsidePlanes(const btAlignedObjectArray<btVector3>& planes, btAlignedObjectArray<btVector3>& verticesOut, std::set<int>& planeIndicesOut)
\r
134 // Based on btGeometryUtil.cpp (Gino van den Bergen / Erwin Coumans)
\r
135 verticesOut.resize(0);
\r
136 planeIndicesOut.clear();
\r
137 const int numPlanes = planes.size();
\r
139 for (i=0;i<numPlanes;i++)
\r
141 const btVector3& N1 = planes[i];
\r
142 for (j=i+1;j<numPlanes;j++)
\r
144 const btVector3& N2 = planes[j];
\r
145 btVector3 n1n2 = N1.cross(N2);
\r
146 if (n1n2.length2() > btScalar(0.0001))
\r
148 for (k=j+1;k<numPlanes;k++)
\r
150 const btVector3& N3 = planes[k];
\r
151 btVector3 n2n3 = N2.cross(N3);
\r
152 btVector3 n3n1 = N3.cross(N1);
\r
153 if ((n2n3.length2() > btScalar(0.0001)) && (n3n1.length2() > btScalar(0.0001) ))
\r
155 btScalar quotient = (N1.dot(n2n3));
\r
156 if (btFabs(quotient) > btScalar(0.0001))
\r
158 btVector3 potentialVertex = (n2n3 * N1[3] + n3n1 * N2[3] + n1n2 * N3[3]) * (btScalar(-1.) / quotient);
\r
159 for (l=0; l<numPlanes; l++)
\r
161 const btVector3& NP = planes[l];
\r
162 if (btScalar(NP.dot(potentialVertex))+btScalar(NP[3]) > btScalar(0.000001))
\r
165 if (l == numPlanes)
\r
167 // vertex (three plane intersection) inside all planes
\r
168 verticesOut.push_back(potentialVertex);
\r
169 planeIndicesOut.insert(i);
\r
170 planeIndicesOut.insert(j);
\r
171 planeIndicesOut.insert(k);
\r
181 static btVector3 curVoronoiPoint; // Here for btAlignedObjectArray.quickSort pointCmp scope
\r
185 bool operator()(const btVector3& p1, const btVector3& p2) const
\r
187 float v1 = (p1-curVoronoiPoint).length2();
\r
188 float v2 = (p2-curVoronoiPoint).length2();
\r
189 bool result0 = v1 < v2;
\r
190 //bool result1 = ((btScalar)(p1-curVoronoiPoint).length2()) < ((btScalar)(p2-curVoronoiPoint).length2());
\r
191 //apparently result0 is not always result1, because extended precision used in registered is different from precision when values are stored in memory
\r
196 void VoronoiFractureDemo::voronoiBBShatter(const btAlignedObjectArray<btVector3>& points, const btVector3& bbmin, const btVector3& bbmax, const btQuaternion& bbq, const btVector3& bbt, btScalar matDensity) {
\r
197 // points define voronoi cells in world space (avoid duplicates)
\r
198 // bbmin & bbmax = bounding box min and max in local space
\r
199 // bbq & bbt = bounding box quaternion rotation and translation
\r
200 // matDensity = Material density for voronoi shard mass calculation
\r
201 btVector3 bbvx = quatRotate(bbq, btVector3(1.0, 0.0, 0.0));
\r
202 btVector3 bbvy = quatRotate(bbq, btVector3(0.0, 1.0, 0.0));
\r
203 btVector3 bbvz = quatRotate(bbq, btVector3(0.0, 0.0, 1.0));
\r
204 btQuaternion bbiq = bbq.inverse();
\r
205 btConvexHullComputer* convexHC = new btConvexHullComputer();
\r
206 btAlignedObjectArray<btVector3> vertices;
\r
207 btVector3 rbb, nrbb;
\r
208 btScalar nlength, maxDistance, distance;
\r
209 btAlignedObjectArray<btVector3> sortedVoronoiPoints;
\r
210 sortedVoronoiPoints.copyFromArray(points);
\r
211 btVector3 normal, plane;
\r
212 btAlignedObjectArray<btVector3> planes;
\r
213 std::set<int> planeIndices;
\r
214 std::set<int>::iterator planeIndicesIter;
\r
215 int numplaneIndices;
\r
219 int numpoints = points.size();
\r
220 for (i=0; i < numpoints ;i++) {
\r
221 curVoronoiPoint = points[i];
\r
222 btVector3 icp = quatRotate(bbiq, curVoronoiPoint - bbt);
\r
224 nrbb = bbmin - icp;
\r
226 planes[0] = bbvx; planes[0][3] = rbb.x();
\r
227 planes[1] = bbvy; planes[1][3] = rbb.y();
\r
228 planes[2] = bbvz; planes[2][3] = rbb.z();
\r
229 planes[3] = -bbvx; planes[3][3] = nrbb.x();
\r
230 planes[4] = -bbvy; planes[4][3] = nrbb.y();
\r
231 planes[5] = -bbvz; planes[5][3] = nrbb.z();
\r
232 maxDistance = SIMD_INFINITY;
\r
233 sortedVoronoiPoints.quickSort(pointCmp());
\r
234 for (j=1; j < numpoints; j++) {
\r
235 normal = sortedVoronoiPoints[j] - curVoronoiPoint;
\r
236 nlength = normal.length();
\r
237 if (nlength > maxDistance)
\r
239 plane = normal.normalized();
\r
240 plane[3] = -nlength / btScalar(2.);
\r
241 planes.push_back(plane);
\r
242 getVerticesInsidePlanes(planes, vertices, planeIndices);
\r
243 if (vertices.size() == 0)
\r
245 numplaneIndices = planeIndices.size();
\r
246 if (numplaneIndices != planes.size()) {
\r
247 planeIndicesIter = planeIndices.begin();
\r
248 for (k=0; k < numplaneIndices; k++) {
\r
249 if (k != *planeIndicesIter)
\r
250 planes[k] = planes[*planeIndicesIter];
\r
251 planeIndicesIter++;
\r
253 planes.resize(numplaneIndices);
\r
255 maxDistance = vertices[0].length();
\r
256 for (k=1; k < vertices.size(); k++) {
\r
257 distance = vertices[k].length();
\r
258 if (maxDistance < distance)
\r
259 maxDistance = distance;
\r
261 maxDistance *= btScalar(2.);
\r
263 if (vertices.size() == 0)
\r
266 // Clean-up voronoi convex shard vertices and generate edges & faces
\r
267 convexHC->compute(&vertices[0].getX(), sizeof(btVector3), vertices.size(),CONVEX_MARGIN,0.0);
\r
269 // At this point we have a complete 3D voronoi shard mesh contained in convexHC
\r
271 // Calculate volume and center of mass (Stan Melax volume integration)
\r
272 int numFaces = convexHC->faces.size();
\r
273 int v0, v1, v2; // Triangle vertices
\r
274 btScalar volume = btScalar(0.);
\r
275 btVector3 com(0., 0., 0.);
\r
276 for (j=0; j < numFaces; j++) {
\r
277 const btConvexHullComputer::Edge* edge = &convexHC->edges[convexHC->faces[j]];
\r
278 v0 = edge->getSourceVertex();
\r
279 v1 = edge->getTargetVertex();
\r
280 edge = edge->getNextEdgeOfFace();
\r
281 v2 = edge->getTargetVertex();
\r
283 // Counter-clockwise triangulated voronoi shard mesh faces (v0-v1-v2) and edges here...
\r
284 btScalar vol = convexHC->vertices[v0].triple(convexHC->vertices[v1], convexHC->vertices[v2]);
\r
286 com += vol * (convexHC->vertices[v0] + convexHC->vertices[v1] + convexHC->vertices[v2]);
\r
287 edge = edge->getNextEdgeOfFace();
\r
289 v2 = edge->getTargetVertex();
\r
292 com /= volume * btScalar(4.);
\r
293 volume /= btScalar(6.);
\r
295 // Shift all vertices relative to center of mass
\r
296 int numVerts = convexHC->vertices.size();
\r
297 for (j=0; j < numVerts; j++)
\r
299 convexHC->vertices[j] -= com;
\r
303 // At this point convex hulls contained in convexHC should be accurate (line up flush with other pieces, no cracks),
\r
304 // ...however Bullet Physics rigid bodies demo visualizations appear to produce some visible cracks.
\r
305 // Use the mesh in convexHC for visual display or to perform boolean operations with.
\r
307 // Create Bullet Physics rigid body shards
\r
308 btCollisionShape* shardShape = new btConvexHullShape(&(convexHC->vertices[0].getX()), convexHC->vertices.size());
\r
309 shardShape->setMargin(CONVEX_MARGIN); // for this demo; note convexHC has optional margin parameter for this
\r
310 m_collisionShapes.push_back(shardShape);
\r
311 btTransform shardTransform;
\r
312 shardTransform.setIdentity();
\r
313 shardTransform.setOrigin(curVoronoiPoint + com); // Shard's adjusted location
\r
314 btDefaultMotionState* shardMotionState = new btDefaultMotionState(shardTransform);
\r
315 btScalar shardMass(volume * matDensity);
\r
316 btVector3 shardInertia(0.,0.,0.);
\r
317 shardShape->calculateLocalInertia(shardMass, shardInertia);
\r
318 btRigidBody::btRigidBodyConstructionInfo shardRBInfo(shardMass, shardMotionState, shardShape, shardInertia);
\r
319 btRigidBody* shardBody = new btRigidBody(shardRBInfo);
\r
320 m_dynamicsWorld->addRigidBody(shardBody);
\r
325 printf("Generated %d voronoi btRigidBody shards\n", cellnum);
\r
328 void VoronoiFractureDemo::voronoiConvexHullShatter(const btAlignedObjectArray<btVector3>& points, const btAlignedObjectArray<btVector3>& verts, const btQuaternion& bbq, const btVector3& bbt, btScalar matDensity) {
\r
329 // points define voronoi cells in world space (avoid duplicates)
\r
330 // verts = source (convex hull) mesh vertices in local space
\r
331 // bbq & bbt = source (convex hull) mesh quaternion rotation and translation
\r
332 // matDensity = Material density for voronoi shard mass calculation
\r
333 btConvexHullComputer* convexHC = new btConvexHullComputer();
\r
334 btAlignedObjectArray<btVector3> vertices, chverts;
\r
335 btVector3 rbb, nrbb;
\r
336 btScalar nlength, maxDistance, distance;
\r
337 btAlignedObjectArray<btVector3> sortedVoronoiPoints;
\r
338 sortedVoronoiPoints.copyFromArray(points);
\r
339 btVector3 normal, plane;
\r
340 btAlignedObjectArray<btVector3> planes, convexPlanes;
\r
341 std::set<int> planeIndices;
\r
342 std::set<int>::iterator planeIndicesIter;
\r
343 int numplaneIndices;
\r
347 // Convert verts to world space and get convexPlanes
\r
348 int numverts = verts.size();
\r
349 chverts.resize(verts.size());
\r
350 for (i=0; i < numverts ;i++) {
\r
351 chverts[i] = quatRotate(bbq, verts[i]) + bbt;
\r
353 //btGeometryUtil::getPlaneEquationsFromVertices(chverts, convexPlanes);
\r
354 // Using convexHullComputer faster than getPlaneEquationsFromVertices for large meshes...
\r
355 convexHC->compute(&chverts[0].getX(), sizeof(btVector3), numverts, 0.0, 0.0);
\r
356 int numFaces = convexHC->faces.size();
\r
357 int v0, v1, v2; // vertices
\r
358 for (i=0; i < numFaces; i++) {
\r
359 const btConvexHullComputer::Edge* edge = &convexHC->edges[convexHC->faces[i]];
\r
360 v0 = edge->getSourceVertex();
\r
361 v1 = edge->getTargetVertex();
\r
362 edge = edge->getNextEdgeOfFace();
\r
363 v2 = edge->getTargetVertex();
\r
364 plane = (convexHC->vertices[v1]-convexHC->vertices[v0]).cross(convexHC->vertices[v2]-convexHC->vertices[v0]).normalize();
\r
365 plane[3] = -plane.dot(convexHC->vertices[v0]);
\r
366 convexPlanes.push_back(plane);
\r
368 const int numconvexPlanes = convexPlanes.size();
\r
370 int numpoints = points.size();
\r
371 for (i=0; i < numpoints ;i++) {
\r
372 curVoronoiPoint = points[i];
\r
373 planes.copyFromArray(convexPlanes);
\r
374 for (j=0; j < numconvexPlanes ;j++) {
\r
375 planes[j][3] += planes[j].dot(curVoronoiPoint);
\r
377 maxDistance = SIMD_INFINITY;
\r
378 sortedVoronoiPoints.quickSort(pointCmp());
\r
379 for (j=1; j < numpoints; j++) {
\r
380 normal = sortedVoronoiPoints[j] - curVoronoiPoint;
\r
381 nlength = normal.length();
\r
382 if (nlength > maxDistance)
\r
384 plane = normal.normalized();
\r
385 plane[3] = -nlength / btScalar(2.);
\r
386 planes.push_back(plane);
\r
387 getVerticesInsidePlanes(planes, vertices, planeIndices);
\r
388 if (vertices.size() == 0)
\r
390 numplaneIndices = planeIndices.size();
\r
391 if (numplaneIndices != planes.size()) {
\r
392 planeIndicesIter = planeIndices.begin();
\r
393 for (k=0; k < numplaneIndices; k++) {
\r
394 if (k != *planeIndicesIter)
\r
395 planes[k] = planes[*planeIndicesIter];
\r
396 planeIndicesIter++;
\r
398 planes.resize(numplaneIndices);
\r
400 maxDistance = vertices[0].length();
\r
401 for (k=1; k < vertices.size(); k++) {
\r
402 distance = vertices[k].length();
\r
403 if (maxDistance < distance)
\r
404 maxDistance = distance;
\r
406 maxDistance *= btScalar(2.);
\r
408 if (vertices.size() == 0)
\r
411 // Clean-up voronoi convex shard vertices and generate edges & faces
\r
412 convexHC->compute(&vertices[0].getX(), sizeof(btVector3), vertices.size(),0.0,0.0);
\r
414 // At this point we have a complete 3D voronoi shard mesh contained in convexHC
\r
416 // Calculate volume and center of mass (Stan Melax volume integration)
\r
417 numFaces = convexHC->faces.size();
\r
418 btScalar volume = btScalar(0.);
\r
419 btVector3 com(0., 0., 0.);
\r
420 for (j=0; j < numFaces; j++) {
\r
421 const btConvexHullComputer::Edge* edge = &convexHC->edges[convexHC->faces[j]];
\r
422 v0 = edge->getSourceVertex();
\r
423 v1 = edge->getTargetVertex();
\r
424 edge = edge->getNextEdgeOfFace();
\r
425 v2 = edge->getTargetVertex();
\r
427 // Counter-clockwise triangulated voronoi shard mesh faces (v0-v1-v2) and edges here...
\r
428 btScalar vol = convexHC->vertices[v0].triple(convexHC->vertices[v1], convexHC->vertices[v2]);
\r
430 com += vol * (convexHC->vertices[v0] + convexHC->vertices[v1] + convexHC->vertices[v2]);
\r
431 edge = edge->getNextEdgeOfFace();
\r
433 v2 = edge->getTargetVertex();
\r
436 com /= volume * btScalar(4.);
\r
437 volume /= btScalar(6.);
\r
439 // Shift all vertices relative to center of mass
\r
440 int numVerts = convexHC->vertices.size();
\r
441 for (j=0; j < numVerts; j++)
\r
443 convexHC->vertices[j] -= com;
\r
447 // At this point convex hulls contained in convexHC should be accurate (line up flush with other pieces, no cracks),
\r
448 // ...however Bullet Physics rigid bodies demo visualizations appear to produce some visible cracks.
\r
449 // Use the mesh in convexHC for visual display or to perform boolean operations with.
\r
451 // Create Bullet Physics rigid body shards
\r
452 btCollisionShape* shardShape = new btConvexHullShape(&(convexHC->vertices[0].getX()), convexHC->vertices.size());
\r
453 shardShape->setMargin(CONVEX_MARGIN); // for this demo; note convexHC has optional margin parameter for this
\r
454 m_collisionShapes.push_back(shardShape);
\r
455 btTransform shardTransform;
\r
456 shardTransform.setIdentity();
\r
457 shardTransform.setOrigin(curVoronoiPoint + com); // Shard's adjusted location
\r
458 btDefaultMotionState* shardMotionState = new btDefaultMotionState(shardTransform);
\r
459 btScalar shardMass(volume * matDensity);
\r
460 btVector3 shardInertia(0.,0.,0.);
\r
461 shardShape->calculateLocalInertia(shardMass, shardInertia);
\r
462 btRigidBody::btRigidBodyConstructionInfo shardRBInfo(shardMass, shardMotionState, shardShape, shardInertia);
\r
463 btRigidBody* shardBody = new btRigidBody(shardRBInfo);
\r
464 m_dynamicsWorld->addRigidBody(shardBody);
\r
469 printf("Generated %d voronoi btRigidBody shards\n", cellnum);
\r
472 void VoronoiFractureDemo::clientMoveAndDisplay()
\r
474 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
\r
476 //simple dynamics world doesn't handle fixed-time-stepping
\r
477 float ms = getDeltaTimeMicroseconds();
\r
479 ///step the simulation
\r
480 if (m_dynamicsWorld)
\r
482 m_dynamicsWorld->stepSimulation(ms / 1000000.f);
\r
483 //optional but useful: debug drawing
\r
484 m_dynamicsWorld->debugDrawWorld();
\r
495 void VoronoiFractureDemo::displayCallback(void) {
\r
497 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
\r
501 //optional but useful: debug drawing to detect problems
\r
502 if (m_dynamicsWorld)
\r
503 m_dynamicsWorld->debugDrawWorld();
\r
510 void VoronoiFractureDemo::initPhysics()
\r
512 setTexturing(true);
\r
515 setCameraDistance(btScalar(20.));
\r
517 ///collision configuration contains default setup for memory, collision setup
\r
518 m_collisionConfiguration = new btDefaultCollisionConfiguration();
\r
519 //m_collisionConfiguration->setConvexConvexMultipointIterations();
\r
521 ///use the default collision dispatcher. For parallel processing you can use a diffent dispatcher (see Extras/BulletMultiThreaded)
\r
522 m_dispatcher = new btCollisionDispatcher(m_collisionConfiguration);
\r
524 m_broadphase = new btDbvtBroadphase();
\r
526 ///the default constraint solver. For parallel processing you can use a different solver (see Extras/BulletMultiThreaded)
\r
527 btSequentialImpulseConstraintSolver* sol = new btSequentialImpulseConstraintSolver;
\r
530 m_dynamicsWorld = new btDiscreteDynamicsWorld(m_dispatcher,m_broadphase,m_solver,m_collisionConfiguration);
\r
531 m_dynamicsWorld->getSolverInfo().m_splitImpulse = true;
\r
532 m_dynamicsWorld->setDebugDrawer(&sDebugDraw);
\r
534 m_dynamicsWorld->setGravity(btVector3(0,-10,0));
\r
536 ///create a few basic rigid bodies
\r
537 btCollisionShape* groundShape = new btBoxShape(btVector3(btScalar(50.),btScalar(50.),btScalar(50.)));
\r
538 // btCollisionShape* groundShape = new btStaticPlaneShape(btVector3(0,1,0),50);
\r
540 m_collisionShapes.push_back(groundShape);
\r
542 btTransform groundTransform;
\r
543 groundTransform.setIdentity();
\r
544 groundTransform.setOrigin(btVector3(0,-50,0));
\r
546 //We can also use DemoApplication::localCreateRigidBody, but for clarity it is provided here:
\r
550 //rigidbody is dynamic if and only if mass is non zero, otherwise static
\r
551 bool isDynamic = (mass != 0.f);
\r
553 btVector3 localInertia(0,0,0);
\r
555 groundShape->calculateLocalInertia(mass,localInertia);
\r
557 //using motionstate is recommended, it provides interpolation capabilities, and only synchronizes 'active' objects
\r
558 btDefaultMotionState* myMotionState = new btDefaultMotionState(groundTransform);
\r
559 btRigidBody::btRigidBodyConstructionInfo rbInfo(mass,myMotionState,groundShape,localInertia);
\r
560 btRigidBody* body = new btRigidBody(rbInfo);
\r
562 //add the body to the dynamics world
\r
563 m_dynamicsWorld->addRigidBody(body);
\r
566 // ==> Voronoi Shatter Basic Demo: Random Cuboid
\r
568 // Random size cuboid (defined by bounding box max and min)
\r
569 btVector3 bbmax(btScalar(rand() / btScalar(RAND_MAX)) * 6. +0.5, btScalar(rand() / btScalar(RAND_MAX)) * 6. +0.5, btScalar(rand() / btScalar(RAND_MAX)) * 6. +0.5);
\r
570 btVector3 bbmin = -bbmax;
\r
571 // Place it 10 units above ground
\r
572 btVector3 bbt(0,10,0);
\r
573 // Use an arbitrary material density for shards (should be consitent/relative with/to rest of RBs in world)
\r
574 btScalar matDensity = 1;
\r
575 // Using random rotation
\r
576 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.);
\r
578 // Generate random points for voronoi cells
\r
579 btAlignedObjectArray<btVector3> points;
\r
581 btVector3 diff = bbmax - bbmin;
\r
582 for (int i=0; i < VORONOIPOINTS; i++) {
\r
583 // Place points within box area (points are in world coordinates)
\r
584 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;
\r
585 points.push_back(point);
\r
587 m_perfmTimer.reset();
\r
588 voronoiBBShatter(points, bbmin, bbmax, bbq, bbt, matDensity);
\r
589 printf("Total Time: %f seconds\n", m_perfmTimer.getTimeMilliseconds()/1000.);
\r
591 for (int i=m_dynamicsWorld->getNumCollisionObjects()-1; i>=0 ;i--)
\r
593 btCollisionObject* obj = m_dynamicsWorld->getCollisionObjectArray()[i];
\r
594 obj->getCollisionShape()->setMargin(CONVEX_MARGIN+0.01);
\r
596 m_dynamicsWorld->performDiscreteCollisionDetection();
\r
598 for (int i=m_dynamicsWorld->getNumCollisionObjects()-1; i>=0 ;i--)
\r
600 btCollisionObject* obj = m_dynamicsWorld->getCollisionObjectArray()[i];
\r
601 obj->getCollisionShape()->setMargin(CONVEX_MARGIN);
\r
604 attachFixedConstraints();
\r
607 void VoronoiFractureDemo::clientResetScene()
\r
614 void VoronoiFractureDemo::exitPhysics()
\r
617 //cleanup in the reverse order of creation/initialization
\r
620 //remove all constraints
\r
621 for (i=m_dynamicsWorld->getNumConstraints()-1;i>=0;i--)
\r
623 btTypedConstraint* constraint = m_dynamicsWorld->getConstraint(i);
\r
624 m_dynamicsWorld->removeConstraint(constraint);
\r
628 //remove the rigidbodies from the dynamics world and delete them
\r
630 for (i=m_dynamicsWorld->getNumCollisionObjects()-1; i>=0 ;i--)
\r
632 btCollisionObject* obj = m_dynamicsWorld->getCollisionObjectArray()[i];
\r
633 btRigidBody* body = btRigidBody::upcast(obj);
\r
634 if (body && body->getMotionState())
\r
636 delete body->getMotionState();
\r
638 m_dynamicsWorld->removeCollisionObject( obj );
\r
642 //delete collision shapes
\r
643 for (int j=0;j<m_collisionShapes.size();j++)
\r
645 btCollisionShape* shape = m_collisionShapes[j];
\r
648 m_collisionShapes.clear();
\r
650 delete m_dynamicsWorld;
\r
654 delete m_broadphase;
\r
656 delete m_dispatcher;
\r
658 delete m_collisionConfiguration;
\r