2 Bullet Continuous Collision Detection and Physics Library
3 Copyright (c) 2018 Google Inc. http://bulletphysics.org
5 This software is provided 'as-is', without any express or implied warranty.
6 In no event will the authors be held liable for any damages arising from the use of this software.
7 Permission is granted to anyone to use this software for any purpose,
8 including commercial applications, and to alter it and redistribute it freely,
9 subject to the following restrictions:
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.
12 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13 3. This notice may not be removed or altered from any source distribution.
16 #include "BulletDynamics/Featherstone/btMultiBodyMLCPConstraintSolver.h"
18 #include "BulletCollision/NarrowPhaseCollision/btPersistentManifold.h"
19 #include "BulletDynamics/Featherstone/btMultiBodyLinkCollider.h"
20 #include "BulletDynamics/Featherstone/btMultiBodyConstraint.h"
21 #include "BulletDynamics/MLCPSolvers/btMLCPSolverInterface.h"
23 #define DIRECTLY_UPDATE_VELOCITY_DURING_SOLVER_ITERATIONS
25 static bool interleaveContactAndFriction1 = false;
29 int jointIndex; // pointer to enclosing dxJoint object
30 int otherBodyIndex; // *other* body this joint is connected to
31 int nextJointNodeIndex; //-1 for null
32 int constraintRowIndex;
35 // Helper function to compute a delta velocity in the constraint space.
36 static btScalar computeDeltaVelocityInConstraintSpace(
37 const btVector3& angularDeltaVelocity,
38 const btVector3& contactNormal,
40 const btVector3& angularJacobian,
41 const btVector3& linearJacobian)
43 return angularDeltaVelocity.dot(angularJacobian) + contactNormal.dot(linearJacobian) * invMass;
46 // Faster version of computeDeltaVelocityInConstraintSpace that can be used when contactNormal and linearJacobian are
48 static btScalar computeDeltaVelocityInConstraintSpace(
49 const btVector3& angularDeltaVelocity,
51 const btVector3& angularJacobian)
53 return angularDeltaVelocity.dot(angularJacobian) + invMass;
56 // Helper function to compute a delta velocity in the constraint space.
57 static btScalar computeDeltaVelocityInConstraintSpace(const btScalar* deltaVelocity, const btScalar* jacobian, int size)
60 for (int i = 0; i < size; ++i)
61 result += deltaVelocity[i] * jacobian[i];
66 static btScalar computeConstraintMatrixDiagElementMultiBody(
67 const btAlignedObjectArray<btSolverBody>& solverBodyPool,
68 const btMultiBodyJacobianData& data,
69 const btMultiBodySolverConstraint& constraint)
73 const btMultiBody* multiBodyA = constraint.m_multiBodyA;
74 const btMultiBody* multiBodyB = constraint.m_multiBodyB;
78 const btScalar* jacA = &data.m_jacobians[constraint.m_jacAindex];
79 const btScalar* deltaA = &data.m_deltaVelocitiesUnitImpulse[constraint.m_jacAindex];
80 const int ndofA = multiBodyA->getNumDofs() + 6;
81 ret += computeDeltaVelocityInConstraintSpace(deltaA, jacA, ndofA);
85 const int solverBodyIdA = constraint.m_solverBodyIdA;
86 btAssert(solverBodyIdA != -1);
87 const btSolverBody* solverBodyA = &solverBodyPool[solverBodyIdA];
88 const btScalar invMassA = solverBodyA->m_originalBody ? solverBodyA->m_originalBody->getInvMass() : 0.0;
89 ret += computeDeltaVelocityInConstraintSpace(
90 constraint.m_relpos1CrossNormal,
92 constraint.m_angularComponentA);
97 const btScalar* jacB = &data.m_jacobians[constraint.m_jacBindex];
98 const btScalar* deltaB = &data.m_deltaVelocitiesUnitImpulse[constraint.m_jacBindex];
99 const int ndofB = multiBodyB->getNumDofs() + 6;
100 ret += computeDeltaVelocityInConstraintSpace(deltaB, jacB, ndofB);
104 const int solverBodyIdB = constraint.m_solverBodyIdB;
105 btAssert(solverBodyIdB != -1);
106 const btSolverBody* solverBodyB = &solverBodyPool[solverBodyIdB];
107 const btScalar invMassB = solverBodyB->m_originalBody ? solverBodyB->m_originalBody->getInvMass() : 0.0;
108 ret += computeDeltaVelocityInConstraintSpace(
109 constraint.m_relpos2CrossNormal,
111 constraint.m_angularComponentB);
117 static btScalar computeConstraintMatrixOffDiagElementMultiBody(
118 const btAlignedObjectArray<btSolverBody>& solverBodyPool,
119 const btMultiBodyJacobianData& data,
120 const btMultiBodySolverConstraint& constraint,
121 const btMultiBodySolverConstraint& offDiagConstraint)
123 btScalar offDiagA = btScalar(0);
125 const btMultiBody* multiBodyA = constraint.m_multiBodyA;
126 const btMultiBody* multiBodyB = constraint.m_multiBodyB;
127 const btMultiBody* offDiagMultiBodyA = offDiagConstraint.m_multiBodyA;
128 const btMultiBody* offDiagMultiBodyB = offDiagConstraint.m_multiBodyB;
130 // Assumed at least one system is multibody
131 btAssert(multiBodyA || multiBodyB);
132 btAssert(offDiagMultiBodyA || offDiagMultiBodyB);
134 if (offDiagMultiBodyA)
136 const btScalar* offDiagJacA = &data.m_jacobians[offDiagConstraint.m_jacAindex];
138 if (offDiagMultiBodyA == multiBodyA)
140 const int ndofA = multiBodyA->getNumDofs() + 6;
141 const btScalar* deltaA = &data.m_deltaVelocitiesUnitImpulse[constraint.m_jacAindex];
142 offDiagA += computeDeltaVelocityInConstraintSpace(deltaA, offDiagJacA, ndofA);
144 else if (offDiagMultiBodyA == multiBodyB)
146 const int ndofB = multiBodyB->getNumDofs() + 6;
147 const btScalar* deltaB = &data.m_deltaVelocitiesUnitImpulse[constraint.m_jacBindex];
148 offDiagA += computeDeltaVelocityInConstraintSpace(deltaB, offDiagJacA, ndofB);
153 const int solverBodyIdA = constraint.m_solverBodyIdA;
154 const int solverBodyIdB = constraint.m_solverBodyIdB;
156 const int offDiagSolverBodyIdA = offDiagConstraint.m_solverBodyIdA;
157 btAssert(offDiagSolverBodyIdA != -1);
159 if (offDiagSolverBodyIdA == solverBodyIdA)
161 btAssert(solverBodyIdA != -1);
162 const btSolverBody* solverBodyA = &solverBodyPool[solverBodyIdA];
163 const btScalar invMassA = solverBodyA->m_originalBody ? solverBodyA->m_originalBody->getInvMass() : 0.0;
164 offDiagA += computeDeltaVelocityInConstraintSpace(
165 offDiagConstraint.m_relpos1CrossNormal,
166 offDiagConstraint.m_contactNormal1,
167 invMassA, constraint.m_angularComponentA,
168 constraint.m_contactNormal1);
170 else if (offDiagSolverBodyIdA == solverBodyIdB)
172 btAssert(solverBodyIdB != -1);
173 const btSolverBody* solverBodyB = &solverBodyPool[solverBodyIdB];
174 const btScalar invMassB = solverBodyB->m_originalBody ? solverBodyB->m_originalBody->getInvMass() : 0.0;
175 offDiagA += computeDeltaVelocityInConstraintSpace(
176 offDiagConstraint.m_relpos1CrossNormal,
177 offDiagConstraint.m_contactNormal1,
179 constraint.m_angularComponentB,
180 constraint.m_contactNormal2);
184 if (offDiagMultiBodyB)
186 const btScalar* offDiagJacB = &data.m_jacobians[offDiagConstraint.m_jacBindex];
188 if (offDiagMultiBodyB == multiBodyA)
190 const int ndofA = multiBodyA->getNumDofs() + 6;
191 const btScalar* deltaA = &data.m_deltaVelocitiesUnitImpulse[constraint.m_jacAindex];
192 offDiagA += computeDeltaVelocityInConstraintSpace(deltaA, offDiagJacB, ndofA);
194 else if (offDiagMultiBodyB == multiBodyB)
196 const int ndofB = multiBodyB->getNumDofs() + 6;
197 const btScalar* deltaB = &data.m_deltaVelocitiesUnitImpulse[constraint.m_jacBindex];
198 offDiagA += computeDeltaVelocityInConstraintSpace(deltaB, offDiagJacB, ndofB);
203 const int solverBodyIdA = constraint.m_solverBodyIdA;
204 const int solverBodyIdB = constraint.m_solverBodyIdB;
206 const int offDiagSolverBodyIdB = offDiagConstraint.m_solverBodyIdB;
207 btAssert(offDiagSolverBodyIdB != -1);
209 if (offDiagSolverBodyIdB == solverBodyIdA)
211 btAssert(solverBodyIdA != -1);
212 const btSolverBody* solverBodyA = &solverBodyPool[solverBodyIdA];
213 const btScalar invMassA = solverBodyA->m_originalBody ? solverBodyA->m_originalBody->getInvMass() : 0.0;
214 offDiagA += computeDeltaVelocityInConstraintSpace(
215 offDiagConstraint.m_relpos2CrossNormal,
216 offDiagConstraint.m_contactNormal2,
217 invMassA, constraint.m_angularComponentA,
218 constraint.m_contactNormal1);
220 else if (offDiagSolverBodyIdB == solverBodyIdB)
222 btAssert(solverBodyIdB != -1);
223 const btSolverBody* solverBodyB = &solverBodyPool[solverBodyIdB];
224 const btScalar invMassB = solverBodyB->m_originalBody ? solverBodyB->m_originalBody->getInvMass() : 0.0;
225 offDiagA += computeDeltaVelocityInConstraintSpace(
226 offDiagConstraint.m_relpos2CrossNormal,
227 offDiagConstraint.m_contactNormal2,
228 invMassB, constraint.m_angularComponentB,
229 constraint.m_contactNormal2);
236 void btMultiBodyMLCPConstraintSolver::createMLCPFast(const btContactSolverInfo& infoGlobal)
238 createMLCPFastRigidBody(infoGlobal);
239 createMLCPFastMultiBody(infoGlobal);
242 void btMultiBodyMLCPConstraintSolver::createMLCPFastRigidBody(const btContactSolverInfo& infoGlobal)
244 int numContactRows = interleaveContactAndFriction1 ? 3 : 1;
246 int numConstraintRows = m_allConstraintPtrArray.size();
248 if (numConstraintRows == 0)
251 int n = numConstraintRows;
253 BT_PROFILE("init b (rhs)");
254 m_b.resize(numConstraintRows);
255 m_bSplit.resize(numConstraintRows);
258 for (int i = 0; i < numConstraintRows; i++)
260 btScalar jacDiag = m_allConstraintPtrArray[i]->m_jacDiagABInv;
261 if (!btFuzzyZero(jacDiag))
263 btScalar rhs = m_allConstraintPtrArray[i]->m_rhs;
264 btScalar rhsPenetration = m_allConstraintPtrArray[i]->m_rhsPenetration;
265 m_b[i] = rhs / jacDiag;
266 m_bSplit[i] = rhsPenetration / jacDiag;
274 m_lo.resize(numConstraintRows);
275 m_hi.resize(numConstraintRows);
278 BT_PROFILE("init lo/ho");
280 for (int i = 0; i < numConstraintRows; i++)
282 if (0) //m_limitDependencies[i]>=0)
284 m_lo[i] = -BT_INFINITY;
285 m_hi[i] = BT_INFINITY;
289 m_lo[i] = m_allConstraintPtrArray[i]->m_lowerLimit;
290 m_hi[i] = m_allConstraintPtrArray[i]->m_upperLimit;
296 int m = m_allConstraintPtrArray.size();
298 int numBodies = m_tmpSolverBodyPool.size();
299 btAlignedObjectArray<int> bodyJointNodeArray;
301 BT_PROFILE("bodyJointNodeArray.resize");
302 bodyJointNodeArray.resize(numBodies, -1);
304 btAlignedObjectArray<btJointNode1> jointNodeArray;
306 BT_PROFILE("jointNodeArray.reserve");
307 jointNodeArray.reserve(2 * m_allConstraintPtrArray.size());
310 btMatrixXu& J3 = m_scratchJ3;
312 BT_PROFILE("J3.resize");
315 btMatrixXu& JinvM3 = m_scratchJInvM3;
317 BT_PROFILE("JinvM3.resize/setZero");
319 JinvM3.resize(2 * m, 8);
325 btAlignedObjectArray<int>& ofs = m_scratchOfs;
327 BT_PROFILE("ofs resize");
329 ofs.resizeNoInitialize(m_allConstraintPtrArray.size());
332 BT_PROFILE("Compute J and JinvM");
337 for (int i = 0; i < m_allConstraintPtrArray.size(); i += numRows, c++)
340 int sbA = m_allConstraintPtrArray[i]->m_solverBodyIdA;
341 int sbB = m_allConstraintPtrArray[i]->m_solverBodyIdB;
342 btRigidBody* orgBodyA = m_tmpSolverBodyPool[sbA].m_originalBody;
343 btRigidBody* orgBodyB = m_tmpSolverBodyPool[sbB].m_originalBody;
345 numRows = i < m_tmpSolverNonContactConstraintPool.size() ? m_tmpConstraintSizesPool[c].m_numConstraintRows : numContactRows;
350 //find free jointNode slot for sbA
351 slotA = jointNodeArray.size();
352 jointNodeArray.expand(); //NonInitializing();
353 int prevSlot = bodyJointNodeArray[sbA];
354 bodyJointNodeArray[sbA] = slotA;
355 jointNodeArray[slotA].nextJointNodeIndex = prevSlot;
356 jointNodeArray[slotA].jointIndex = c;
357 jointNodeArray[slotA].constraintRowIndex = i;
358 jointNodeArray[slotA].otherBodyIndex = orgBodyB ? sbB : -1;
360 for (int row = 0; row < numRows; row++, cur++)
362 btVector3 normalInvMass = m_allConstraintPtrArray[i + row]->m_contactNormal1 * orgBodyA->getInvMass();
363 btVector3 relPosCrossNormalInvInertia = m_allConstraintPtrArray[i + row]->m_relpos1CrossNormal * orgBodyA->getInvInertiaTensorWorld();
365 for (int r = 0; r < 3; r++)
367 J3.setElem(cur, r, m_allConstraintPtrArray[i + row]->m_contactNormal1[r]);
368 J3.setElem(cur, r + 4, m_allConstraintPtrArray[i + row]->m_relpos1CrossNormal[r]);
369 JinvM3.setElem(cur, r, normalInvMass[r]);
370 JinvM3.setElem(cur, r + 4, relPosCrossNormalInvInertia[r]);
372 J3.setElem(cur, 3, 0);
373 JinvM3.setElem(cur, 3, 0);
374 J3.setElem(cur, 7, 0);
375 JinvM3.setElem(cur, 7, 0);
386 //find free jointNode slot for sbA
387 slotB = jointNodeArray.size();
388 jointNodeArray.expand(); //NonInitializing();
389 int prevSlot = bodyJointNodeArray[sbB];
390 bodyJointNodeArray[sbB] = slotB;
391 jointNodeArray[slotB].nextJointNodeIndex = prevSlot;
392 jointNodeArray[slotB].jointIndex = c;
393 jointNodeArray[slotB].otherBodyIndex = orgBodyA ? sbA : -1;
394 jointNodeArray[slotB].constraintRowIndex = i;
397 for (int row = 0; row < numRows; row++, cur++)
399 btVector3 normalInvMassB = m_allConstraintPtrArray[i + row]->m_contactNormal2 * orgBodyB->getInvMass();
400 btVector3 relPosInvInertiaB = m_allConstraintPtrArray[i + row]->m_relpos2CrossNormal * orgBodyB->getInvInertiaTensorWorld();
402 for (int r = 0; r < 3; r++)
404 J3.setElem(cur, r, m_allConstraintPtrArray[i + row]->m_contactNormal2[r]);
405 J3.setElem(cur, r + 4, m_allConstraintPtrArray[i + row]->m_relpos2CrossNormal[r]);
406 JinvM3.setElem(cur, r, normalInvMassB[r]);
407 JinvM3.setElem(cur, r + 4, relPosInvInertiaB[r]);
409 J3.setElem(cur, 3, 0);
410 JinvM3.setElem(cur, 3, 0);
411 J3.setElem(cur, 7, 0);
412 JinvM3.setElem(cur, 7, 0);
419 rowOffset += numRows;
423 //compute JinvM = J*invM.
424 const btScalar* JinvM = JinvM3.getBufferPointer();
426 const btScalar* Jptr = J3.getBufferPointer();
428 BT_PROFILE("m_A.resize");
433 BT_PROFILE("m_A.setZero");
439 BT_PROFILE("Compute A");
440 for (int i = 0; i < m_allConstraintPtrArray.size(); i += numRows, c++)
443 int sbA = m_allConstraintPtrArray[i]->m_solverBodyIdA;
444 int sbB = m_allConstraintPtrArray[i]->m_solverBodyIdB;
445 // btRigidBody* orgBodyA = m_tmpSolverBodyPool[sbA].m_originalBody;
446 // btRigidBody* orgBodyB = m_tmpSolverBodyPool[sbB].m_originalBody;
448 numRows = i < m_tmpSolverNonContactConstraintPool.size() ? m_tmpConstraintSizesPool[c].m_numConstraintRows : numContactRows;
450 const btScalar* JinvMrow = JinvM + 2 * 8 * (size_t)row__;
453 int startJointNodeA = bodyJointNodeArray[sbA];
454 while (startJointNodeA >= 0)
456 int j0 = jointNodeArray[startJointNodeA].jointIndex;
457 int cr0 = jointNodeArray[startJointNodeA].constraintRowIndex;
460 int numRowsOther = cr0 < m_tmpSolverNonContactConstraintPool.size() ? m_tmpConstraintSizesPool[j0].m_numConstraintRows : numContactRows;
461 size_t ofsother = (m_allConstraintPtrArray[cr0]->m_solverBodyIdB == sbA) ? 8 * numRowsOther : 0;
462 //printf("%d joint i %d and j0: %d: ",count++,i,j0);
463 m_A.multiplyAdd2_p8r(JinvMrow,
464 Jptr + 2 * 8 * (size_t)ofs[j0] + ofsother, numRows, numRowsOther, row__, ofs[j0]);
466 startJointNodeA = jointNodeArray[startJointNodeA].nextJointNodeIndex;
471 int startJointNodeB = bodyJointNodeArray[sbB];
472 while (startJointNodeB >= 0)
474 int j1 = jointNodeArray[startJointNodeB].jointIndex;
475 int cj1 = jointNodeArray[startJointNodeB].constraintRowIndex;
479 int numRowsOther = cj1 < m_tmpSolverNonContactConstraintPool.size() ? m_tmpConstraintSizesPool[j1].m_numConstraintRows : numContactRows;
480 size_t ofsother = (m_allConstraintPtrArray[cj1]->m_solverBodyIdB == sbB) ? 8 * numRowsOther : 0;
481 m_A.multiplyAdd2_p8r(JinvMrow + 8 * (size_t)numRows,
482 Jptr + 2 * 8 * (size_t)ofs[j1] + ofsother, numRows, numRowsOther, row__, ofs[j1]);
484 startJointNodeB = jointNodeArray[startJointNodeB].nextJointNodeIndex;
490 BT_PROFILE("compute diagonal");
491 // compute diagonal blocks of m_A
494 int numJointRows = m_allConstraintPtrArray.size();
497 for (; row__ < numJointRows;)
499 //int sbA = m_allConstraintPtrArray[row__]->m_solverBodyIdA;
500 int sbB = m_allConstraintPtrArray[row__]->m_solverBodyIdB;
501 // btRigidBody* orgBodyA = m_tmpSolverBodyPool[sbA].m_originalBody;
502 btRigidBody* orgBodyB = m_tmpSolverBodyPool[sbB].m_originalBody;
504 const unsigned int infom = row__ < m_tmpSolverNonContactConstraintPool.size() ? m_tmpConstraintSizesPool[jj].m_numConstraintRows : numContactRows;
506 const btScalar* JinvMrow = JinvM + 2 * 8 * (size_t)row__;
507 const btScalar* Jrow = Jptr + 2 * 8 * (size_t)row__;
508 m_A.multiply2_p8r(JinvMrow, Jrow, infom, infom, row__, row__);
511 m_A.multiplyAdd2_p8r(JinvMrow + 8 * (size_t)infom, Jrow + 8 * (size_t)infom, infom, infom, row__, row__);
521 // add cfm to the diagonal of m_A
522 for (int i = 0; i < m_A.rows(); ++i)
524 m_A.setElem(i, i, m_A(i, i) + infoGlobal.m_globalCfm / infoGlobal.m_timeStep);
528 ///fill the upper triangle of the matrix, to make it symmetric
530 BT_PROFILE("fill the upper triangle ");
531 m_A.copyLowerToUpperTriangle();
535 BT_PROFILE("resize/init x");
536 m_x.resize(numConstraintRows);
537 m_xSplit.resize(numConstraintRows);
539 if (infoGlobal.m_solverMode & SOLVER_USE_WARMSTARTING)
541 for (int i = 0; i < m_allConstraintPtrArray.size(); i++)
543 const btSolverConstraint& c = *m_allConstraintPtrArray[i];
544 m_x[i] = c.m_appliedImpulse;
545 m_xSplit[i] = c.m_appliedPushImpulse;
556 void btMultiBodyMLCPConstraintSolver::createMLCPFastMultiBody(const btContactSolverInfo& infoGlobal)
558 const int multiBodyNumConstraints = m_multiBodyAllConstraintPtrArray.size();
560 if (multiBodyNumConstraints == 0)
565 BT_PROFILE("init b (rhs)");
567 m_multiBodyB.resize(multiBodyNumConstraints);
568 m_multiBodyB.setZero();
570 for (int i = 0; i < multiBodyNumConstraints; ++i)
572 const btMultiBodySolverConstraint& constraint = *m_multiBodyAllConstraintPtrArray[i];
573 const btScalar jacDiag = constraint.m_jacDiagABInv;
575 if (!btFuzzyZero(jacDiag))
577 // Note that rhsPenetration is currently always zero because the split impulse hasn't been implemented for multibody yet.
578 const btScalar rhs = constraint.m_rhs;
579 m_multiBodyB[i] = rhs / jacDiag;
584 // 2. Compute lo and hi
586 BT_PROFILE("init lo/ho");
588 m_multiBodyLo.resize(multiBodyNumConstraints);
589 m_multiBodyHi.resize(multiBodyNumConstraints);
591 for (int i = 0; i < multiBodyNumConstraints; ++i)
593 const btMultiBodySolverConstraint& constraint = *m_multiBodyAllConstraintPtrArray[i];
594 m_multiBodyLo[i] = constraint.m_lowerLimit;
595 m_multiBodyHi[i] = constraint.m_upperLimit;
599 // 3. Construct A matrix by using the impulse testing
601 BT_PROFILE("Compute A");
604 BT_PROFILE("m_A.resize");
605 m_multiBodyA.resize(multiBodyNumConstraints, multiBodyNumConstraints);
608 for (int i = 0; i < multiBodyNumConstraints; ++i)
610 // Compute the diagonal of A, which is A(i, i)
611 const btMultiBodySolverConstraint& constraint = *m_multiBodyAllConstraintPtrArray[i];
612 const btScalar diagA = computeConstraintMatrixDiagElementMultiBody(m_tmpSolverBodyPool, m_data, constraint);
613 m_multiBodyA.setElem(i, i, diagA);
615 // Computes the off-diagonals of A:
616 // a. The rest of i-th row of A, from A(i, i+1) to A(i, n)
617 // b. The rest of i-th column of A, from A(i+1, i) to A(n, i)
618 for (int j = i + 1; j < multiBodyNumConstraints; ++j)
620 const btMultiBodySolverConstraint& offDiagConstraint = *m_multiBodyAllConstraintPtrArray[j];
621 const btScalar offDiagA = computeConstraintMatrixOffDiagElementMultiBody(m_tmpSolverBodyPool, m_data, constraint, offDiagConstraint);
623 // Set the off-diagonal values of A. Note that A is symmetric.
624 m_multiBodyA.setElem(i, j, offDiagA);
625 m_multiBodyA.setElem(j, i, offDiagA);
630 // Add CFM to the diagonal of m_A
631 for (int i = 0; i < m_multiBodyA.rows(); ++i)
633 m_multiBodyA.setElem(i, i, m_multiBodyA(i, i) + infoGlobal.m_globalCfm / infoGlobal.m_timeStep);
638 BT_PROFILE("resize/init x");
640 m_multiBodyX.resize(multiBodyNumConstraints);
642 if (infoGlobal.m_solverMode & SOLVER_USE_WARMSTARTING)
644 for (int i = 0; i < multiBodyNumConstraints; ++i)
646 const btMultiBodySolverConstraint& constraint = *m_multiBodyAllConstraintPtrArray[i];
647 m_multiBodyX[i] = constraint.m_appliedImpulse;
652 m_multiBodyX.setZero();
657 bool btMultiBodyMLCPConstraintSolver::solveMLCP(const btContactSolverInfo& infoGlobal)
663 // If using split impulse, we solve 2 separate (M)LCPs
664 if (infoGlobal.m_splitImpulse)
666 const btMatrixXu Acopy = m_A;
667 const btAlignedObjectArray<int> limitDependenciesCopy = m_limitDependencies;
668 // TODO(JS): Do we really need these copies when solveMLCP takes them as const?
670 result = m_solver->solveMLCP(m_A, m_b, m_x, m_lo, m_hi, m_limitDependencies, infoGlobal.m_numIterations);
672 result = m_solver->solveMLCP(Acopy, m_bSplit, m_xSplit, m_lo, m_hi, limitDependenciesCopy, infoGlobal.m_numIterations);
676 result = m_solver->solveMLCP(m_A, m_b, m_x, m_lo, m_hi, m_limitDependencies, infoGlobal.m_numIterations);
683 if (m_multiBodyA.rows() != 0)
685 result = m_solver->solveMLCP(m_multiBodyA, m_multiBodyB, m_multiBodyX, m_multiBodyLo, m_multiBodyHi, m_multiBodyLimitDependencies, infoGlobal.m_numIterations);
691 btScalar btMultiBodyMLCPConstraintSolver::solveGroupCacheFriendlySetup(
692 btCollisionObject** bodies,
694 btPersistentManifold** manifoldPtr,
696 btTypedConstraint** constraints,
698 const btContactSolverInfo& infoGlobal,
699 btIDebugDraw* debugDrawer)
701 // 1. Setup for rigid-bodies
702 btMultiBodyConstraintSolver::solveGroupCacheFriendlySetup(
703 bodies, numBodies, manifoldPtr, numManifolds, constraints, numConstraints, infoGlobal, debugDrawer);
705 // 2. Setup for multi-bodies
706 // a. Collect all different kinds of constraint as pointers into one array, m_allConstraintPtrArray
707 // b. Set the index array for frictional contact constraints, m_limitDependencies
709 BT_PROFILE("gather constraint data");
713 const int numRigidBodyConstraints = m_tmpSolverNonContactConstraintPool.size() + m_tmpSolverContactConstraintPool.size() + m_tmpSolverContactFrictionConstraintPool.size();
714 const int numMultiBodyConstraints = m_multiBodyNonContactConstraints.size() + m_multiBodyNormalContactConstraints.size() + m_multiBodyFrictionContactConstraints.size();
716 m_allConstraintPtrArray.resize(0);
717 m_multiBodyAllConstraintPtrArray.resize(0);
719 // i. Setup for rigid bodies
721 m_limitDependencies.resize(numRigidBodyConstraints);
723 for (int i = 0; i < m_tmpSolverNonContactConstraintPool.size(); ++i)
725 m_allConstraintPtrArray.push_back(&m_tmpSolverNonContactConstraintPool[i]);
726 m_limitDependencies[dindex++] = -1;
729 int firstContactConstraintOffset = dindex;
731 // The btSequentialImpulseConstraintSolver moves all friction constraints at the very end, we can also interleave them instead
732 if (interleaveContactAndFriction1)
734 for (int i = 0; i < m_tmpSolverContactConstraintPool.size(); i++)
736 const int numFrictionPerContact = m_tmpSolverContactConstraintPool.size() == m_tmpSolverContactFrictionConstraintPool.size() ? 1 : 2;
738 m_allConstraintPtrArray.push_back(&m_tmpSolverContactConstraintPool[i]);
739 m_limitDependencies[dindex++] = -1;
740 m_allConstraintPtrArray.push_back(&m_tmpSolverContactFrictionConstraintPool[i * numFrictionPerContact]);
741 int findex = (m_tmpSolverContactFrictionConstraintPool[i * numFrictionPerContact].m_frictionIndex * (1 + numFrictionPerContact));
742 m_limitDependencies[dindex++] = findex + firstContactConstraintOffset;
743 if (numFrictionPerContact == 2)
745 m_allConstraintPtrArray.push_back(&m_tmpSolverContactFrictionConstraintPool[i * numFrictionPerContact + 1]);
746 m_limitDependencies[dindex++] = findex + firstContactConstraintOffset;
752 for (int i = 0; i < m_tmpSolverContactConstraintPool.size(); i++)
754 m_allConstraintPtrArray.push_back(&m_tmpSolverContactConstraintPool[i]);
755 m_limitDependencies[dindex++] = -1;
757 for (int i = 0; i < m_tmpSolverContactFrictionConstraintPool.size(); i++)
759 m_allConstraintPtrArray.push_back(&m_tmpSolverContactFrictionConstraintPool[i]);
760 m_limitDependencies[dindex++] = m_tmpSolverContactFrictionConstraintPool[i].m_frictionIndex + firstContactConstraintOffset;
764 if (!m_allConstraintPtrArray.size())
773 // ii. Setup for multibodies
777 m_multiBodyLimitDependencies.resize(numMultiBodyConstraints);
779 for (int i = 0; i < m_multiBodyNonContactConstraints.size(); ++i)
781 m_multiBodyAllConstraintPtrArray.push_back(&m_multiBodyNonContactConstraints[i]);
782 m_multiBodyLimitDependencies[dindex++] = -1;
785 firstContactConstraintOffset = dindex;
787 // The btSequentialImpulseConstraintSolver moves all friction constraints at the very end, we can also interleave them instead
788 if (interleaveContactAndFriction1)
790 for (int i = 0; i < m_multiBodyNormalContactConstraints.size(); ++i)
792 const int numtiBodyNumFrictionPerContact = m_multiBodyNormalContactConstraints.size() == m_multiBodyFrictionContactConstraints.size() ? 1 : 2;
794 m_multiBodyAllConstraintPtrArray.push_back(&m_multiBodyNormalContactConstraints[i]);
795 m_multiBodyLimitDependencies[dindex++] = -1;
797 btMultiBodySolverConstraint& frictionContactConstraint1 = m_multiBodyFrictionContactConstraints[i * numtiBodyNumFrictionPerContact];
798 m_multiBodyAllConstraintPtrArray.push_back(&frictionContactConstraint1);
800 const int findex = (frictionContactConstraint1.m_frictionIndex * (1 + numtiBodyNumFrictionPerContact)) + firstContactConstraintOffset;
802 m_multiBodyLimitDependencies[dindex++] = findex;
804 if (numtiBodyNumFrictionPerContact == 2)
806 btMultiBodySolverConstraint& frictionContactConstraint2 = m_multiBodyFrictionContactConstraints[i * numtiBodyNumFrictionPerContact + 1];
807 m_multiBodyAllConstraintPtrArray.push_back(&frictionContactConstraint2);
809 m_multiBodyLimitDependencies[dindex++] = findex;
815 for (int i = 0; i < m_multiBodyNormalContactConstraints.size(); ++i)
817 m_multiBodyAllConstraintPtrArray.push_back(&m_multiBodyNormalContactConstraints[i]);
818 m_multiBodyLimitDependencies[dindex++] = -1;
820 for (int i = 0; i < m_multiBodyFrictionContactConstraints.size(); ++i)
822 m_multiBodyAllConstraintPtrArray.push_back(&m_multiBodyFrictionContactConstraints[i]);
823 m_multiBodyLimitDependencies[dindex++] = m_multiBodyFrictionContactConstraints[i].m_frictionIndex + firstContactConstraintOffset;
827 if (!m_multiBodyAllConstraintPtrArray.size())
829 m_multiBodyA.resize(0, 0);
830 m_multiBodyB.resize(0);
831 m_multiBodyX.resize(0);
832 m_multiBodyLo.resize(0);
833 m_multiBodyHi.resize(0);
837 // Construct MLCP terms
839 BT_PROFILE("createMLCPFast");
840 createMLCPFast(infoGlobal);
846 btScalar btMultiBodyMLCPConstraintSolver::solveGroupCacheFriendlyIterations(btCollisionObject** bodies, int numBodies, btPersistentManifold** manifoldPtr, int numManifolds, btTypedConstraint** constraints, int numConstraints, const btContactSolverInfo& infoGlobal, btIDebugDraw* debugDrawer)
850 BT_PROFILE("solveMLCP");
851 result = solveMLCP(infoGlobal);
854 // Fallback to btSequentialImpulseConstraintSolver::solveGroupCacheFriendlyIterations if the solution isn't valid.
858 return btMultiBodyConstraintSolver::solveGroupCacheFriendlyIterations(bodies, numBodies, manifoldPtr, numManifolds, constraints, numConstraints, infoGlobal, debugDrawer);
862 BT_PROFILE("process MLCP results");
864 for (int i = 0; i < m_allConstraintPtrArray.size(); ++i)
866 const btSolverConstraint& c = *m_allConstraintPtrArray[i];
868 const btScalar deltaImpulse = m_x[i] - c.m_appliedImpulse;
869 c.m_appliedImpulse = m_x[i];
871 int sbA = c.m_solverBodyIdA;
872 int sbB = c.m_solverBodyIdB;
874 btSolverBody& solverBodyA = m_tmpSolverBodyPool[sbA];
875 btSolverBody& solverBodyB = m_tmpSolverBodyPool[sbB];
877 solverBodyA.internalApplyImpulse(c.m_contactNormal1 * solverBodyA.internalGetInvMass(), c.m_angularComponentA, deltaImpulse);
878 solverBodyB.internalApplyImpulse(c.m_contactNormal2 * solverBodyB.internalGetInvMass(), c.m_angularComponentB, deltaImpulse);
880 if (infoGlobal.m_splitImpulse)
882 const btScalar deltaPushImpulse = m_xSplit[i] - c.m_appliedPushImpulse;
883 solverBodyA.internalApplyPushImpulse(c.m_contactNormal1 * solverBodyA.internalGetInvMass(), c.m_angularComponentA, deltaPushImpulse);
884 solverBodyB.internalApplyPushImpulse(c.m_contactNormal2 * solverBodyB.internalGetInvMass(), c.m_angularComponentB, deltaPushImpulse);
885 c.m_appliedPushImpulse = m_xSplit[i];
889 for (int i = 0; i < m_multiBodyAllConstraintPtrArray.size(); ++i)
891 btMultiBodySolverConstraint& c = *m_multiBodyAllConstraintPtrArray[i];
893 const btScalar deltaImpulse = m_multiBodyX[i] - c.m_appliedImpulse;
894 c.m_appliedImpulse = m_multiBodyX[i];
896 btMultiBody* multiBodyA = c.m_multiBodyA;
899 const int ndofA = multiBodyA->getNumDofs() + 6;
900 applyDeltaVee(&m_data.m_deltaVelocitiesUnitImpulse[c.m_jacAindex], deltaImpulse, c.m_deltaVelAindex, ndofA);
901 #ifdef DIRECTLY_UPDATE_VELOCITY_DURING_SOLVER_ITERATIONS
902 //note: update of the actual velocities (below) in the multibody does not have to happen now since m_deltaVelocities can be applied after all iterations
903 //it would make the multibody solver more like the regular one with m_deltaVelocities being equivalent to btSolverBody::m_deltaLinearVelocity/m_deltaAngularVelocity
904 multiBodyA->applyDeltaVeeMultiDof2(&m_data.m_deltaVelocitiesUnitImpulse[c.m_jacAindex], deltaImpulse);
905 #endif // DIRECTLY_UPDATE_VELOCITY_DURING_SOLVER_ITERATIONS
909 const int sbA = c.m_solverBodyIdA;
910 btSolverBody& solverBodyA = m_tmpSolverBodyPool[sbA];
911 solverBodyA.internalApplyImpulse(c.m_contactNormal1 * solverBodyA.internalGetInvMass(), c.m_angularComponentA, deltaImpulse);
914 btMultiBody* multiBodyB = c.m_multiBodyB;
917 const int ndofB = multiBodyB->getNumDofs() + 6;
918 applyDeltaVee(&m_data.m_deltaVelocitiesUnitImpulse[c.m_jacBindex], deltaImpulse, c.m_deltaVelBindex, ndofB);
919 #ifdef DIRECTLY_UPDATE_VELOCITY_DURING_SOLVER_ITERATIONS
920 //note: update of the actual velocities (below) in the multibody does not have to happen now since m_deltaVelocities can be applied after all iterations
921 //it would make the multibody solver more like the regular one with m_deltaVelocities being equivalent to btSolverBody::m_deltaLinearVelocity/m_deltaAngularVelocity
922 multiBodyB->applyDeltaVeeMultiDof2(&m_data.m_deltaVelocitiesUnitImpulse[c.m_jacBindex], deltaImpulse);
923 #endif // DIRECTLY_UPDATE_VELOCITY_DURING_SOLVER_ITERATIONS
927 const int sbB = c.m_solverBodyIdB;
928 btSolverBody& solverBodyB = m_tmpSolverBodyPool[sbB];
929 solverBodyB.internalApplyImpulse(c.m_contactNormal2 * solverBodyB.internalGetInvMass(), c.m_angularComponentB, deltaImpulse);
937 btMultiBodyMLCPConstraintSolver::btMultiBodyMLCPConstraintSolver(btMLCPSolverInterface* solver)
938 : m_solver(solver), m_fallback(0)
943 btMultiBodyMLCPConstraintSolver::~btMultiBodyMLCPConstraintSolver()
948 void btMultiBodyMLCPConstraintSolver::setMLCPSolver(btMLCPSolverInterface* solver)
953 int btMultiBodyMLCPConstraintSolver::getNumFallbacks() const
958 void btMultiBodyMLCPConstraintSolver::setNumFallbacks(int num)
963 btConstraintSolverType btMultiBodyMLCPConstraintSolver::getSolverType() const
965 return BT_MLCP_SOLVER;