btFractureDynamicsWorld.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688
  1. #include "btFractureDynamicsWorld.h"
  2. #include "btFractureBody.h"
  3. #include "BulletCollision/CollisionShapes/btCompoundShape.h"
  4. #include "BulletCollision/CollisionDispatch/btUnionFind.h"
  5. btFractureDynamicsWorld::btFractureDynamicsWorld ( btDispatcher* dispatcher,btBroadphaseInterface* pairCache,btConstraintSolver* constraintSolver,btCollisionConfiguration* collisionConfiguration)
  6. :btDiscreteDynamicsWorld(dispatcher,pairCache,constraintSolver,collisionConfiguration),
  7. m_fracturingMode(true)
  8. {
  9. }
  10. void btFractureDynamicsWorld::glueCallback()
  11. {
  12. int numManifolds = getDispatcher()->getNumManifolds();
  13. ///first build the islands based on axis aligned bounding box overlap
  14. btUnionFind unionFind;
  15. int index = 0;
  16. {
  17. int i;
  18. for (i=0;i<getCollisionObjectArray().size(); i++)
  19. {
  20. btCollisionObject* collisionObject= getCollisionObjectArray()[i];
  21. // btRigidBody* body = btRigidBody::upcast(collisionObject);
  22. //Adding filtering here
  23. #ifdef STATIC_SIMULATION_ISLAND_OPTIMIZATION
  24. if (!collisionObject->isStaticOrKinematicObject())
  25. {
  26. collisionObject->setIslandTag(index++);
  27. } else
  28. {
  29. collisionObject->setIslandTag(-1);
  30. }
  31. #else
  32. collisionObject->setIslandTag(i);
  33. index=i+1;
  34. #endif
  35. }
  36. }
  37. unionFind.reset(index);
  38. int numElem = unionFind.getNumElements();
  39. for (int i=0;i<numManifolds;i++)
  40. {
  41. btPersistentManifold* manifold = getDispatcher()->getManifoldByIndexInternal(i);
  42. if (!manifold->getNumContacts())
  43. continue;
  44. btScalar minDist = 1e30f;
  45. for (int v=0;v<manifold->getNumContacts();v++)
  46. {
  47. minDist = btMin(minDist,manifold->getContactPoint(v).getDistance());
  48. }
  49. if (minDist>0.)
  50. continue;
  51. btCollisionObject* colObj0 = (btCollisionObject*)manifold->getBody0();
  52. btCollisionObject* colObj1 = (btCollisionObject*)manifold->getBody1();
  53. int tag0 = (colObj0)->getIslandTag();
  54. int tag1 = (colObj1)->getIslandTag();
  55. //btRigidBody* body0 = btRigidBody::upcast(colObj0);
  56. //btRigidBody* body1 = btRigidBody::upcast(colObj1);
  57. if (!colObj0->isStaticOrKinematicObject() && !colObj1->isStaticOrKinematicObject())
  58. {
  59. unionFind.unite(tag0, tag1);
  60. }
  61. }
  62. numElem = unionFind.getNumElements();
  63. index=0;
  64. for (int ai=0;ai<getCollisionObjectArray().size();ai++)
  65. {
  66. btCollisionObject* collisionObject= getCollisionObjectArray()[ai];
  67. if (!collisionObject->isStaticOrKinematicObject())
  68. {
  69. int tag = unionFind.find(index);
  70. collisionObject->setIslandTag( tag);
  71. //Set the correct object offset in Collision Object Array
  72. #if STATIC_SIMULATION_ISLAND_OPTIMIZATION
  73. unionFind.getElement(index).m_sz = ai;
  74. #endif //STATIC_SIMULATION_ISLAND_OPTIMIZATION
  75. index++;
  76. }
  77. }
  78. unionFind.sortIslands();
  79. int endIslandIndex=1;
  80. int startIslandIndex;
  81. btAlignedObjectArray<btCollisionObject*> removedObjects;
  82. ///iterate over all islands
  83. for ( startIslandIndex=0;startIslandIndex<numElem;startIslandIndex = endIslandIndex)
  84. {
  85. int islandId = unionFind.getElement(startIslandIndex).m_id;
  86. for (endIslandIndex = startIslandIndex+1;(endIslandIndex<numElem) && (unionFind.getElement(endIslandIndex).m_id == islandId);endIslandIndex++)
  87. {
  88. }
  89. int fractureObjectIndex = -1;
  90. int numObjects=0;
  91. int idx;
  92. for (idx=startIslandIndex;idx<endIslandIndex;idx++)
  93. {
  94. int i = unionFind.getElement(idx).m_sz;
  95. btCollisionObject* colObj0 = getCollisionObjectArray()[i];
  96. if (colObj0->getInternalType()& CUSTOM_FRACTURE_TYPE)
  97. {
  98. fractureObjectIndex = i;
  99. }
  100. btRigidBody* otherObject = btRigidBody::upcast(colObj0);
  101. if (!otherObject || !otherObject->getInvMass())
  102. continue;
  103. numObjects++;
  104. }
  105. ///Then for each island that contains at least two objects and one fracture object
  106. if (fractureObjectIndex>=0 && numObjects>1)
  107. {
  108. btFractureBody* fracObj = (btFractureBody*)getCollisionObjectArray()[fractureObjectIndex];
  109. ///glueing objects means creating a new compound and removing the old objects
  110. ///delay the removal of old objects to avoid array indexing problems
  111. removedObjects.push_back(fracObj);
  112. m_fractureBodies.remove(fracObj);
  113. btAlignedObjectArray<btScalar> massArray;
  114. btAlignedObjectArray<btVector3> oldImpulses;
  115. btAlignedObjectArray<btVector3> oldCenterOfMassesWS;
  116. oldImpulses.push_back(fracObj->getLinearVelocity()/1./fracObj->getInvMass());
  117. oldCenterOfMassesWS.push_back(fracObj->getCenterOfMassPosition());
  118. btScalar totalMass = 0.f;
  119. btCompoundShape* compound = new btCompoundShape();
  120. if (fracObj->getCollisionShape()->isCompound())
  121. {
  122. btTransform tr;
  123. tr.setIdentity();
  124. btCompoundShape* oldCompound = (btCompoundShape*)fracObj->getCollisionShape();
  125. for (int c=0;c<oldCompound->getNumChildShapes();c++)
  126. {
  127. compound->addChildShape(oldCompound->getChildTransform(c),oldCompound->getChildShape(c));
  128. massArray.push_back(fracObj->m_masses[c]);
  129. totalMass+=fracObj->m_masses[c];
  130. }
  131. } else
  132. {
  133. btTransform tr;
  134. tr.setIdentity();
  135. compound->addChildShape(tr,fracObj->getCollisionShape());
  136. massArray.push_back(fracObj->m_masses[0]);
  137. totalMass+=fracObj->m_masses[0];
  138. }
  139. for (idx=startIslandIndex;idx<endIslandIndex;idx++)
  140. {
  141. int i = unionFind.getElement(idx).m_sz;
  142. if (i==fractureObjectIndex)
  143. continue;
  144. btCollisionObject* otherCollider = getCollisionObjectArray()[i];
  145. btRigidBody* otherObject = btRigidBody::upcast(otherCollider);
  146. //don't glue/merge with static objects right now, otherwise everything gets stuck to the ground
  147. ///todo: expose this as a callback
  148. if (!otherObject || !otherObject->getInvMass())
  149. continue;
  150. oldImpulses.push_back(otherObject->getLinearVelocity()*(1.f/otherObject->getInvMass()));
  151. oldCenterOfMassesWS.push_back(otherObject->getCenterOfMassPosition());
  152. removedObjects.push_back(otherObject);
  153. m_fractureBodies.remove((btFractureBody*)otherObject);
  154. btScalar curMass = 1.f/otherObject->getInvMass();
  155. if (otherObject->getCollisionShape()->isCompound())
  156. {
  157. btTransform tr;
  158. btCompoundShape* oldCompound = (btCompoundShape*)otherObject->getCollisionShape();
  159. for (int c=0;c<oldCompound->getNumChildShapes();c++)
  160. {
  161. tr = fracObj->getWorldTransform().inverseTimes(otherObject->getWorldTransform()*oldCompound->getChildTransform(c));
  162. compound->addChildShape(tr,oldCompound->getChildShape(c));
  163. massArray.push_back(curMass/(btScalar)oldCompound->getNumChildShapes());
  164. }
  165. } else
  166. {
  167. btTransform tr;
  168. tr = fracObj->getWorldTransform().inverseTimes(otherObject->getWorldTransform());
  169. compound->addChildShape(tr,otherObject->getCollisionShape());
  170. massArray.push_back(curMass);
  171. }
  172. totalMass+=curMass;
  173. }
  174. btTransform shift;
  175. shift.setIdentity();
  176. btCompoundShape* newCompound = btFractureBody::shiftTransformDistributeMass(compound,totalMass,shift);
  177. int numChildren = newCompound->getNumChildShapes();
  178. btAssert(numChildren == massArray.size());
  179. btVector3 localInertia;
  180. newCompound->calculateLocalInertia(totalMass,localInertia);
  181. btFractureBody* newBody = new btFractureBody(totalMass,0,newCompound,localInertia, &massArray[0], numChildren,this);
  182. newBody->recomputeConnectivity(this);
  183. newBody->setWorldTransform(fracObj->getWorldTransform()*shift);
  184. //now the linear/angular velocity is still zero, apply the impulses
  185. for (int i=0;i<oldImpulses.size();i++)
  186. {
  187. btVector3 rel_pos = oldCenterOfMassesWS[i]-newBody->getCenterOfMassPosition();
  188. const btVector3& imp = oldImpulses[i];
  189. newBody->applyImpulse(imp, rel_pos);
  190. }
  191. addRigidBody(newBody);
  192. }
  193. }
  194. //remove the objects from the world at the very end,
  195. //otherwise the island tags would not match the world collision object array indices anymore
  196. while (removedObjects.size())
  197. {
  198. btCollisionObject* otherCollider = removedObjects[removedObjects.size()-1];
  199. removedObjects.pop_back();
  200. btRigidBody* otherObject = btRigidBody::upcast(otherCollider);
  201. if (!otherObject || !otherObject->getInvMass())
  202. continue;
  203. removeRigidBody(otherObject);
  204. }
  205. }
  206. struct btFracturePair
  207. {
  208. btFractureBody* m_fracObj;
  209. btAlignedObjectArray<btPersistentManifold*> m_contactManifolds;
  210. };
  211. void btFractureDynamicsWorld::solveConstraints(btContactSolverInfo& solverInfo)
  212. {
  213. // todo: after fracture we should run the solver again for better realism
  214. // for example
  215. // save all velocities and if one or more objects fracture:
  216. // 1) revert all velocties
  217. // 2) apply impulses for the fracture bodies at the contact locations
  218. // 3)and run the constaint solver again
  219. btDiscreteDynamicsWorld::solveConstraints(solverInfo);
  220. fractureCallback();
  221. }
  222. btFractureBody* btFractureDynamicsWorld::addNewBody(const btTransform& oldTransform,btScalar* masses, btCompoundShape* oldCompound)
  223. {
  224. int i;
  225. btTransform shift;
  226. shift.setIdentity();
  227. btVector3 localInertia;
  228. btCompoundShape* newCompound = btFractureBody::shiftTransform(oldCompound,masses,shift,localInertia);
  229. btScalar totalMass = 0;
  230. for (i=0;i<newCompound->getNumChildShapes();i++)
  231. totalMass += masses[i];
  232. //newCompound->calculateLocalInertia(totalMass,localInertia);
  233. btFractureBody* newBody = new btFractureBody(totalMass,0,newCompound,localInertia, masses,newCompound->getNumChildShapes(), this);
  234. newBody->recomputeConnectivity(this);
  235. newBody->setCollisionFlags(newBody->getCollisionFlags()|btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK);
  236. newBody->setWorldTransform(oldTransform*shift);
  237. addRigidBody(newBody);
  238. return newBody;
  239. }
  240. void btFractureDynamicsWorld::addRigidBody(btRigidBody* body)
  241. {
  242. if (body->getInternalType() & CUSTOM_FRACTURE_TYPE)
  243. {
  244. btFractureBody* fbody = (btFractureBody*)body;
  245. m_fractureBodies.push_back(fbody);
  246. }
  247. btDiscreteDynamicsWorld::addRigidBody(body);
  248. }
  249. void btFractureDynamicsWorld::removeRigidBody(btRigidBody* body)
  250. {
  251. if (body->getInternalType() & CUSTOM_FRACTURE_TYPE)
  252. {
  253. btFractureBody* fbody = (btFractureBody*)body;
  254. btAlignedObjectArray<btTypedConstraint*> tmpConstraints;
  255. for (int i=0;i<fbody->getNumConstraintRefs();i++)
  256. {
  257. tmpConstraints.push_back(fbody->getConstraintRef(i));
  258. }
  259. //remove all constraints attached to this rigid body too
  260. for (int i=0;i<tmpConstraints.size();i++)
  261. btDiscreteDynamicsWorld::removeConstraint(tmpConstraints[i]);
  262. m_fractureBodies.remove(fbody);
  263. }
  264. btDiscreteDynamicsWorld::removeRigidBody(body);
  265. }
  266. void btFractureDynamicsWorld::breakDisconnectedParts( btFractureBody* fracObj)
  267. {
  268. if (!fracObj->getCollisionShape()->isCompound())
  269. return;
  270. btCompoundShape* compound = (btCompoundShape*)fracObj->getCollisionShape();
  271. int numChildren = compound->getNumChildShapes();
  272. if (numChildren<=1)
  273. return;
  274. //compute connectivity
  275. btUnionFind unionFind;
  276. btAlignedObjectArray<int> tags;
  277. tags.resize(numChildren);
  278. int i, index = 0;
  279. for ( i=0;i<numChildren;i++)
  280. {
  281. #ifdef STATIC_SIMULATION_ISLAND_OPTIMIZATION
  282. tags[i] = index++;
  283. #else
  284. tags[i] = i;
  285. index=i+1;
  286. #endif
  287. }
  288. unionFind.reset(index);
  289. int numElem = unionFind.getNumElements();
  290. for (i=0;i<fracObj->m_connections.size();i++)
  291. {
  292. btConnection& connection = fracObj->m_connections[i];
  293. if (connection.m_strength > 0.)
  294. {
  295. int tag0 = tags[connection.m_childIndex0];
  296. int tag1 = tags[connection.m_childIndex1];
  297. unionFind.unite(tag0, tag1);
  298. }
  299. }
  300. numElem = unionFind.getNumElements();
  301. index=0;
  302. for (int ai=0;ai<numChildren;ai++)
  303. {
  304. int tag = unionFind.find(index);
  305. tags[ai] = tag;
  306. //Set the correct object offset in Collision Object Array
  307. #if STATIC_SIMULATION_ISLAND_OPTIMIZATION
  308. unionFind.getElement(index).m_sz = ai;
  309. #endif //STATIC_SIMULATION_ISLAND_OPTIMIZATION
  310. index++;
  311. }
  312. unionFind.sortIslands();
  313. int endIslandIndex=1;
  314. int startIslandIndex;
  315. btAlignedObjectArray<btCollisionObject*> removedObjects;
  316. int numIslands = 0;
  317. for ( startIslandIndex=0;startIslandIndex<numElem;startIslandIndex = endIslandIndex)
  318. {
  319. int islandId = unionFind.getElement(startIslandIndex).m_id;
  320. for (endIslandIndex = startIslandIndex+1;(endIslandIndex<numElem) && (unionFind.getElement(endIslandIndex).m_id == islandId);endIslandIndex++)
  321. {
  322. }
  323. // int fractureObjectIndex = -1;
  324. int numShapes=0;
  325. btCompoundShape* newCompound = new btCompoundShape();
  326. btAlignedObjectArray<btScalar> masses;
  327. int idx;
  328. for (idx=startIslandIndex;idx<endIslandIndex;idx++)
  329. {
  330. int i = unionFind.getElement(idx).m_sz;
  331. // btCollisionShape* shape = compound->getChildShape(i);
  332. newCompound->addChildShape(compound->getChildTransform(i),compound->getChildShape(i));
  333. masses.push_back(fracObj->m_masses[i]);
  334. numShapes++;
  335. }
  336. if (numShapes)
  337. {
  338. btFractureBody* newBody = addNewBody(fracObj->getWorldTransform(),&masses[0],newCompound);
  339. newBody->setLinearVelocity(fracObj->getLinearVelocity());
  340. newBody->setAngularVelocity(fracObj->getAngularVelocity());
  341. numIslands++;
  342. }
  343. }
  344. removeRigidBody(fracObj);//should it also be removed from the array?
  345. }
  346. #include <stdio.h>
  347. void btFractureDynamicsWorld::fractureCallback( )
  348. {
  349. btAlignedObjectArray<btFracturePair> sFracturePairs;
  350. if (!m_fracturingMode)
  351. {
  352. glueCallback();
  353. return;
  354. }
  355. int numManifolds = getDispatcher()->getNumManifolds();
  356. sFracturePairs.clear();
  357. for (int i=0;i<numManifolds;i++)
  358. {
  359. btPersistentManifold* manifold = getDispatcher()->getManifoldByIndexInternal(i);
  360. if (!manifold->getNumContacts())
  361. continue;
  362. btScalar totalImpact = 0.f;
  363. for (int p=0;p<manifold->getNumContacts();p++)
  364. {
  365. totalImpact += manifold->getContactPoint(p).m_appliedImpulse;
  366. }
  367. // printf("totalImpact=%f\n",totalImpact);
  368. static float maxImpact = 0;
  369. if (totalImpact>maxImpact)
  370. maxImpact = totalImpact;
  371. //some threshold otherwise resting contact would break objects after a while
  372. if (totalImpact < 40.f)
  373. continue;
  374. // printf("strong impact\n");
  375. //@todo: add better logic to decide what parts to fracture
  376. //For example use the idea from the SIGGRAPH talk about the fracture in the movie 2012:
  377. //
  378. //Breaking thresholds can be stored as connectivity information between child shapes in the fracture object
  379. //
  380. //You can calculate some "impact value" by simulating all the individual child shapes
  381. //as rigid bodies, without constraints, running it in a separate simulation world
  382. //(or by running the constraint solver without actually modifying the dynamics world)
  383. //Then measure some "impact value" using the offset and applied impulse for each child shape
  384. //weaken the connections based on this "impact value" and only break
  385. //if this impact value exceeds the breaking threshold.
  386. //you can propagate the weakening and breaking of connections using the connectivity information
  387. int f0 = m_fractureBodies.findLinearSearch((btFractureBody*)manifold->getBody0());
  388. int f1 = m_fractureBodies.findLinearSearch((btFractureBody*)manifold->getBody1());
  389. if (f0 == f1 == m_fractureBodies.size())
  390. continue;
  391. if (f0<m_fractureBodies.size())
  392. {
  393. int j=f0;
  394. btCollisionObject* colOb = (btCollisionObject*)manifold->getBody1();
  395. // btRigidBody* otherOb = btRigidBody::upcast(colOb);
  396. // if (!otherOb->getInvMass())
  397. // continue;
  398. int pi=-1;
  399. for (int p=0;p<sFracturePairs.size();p++)
  400. {
  401. if (sFracturePairs[p].m_fracObj == m_fractureBodies[j])
  402. {
  403. pi = p; break;
  404. }
  405. }
  406. if (pi<0)
  407. {
  408. btFracturePair p;
  409. p.m_fracObj = m_fractureBodies[j];
  410. p.m_contactManifolds.push_back(manifold);
  411. sFracturePairs.push_back(p);
  412. } else
  413. {
  414. btAssert(sFracturePairs[pi].m_contactManifolds.findLinearSearch(manifold)==sFracturePairs[pi].m_contactManifolds.size());
  415. sFracturePairs[pi].m_contactManifolds.push_back(manifold);
  416. }
  417. }
  418. if (f1 < m_fractureBodies.size())
  419. {
  420. int j=f1;
  421. {
  422. btCollisionObject* colOb = (btCollisionObject*)manifold->getBody0();
  423. btRigidBody* otherOb = btRigidBody::upcast(colOb);
  424. // if (!otherOb->getInvMass())
  425. // continue;
  426. int pi=-1;
  427. for (int p=0;p<sFracturePairs.size();p++)
  428. {
  429. if (sFracturePairs[p].m_fracObj == m_fractureBodies[j])
  430. {
  431. pi = p; break;
  432. }
  433. }
  434. if (pi<0)
  435. {
  436. btFracturePair p;
  437. p.m_fracObj = m_fractureBodies[j];
  438. p.m_contactManifolds.push_back( manifold);
  439. sFracturePairs.push_back(p);
  440. } else
  441. {
  442. btAssert(sFracturePairs[pi].m_contactManifolds.findLinearSearch(manifold)==sFracturePairs[pi].m_contactManifolds.size());
  443. sFracturePairs[pi].m_contactManifolds.push_back(manifold);
  444. }
  445. }
  446. }
  447. //
  448. }
  449. //printf("m_fractureBodies size=%d\n",m_fractureBodies.size());
  450. //printf("sFracturePairs size=%d\n",sFracturePairs.size());
  451. if (!sFracturePairs.size())
  452. return;
  453. {
  454. // printf("fracturing\n");
  455. for (int i=0;i<sFracturePairs.size();i++)
  456. {
  457. //check impulse/displacement at impact
  458. //weaken/break connections (and propagate breaking)
  459. //compute connectivity of connected child shapes
  460. if (sFracturePairs[i].m_fracObj->getCollisionShape()->isCompound())
  461. {
  462. btTransform tr;
  463. tr.setIdentity();
  464. btCompoundShape* oldCompound = (btCompoundShape*)sFracturePairs[i].m_fracObj->getCollisionShape();
  465. if (oldCompound->getNumChildShapes()>1)
  466. {
  467. bool needsBreakingCheck = false;
  468. //weaken/break the connections
  469. //@todo: propagate along the connection graph
  470. for (int j=0;j<sFracturePairs[i].m_contactManifolds.size();j++)
  471. {
  472. btPersistentManifold* manifold = sFracturePairs[i].m_contactManifolds[j];
  473. for (int k=0;k<manifold->getNumContacts();k++)
  474. {
  475. btManifoldPoint& pt = manifold->getContactPoint(k);
  476. if (manifold->getBody0()==sFracturePairs[i].m_fracObj)
  477. {
  478. for (int f=0;f<sFracturePairs[i].m_fracObj->m_connections.size();f++)
  479. {
  480. btConnection& connection = sFracturePairs[i].m_fracObj->m_connections[f];
  481. if ( (connection.m_childIndex0 == pt.m_index0) ||
  482. (connection.m_childIndex1 == pt.m_index0)
  483. )
  484. {
  485. connection.m_strength -= pt.m_appliedImpulse;
  486. if (connection.m_strength<0)
  487. {
  488. //remove or set to zero
  489. connection.m_strength=0.f;
  490. needsBreakingCheck = true;
  491. }
  492. }
  493. }
  494. } else
  495. {
  496. for (int f=0;f<sFracturePairs[i].m_fracObj->m_connections.size();f++)
  497. {
  498. btConnection& connection = sFracturePairs[i].m_fracObj->m_connections[f];
  499. if ( (connection.m_childIndex0 == pt.m_index1) ||
  500. (connection.m_childIndex1 == pt.m_index1)
  501. )
  502. {
  503. connection.m_strength -= pt.m_appliedImpulse;
  504. if (connection.m_strength<0)
  505. {
  506. //remove or set to zero
  507. connection.m_strength=0.f;
  508. needsBreakingCheck = true;
  509. }
  510. }
  511. }
  512. }
  513. }
  514. }
  515. if (needsBreakingCheck)
  516. {
  517. breakDisconnectedParts(sFracturePairs[i].m_fracObj);
  518. }
  519. }
  520. }
  521. }
  522. }
  523. sFracturePairs.clear();
  524. }