123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967 |
- /*
- Bullet Continuous Collision Detection and Physics Library
- Copyright (c) 2018 Google Inc. http://bulletphysics.org
- This software is provided 'as-is', without any express or implied warranty.
- In no event will the authors be held liable for any damages arising from the use of this software.
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it freely,
- subject to the following restrictions:
- 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.
- 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
- 3. This notice may not be removed or altered from any source distribution.
- */
- #include "BulletDynamics/Featherstone/btMultiBodyMLCPConstraintSolver.h"
- #include "BulletCollision/NarrowPhaseCollision/btPersistentManifold.h"
- #include "BulletDynamics/Featherstone/btMultiBodyLinkCollider.h"
- #include "BulletDynamics/Featherstone/btMultiBodyConstraint.h"
- #include "BulletDynamics/MLCPSolvers/btMLCPSolverInterface.h"
- #define DIRECTLY_UPDATE_VELOCITY_DURING_SOLVER_ITERATIONS
- static bool interleaveContactAndFriction = false;
- struct btJointNode
- {
- int jointIndex; // pointer to enclosing dxJoint object
- int otherBodyIndex; // *other* body this joint is connected to
- int nextJointNodeIndex; //-1 for null
- int constraintRowIndex;
- };
- // Helper function to compute a delta velocity in the constraint space.
- static btScalar computeDeltaVelocityInConstraintSpace(
- const btVector3& angularDeltaVelocity,
- const btVector3& contactNormal,
- btScalar invMass,
- const btVector3& angularJacobian,
- const btVector3& linearJacobian)
- {
- return angularDeltaVelocity.dot(angularJacobian) + contactNormal.dot(linearJacobian) * invMass;
- }
- // Faster version of computeDeltaVelocityInConstraintSpace that can be used when contactNormal and linearJacobian are
- // identical.
- static btScalar computeDeltaVelocityInConstraintSpace(
- const btVector3& angularDeltaVelocity,
- btScalar invMass,
- const btVector3& angularJacobian)
- {
- return angularDeltaVelocity.dot(angularJacobian) + invMass;
- }
- // Helper function to compute a delta velocity in the constraint space.
- static btScalar computeDeltaVelocityInConstraintSpace(const btScalar* deltaVelocity, const btScalar* jacobian, int size)
- {
- btScalar result = 0;
- for (int i = 0; i < size; ++i)
- result += deltaVelocity[i] * jacobian[i];
- return result;
- }
- static btScalar computeConstraintMatrixDiagElementMultiBody(
- const btAlignedObjectArray<btSolverBody>& solverBodyPool,
- const btMultiBodyJacobianData& data,
- const btMultiBodySolverConstraint& constraint)
- {
- btScalar ret = 0;
- const btMultiBody* multiBodyA = constraint.m_multiBodyA;
- const btMultiBody* multiBodyB = constraint.m_multiBodyB;
- if (multiBodyA)
- {
- const btScalar* jacA = &data.m_jacobians[constraint.m_jacAindex];
- const btScalar* deltaA = &data.m_deltaVelocitiesUnitImpulse[constraint.m_jacAindex];
- const int ndofA = multiBodyA->getNumDofs() + 6;
- ret += computeDeltaVelocityInConstraintSpace(deltaA, jacA, ndofA);
- }
- else
- {
- const int solverBodyIdA = constraint.m_solverBodyIdA;
- btAssert(solverBodyIdA != -1);
- const btSolverBody* solverBodyA = &solverBodyPool[solverBodyIdA];
- const btScalar invMassA = solverBodyA->m_originalBody ? solverBodyA->m_originalBody->getInvMass() : 0.0;
- ret += computeDeltaVelocityInConstraintSpace(
- constraint.m_relpos1CrossNormal,
- invMassA,
- constraint.m_angularComponentA);
- }
- if (multiBodyB)
- {
- const btScalar* jacB = &data.m_jacobians[constraint.m_jacBindex];
- const btScalar* deltaB = &data.m_deltaVelocitiesUnitImpulse[constraint.m_jacBindex];
- const int ndofB = multiBodyB->getNumDofs() + 6;
- ret += computeDeltaVelocityInConstraintSpace(deltaB, jacB, ndofB);
- }
- else
- {
- const int solverBodyIdB = constraint.m_solverBodyIdB;
- btAssert(solverBodyIdB != -1);
- const btSolverBody* solverBodyB = &solverBodyPool[solverBodyIdB];
- const btScalar invMassB = solverBodyB->m_originalBody ? solverBodyB->m_originalBody->getInvMass() : 0.0;
- ret += computeDeltaVelocityInConstraintSpace(
- constraint.m_relpos2CrossNormal,
- invMassB,
- constraint.m_angularComponentB);
- }
- return ret;
- }
- static btScalar computeConstraintMatrixOffDiagElementMultiBody(
- const btAlignedObjectArray<btSolverBody>& solverBodyPool,
- const btMultiBodyJacobianData& data,
- const btMultiBodySolverConstraint& constraint,
- const btMultiBodySolverConstraint& offDiagConstraint)
- {
- btScalar offDiagA = btScalar(0);
- const btMultiBody* multiBodyA = constraint.m_multiBodyA;
- const btMultiBody* multiBodyB = constraint.m_multiBodyB;
- const btMultiBody* offDiagMultiBodyA = offDiagConstraint.m_multiBodyA;
- const btMultiBody* offDiagMultiBodyB = offDiagConstraint.m_multiBodyB;
- // Assumed at least one system is multibody
- btAssert(multiBodyA || multiBodyB);
- btAssert(offDiagMultiBodyA || offDiagMultiBodyB);
- if (offDiagMultiBodyA)
- {
- const btScalar* offDiagJacA = &data.m_jacobians[offDiagConstraint.m_jacAindex];
- if (offDiagMultiBodyA == multiBodyA)
- {
- const int ndofA = multiBodyA->getNumDofs() + 6;
- const btScalar* deltaA = &data.m_deltaVelocitiesUnitImpulse[constraint.m_jacAindex];
- offDiagA += computeDeltaVelocityInConstraintSpace(deltaA, offDiagJacA, ndofA);
- }
- else if (offDiagMultiBodyA == multiBodyB)
- {
- const int ndofB = multiBodyB->getNumDofs() + 6;
- const btScalar* deltaB = &data.m_deltaVelocitiesUnitImpulse[constraint.m_jacBindex];
- offDiagA += computeDeltaVelocityInConstraintSpace(deltaB, offDiagJacA, ndofB);
- }
- }
- else
- {
- const int solverBodyIdA = constraint.m_solverBodyIdA;
- const int solverBodyIdB = constraint.m_solverBodyIdB;
- const int offDiagSolverBodyIdA = offDiagConstraint.m_solverBodyIdA;
- btAssert(offDiagSolverBodyIdA != -1);
- if (offDiagSolverBodyIdA == solverBodyIdA)
- {
- btAssert(solverBodyIdA != -1);
- const btSolverBody* solverBodyA = &solverBodyPool[solverBodyIdA];
- const btScalar invMassA = solverBodyA->m_originalBody ? solverBodyA->m_originalBody->getInvMass() : 0.0;
- offDiagA += computeDeltaVelocityInConstraintSpace(
- offDiagConstraint.m_relpos1CrossNormal,
- offDiagConstraint.m_contactNormal1,
- invMassA, constraint.m_angularComponentA,
- constraint.m_contactNormal1);
- }
- else if (offDiagSolverBodyIdA == solverBodyIdB)
- {
- btAssert(solverBodyIdB != -1);
- const btSolverBody* solverBodyB = &solverBodyPool[solverBodyIdB];
- const btScalar invMassB = solverBodyB->m_originalBody ? solverBodyB->m_originalBody->getInvMass() : 0.0;
- offDiagA += computeDeltaVelocityInConstraintSpace(
- offDiagConstraint.m_relpos1CrossNormal,
- offDiagConstraint.m_contactNormal1,
- invMassB,
- constraint.m_angularComponentB,
- constraint.m_contactNormal2);
- }
- }
- if (offDiagMultiBodyB)
- {
- const btScalar* offDiagJacB = &data.m_jacobians[offDiagConstraint.m_jacBindex];
- if (offDiagMultiBodyB == multiBodyA)
- {
- const int ndofA = multiBodyA->getNumDofs() + 6;
- const btScalar* deltaA = &data.m_deltaVelocitiesUnitImpulse[constraint.m_jacAindex];
- offDiagA += computeDeltaVelocityInConstraintSpace(deltaA, offDiagJacB, ndofA);
- }
- else if (offDiagMultiBodyB == multiBodyB)
- {
- const int ndofB = multiBodyB->getNumDofs() + 6;
- const btScalar* deltaB = &data.m_deltaVelocitiesUnitImpulse[constraint.m_jacBindex];
- offDiagA += computeDeltaVelocityInConstraintSpace(deltaB, offDiagJacB, ndofB);
- }
- }
- else
- {
- const int solverBodyIdA = constraint.m_solverBodyIdA;
- const int solverBodyIdB = constraint.m_solverBodyIdB;
- const int offDiagSolverBodyIdB = offDiagConstraint.m_solverBodyIdB;
- btAssert(offDiagSolverBodyIdB != -1);
- if (offDiagSolverBodyIdB == solverBodyIdA)
- {
- btAssert(solverBodyIdA != -1);
- const btSolverBody* solverBodyA = &solverBodyPool[solverBodyIdA];
- const btScalar invMassA = solverBodyA->m_originalBody ? solverBodyA->m_originalBody->getInvMass() : 0.0;
- offDiagA += computeDeltaVelocityInConstraintSpace(
- offDiagConstraint.m_relpos2CrossNormal,
- offDiagConstraint.m_contactNormal2,
- invMassA, constraint.m_angularComponentA,
- constraint.m_contactNormal1);
- }
- else if (offDiagSolverBodyIdB == solverBodyIdB)
- {
- btAssert(solverBodyIdB != -1);
- const btSolverBody* solverBodyB = &solverBodyPool[solverBodyIdB];
- const btScalar invMassB = solverBodyB->m_originalBody ? solverBodyB->m_originalBody->getInvMass() : 0.0;
- offDiagA += computeDeltaVelocityInConstraintSpace(
- offDiagConstraint.m_relpos2CrossNormal,
- offDiagConstraint.m_contactNormal2,
- invMassB, constraint.m_angularComponentB,
- constraint.m_contactNormal2);
- }
- }
- return offDiagA;
- }
- void btMultiBodyMLCPConstraintSolver::createMLCPFast(const btContactSolverInfo& infoGlobal)
- {
- createMLCPFastRigidBody(infoGlobal);
- createMLCPFastMultiBody(infoGlobal);
- }
- void btMultiBodyMLCPConstraintSolver::createMLCPFastRigidBody(const btContactSolverInfo& infoGlobal)
- {
- int numContactRows = interleaveContactAndFriction ? 3 : 1;
- int numConstraintRows = m_allConstraintPtrArray.size();
- if (numConstraintRows == 0)
- return;
- int n = numConstraintRows;
- {
- BT_PROFILE("init b (rhs)");
- m_b.resize(numConstraintRows);
- m_bSplit.resize(numConstraintRows);
- m_b.setZero();
- m_bSplit.setZero();
- for (int i = 0; i < numConstraintRows; i++)
- {
- btScalar jacDiag = m_allConstraintPtrArray[i]->m_jacDiagABInv;
- if (!btFuzzyZero(jacDiag))
- {
- btScalar rhs = m_allConstraintPtrArray[i]->m_rhs;
- btScalar rhsPenetration = m_allConstraintPtrArray[i]->m_rhsPenetration;
- m_b[i] = rhs / jacDiag;
- m_bSplit[i] = rhsPenetration / jacDiag;
- }
- }
- }
- // btScalar* w = 0;
- // int nub = 0;
- m_lo.resize(numConstraintRows);
- m_hi.resize(numConstraintRows);
- {
- BT_PROFILE("init lo/ho");
- for (int i = 0; i < numConstraintRows; i++)
- {
- if (0) //m_limitDependencies[i]>=0)
- {
- m_lo[i] = -BT_INFINITY;
- m_hi[i] = BT_INFINITY;
- }
- else
- {
- m_lo[i] = m_allConstraintPtrArray[i]->m_lowerLimit;
- m_hi[i] = m_allConstraintPtrArray[i]->m_upperLimit;
- }
- }
- }
- //
- int m = m_allConstraintPtrArray.size();
- int numBodies = m_tmpSolverBodyPool.size();
- btAlignedObjectArray<int> bodyJointNodeArray;
- {
- BT_PROFILE("bodyJointNodeArray.resize");
- bodyJointNodeArray.resize(numBodies, -1);
- }
- btAlignedObjectArray<btJointNode> jointNodeArray;
- {
- BT_PROFILE("jointNodeArray.reserve");
- jointNodeArray.reserve(2 * m_allConstraintPtrArray.size());
- }
- btMatrixXu& J3 = m_scratchJ3;
- {
- BT_PROFILE("J3.resize");
- J3.resize(2 * m, 8);
- }
- btMatrixXu& JinvM3 = m_scratchJInvM3;
- {
- BT_PROFILE("JinvM3.resize/setZero");
- JinvM3.resize(2 * m, 8);
- JinvM3.setZero();
- J3.setZero();
- }
- int cur = 0;
- int rowOffset = 0;
- btAlignedObjectArray<int>& ofs = m_scratchOfs;
- {
- BT_PROFILE("ofs resize");
- ofs.resize(0);
- ofs.resizeNoInitialize(m_allConstraintPtrArray.size());
- }
- {
- BT_PROFILE("Compute J and JinvM");
- int c = 0;
- int numRows = 0;
- for (int i = 0; i < m_allConstraintPtrArray.size(); i += numRows, c++)
- {
- ofs[c] = rowOffset;
- int sbA = m_allConstraintPtrArray[i]->m_solverBodyIdA;
- int sbB = m_allConstraintPtrArray[i]->m_solverBodyIdB;
- btRigidBody* orgBodyA = m_tmpSolverBodyPool[sbA].m_originalBody;
- btRigidBody* orgBodyB = m_tmpSolverBodyPool[sbB].m_originalBody;
- numRows = i < m_tmpSolverNonContactConstraintPool.size() ? m_tmpConstraintSizesPool[c].m_numConstraintRows : numContactRows;
- if (orgBodyA)
- {
- {
- int slotA = -1;
- //find free jointNode slot for sbA
- slotA = jointNodeArray.size();
- jointNodeArray.expand(); //NonInitializing();
- int prevSlot = bodyJointNodeArray[sbA];
- bodyJointNodeArray[sbA] = slotA;
- jointNodeArray[slotA].nextJointNodeIndex = prevSlot;
- jointNodeArray[slotA].jointIndex = c;
- jointNodeArray[slotA].constraintRowIndex = i;
- jointNodeArray[slotA].otherBodyIndex = orgBodyB ? sbB : -1;
- }
- for (int row = 0; row < numRows; row++, cur++)
- {
- btVector3 normalInvMass = m_allConstraintPtrArray[i + row]->m_contactNormal1 * orgBodyA->getInvMass();
- btVector3 relPosCrossNormalInvInertia = m_allConstraintPtrArray[i + row]->m_relpos1CrossNormal * orgBodyA->getInvInertiaTensorWorld();
- for (int r = 0; r < 3; r++)
- {
- J3.setElem(cur, r, m_allConstraintPtrArray[i + row]->m_contactNormal1[r]);
- J3.setElem(cur, r + 4, m_allConstraintPtrArray[i + row]->m_relpos1CrossNormal[r]);
- JinvM3.setElem(cur, r, normalInvMass[r]);
- JinvM3.setElem(cur, r + 4, relPosCrossNormalInvInertia[r]);
- }
- J3.setElem(cur, 3, 0);
- JinvM3.setElem(cur, 3, 0);
- J3.setElem(cur, 7, 0);
- JinvM3.setElem(cur, 7, 0);
- }
- }
- else
- {
- cur += numRows;
- }
- if (orgBodyB)
- {
- {
- int slotB = -1;
- //find free jointNode slot for sbA
- slotB = jointNodeArray.size();
- jointNodeArray.expand(); //NonInitializing();
- int prevSlot = bodyJointNodeArray[sbB];
- bodyJointNodeArray[sbB] = slotB;
- jointNodeArray[slotB].nextJointNodeIndex = prevSlot;
- jointNodeArray[slotB].jointIndex = c;
- jointNodeArray[slotB].otherBodyIndex = orgBodyA ? sbA : -1;
- jointNodeArray[slotB].constraintRowIndex = i;
- }
- for (int row = 0; row < numRows; row++, cur++)
- {
- btVector3 normalInvMassB = m_allConstraintPtrArray[i + row]->m_contactNormal2 * orgBodyB->getInvMass();
- btVector3 relPosInvInertiaB = m_allConstraintPtrArray[i + row]->m_relpos2CrossNormal * orgBodyB->getInvInertiaTensorWorld();
- for (int r = 0; r < 3; r++)
- {
- J3.setElem(cur, r, m_allConstraintPtrArray[i + row]->m_contactNormal2[r]);
- J3.setElem(cur, r + 4, m_allConstraintPtrArray[i + row]->m_relpos2CrossNormal[r]);
- JinvM3.setElem(cur, r, normalInvMassB[r]);
- JinvM3.setElem(cur, r + 4, relPosInvInertiaB[r]);
- }
- J3.setElem(cur, 3, 0);
- JinvM3.setElem(cur, 3, 0);
- J3.setElem(cur, 7, 0);
- JinvM3.setElem(cur, 7, 0);
- }
- }
- else
- {
- cur += numRows;
- }
- rowOffset += numRows;
- }
- }
- //compute JinvM = J*invM.
- const btScalar* JinvM = JinvM3.getBufferPointer();
- const btScalar* Jptr = J3.getBufferPointer();
- {
- BT_PROFILE("m_A.resize");
- m_A.resize(n, n);
- }
- {
- BT_PROFILE("m_A.setZero");
- m_A.setZero();
- }
- int c = 0;
- {
- int numRows = 0;
- BT_PROFILE("Compute A");
- for (int i = 0; i < m_allConstraintPtrArray.size(); i += numRows, c++)
- {
- int row__ = ofs[c];
- int sbA = m_allConstraintPtrArray[i]->m_solverBodyIdA;
- int sbB = m_allConstraintPtrArray[i]->m_solverBodyIdB;
- // btRigidBody* orgBodyA = m_tmpSolverBodyPool[sbA].m_originalBody;
- // btRigidBody* orgBodyB = m_tmpSolverBodyPool[sbB].m_originalBody;
- numRows = i < m_tmpSolverNonContactConstraintPool.size() ? m_tmpConstraintSizesPool[c].m_numConstraintRows : numContactRows;
- const btScalar* JinvMrow = JinvM + 2 * 8 * (size_t)row__;
- {
- int startJointNodeA = bodyJointNodeArray[sbA];
- while (startJointNodeA >= 0)
- {
- int j0 = jointNodeArray[startJointNodeA].jointIndex;
- int cr0 = jointNodeArray[startJointNodeA].constraintRowIndex;
- if (j0 < c)
- {
- int numRowsOther = cr0 < m_tmpSolverNonContactConstraintPool.size() ? m_tmpConstraintSizesPool[j0].m_numConstraintRows : numContactRows;
- size_t ofsother = (m_allConstraintPtrArray[cr0]->m_solverBodyIdB == sbA) ? 8 * numRowsOther : 0;
- //printf("%d joint i %d and j0: %d: ",count++,i,j0);
- m_A.multiplyAdd2_p8r(JinvMrow,
- Jptr + 2 * 8 * (size_t)ofs[j0] + ofsother, numRows, numRowsOther, row__, ofs[j0]);
- }
- startJointNodeA = jointNodeArray[startJointNodeA].nextJointNodeIndex;
- }
- }
- {
- int startJointNodeB = bodyJointNodeArray[sbB];
- while (startJointNodeB >= 0)
- {
- int j1 = jointNodeArray[startJointNodeB].jointIndex;
- int cj1 = jointNodeArray[startJointNodeB].constraintRowIndex;
- if (j1 < c)
- {
- int numRowsOther = cj1 < m_tmpSolverNonContactConstraintPool.size() ? m_tmpConstraintSizesPool[j1].m_numConstraintRows : numContactRows;
- size_t ofsother = (m_allConstraintPtrArray[cj1]->m_solverBodyIdB == sbB) ? 8 * numRowsOther : 0;
- m_A.multiplyAdd2_p8r(JinvMrow + 8 * (size_t)numRows,
- Jptr + 2 * 8 * (size_t)ofs[j1] + ofsother, numRows, numRowsOther, row__, ofs[j1]);
- }
- startJointNodeB = jointNodeArray[startJointNodeB].nextJointNodeIndex;
- }
- }
- }
- {
- BT_PROFILE("compute diagonal");
- // compute diagonal blocks of m_A
- int row__ = 0;
- int numJointRows = m_allConstraintPtrArray.size();
- int jj = 0;
- for (; row__ < numJointRows;)
- {
- //int sbA = m_allConstraintPtrArray[row__]->m_solverBodyIdA;
- int sbB = m_allConstraintPtrArray[row__]->m_solverBodyIdB;
- // btRigidBody* orgBodyA = m_tmpSolverBodyPool[sbA].m_originalBody;
- btRigidBody* orgBodyB = m_tmpSolverBodyPool[sbB].m_originalBody;
- const unsigned int infom = row__ < m_tmpSolverNonContactConstraintPool.size() ? m_tmpConstraintSizesPool[jj].m_numConstraintRows : numContactRows;
- const btScalar* JinvMrow = JinvM + 2 * 8 * (size_t)row__;
- const btScalar* Jrow = Jptr + 2 * 8 * (size_t)row__;
- m_A.multiply2_p8r(JinvMrow, Jrow, infom, infom, row__, row__);
- if (orgBodyB)
- {
- m_A.multiplyAdd2_p8r(JinvMrow + 8 * (size_t)infom, Jrow + 8 * (size_t)infom, infom, infom, row__, row__);
- }
- row__ += infom;
- jj++;
- }
- }
- }
- if (1)
- {
- // add cfm to the diagonal of m_A
- for (int i = 0; i < m_A.rows(); ++i)
- {
- m_A.setElem(i, i, m_A(i, i) + infoGlobal.m_globalCfm / infoGlobal.m_timeStep);
- }
- }
- ///fill the upper triangle of the matrix, to make it symmetric
- {
- BT_PROFILE("fill the upper triangle ");
- m_A.copyLowerToUpperTriangle();
- }
- {
- BT_PROFILE("resize/init x");
- m_x.resize(numConstraintRows);
- m_xSplit.resize(numConstraintRows);
- if (infoGlobal.m_solverMode & SOLVER_USE_WARMSTARTING)
- {
- for (int i = 0; i < m_allConstraintPtrArray.size(); i++)
- {
- const btSolverConstraint& c = *m_allConstraintPtrArray[i];
- m_x[i] = c.m_appliedImpulse;
- m_xSplit[i] = c.m_appliedPushImpulse;
- }
- }
- else
- {
- m_x.setZero();
- m_xSplit.setZero();
- }
- }
- }
- void btMultiBodyMLCPConstraintSolver::createMLCPFastMultiBody(const btContactSolverInfo& infoGlobal)
- {
- const int multiBodyNumConstraints = m_multiBodyAllConstraintPtrArray.size();
- if (multiBodyNumConstraints == 0)
- return;
- // 1. Compute b
- {
- BT_PROFILE("init b (rhs)");
- m_multiBodyB.resize(multiBodyNumConstraints);
- m_multiBodyB.setZero();
- for (int i = 0; i < multiBodyNumConstraints; ++i)
- {
- const btMultiBodySolverConstraint& constraint = *m_multiBodyAllConstraintPtrArray[i];
- const btScalar jacDiag = constraint.m_jacDiagABInv;
- if (!btFuzzyZero(jacDiag))
- {
- // Note that rhsPenetration is currently always zero because the split impulse hasn't been implemented for multibody yet.
- const btScalar rhs = constraint.m_rhs;
- m_multiBodyB[i] = rhs / jacDiag;
- }
- }
- }
- // 2. Compute lo and hi
- {
- BT_PROFILE("init lo/ho");
- m_multiBodyLo.resize(multiBodyNumConstraints);
- m_multiBodyHi.resize(multiBodyNumConstraints);
- for (int i = 0; i < multiBodyNumConstraints; ++i)
- {
- const btMultiBodySolverConstraint& constraint = *m_multiBodyAllConstraintPtrArray[i];
- m_multiBodyLo[i] = constraint.m_lowerLimit;
- m_multiBodyHi[i] = constraint.m_upperLimit;
- }
- }
- // 3. Construct A matrix by using the impulse testing
- {
- BT_PROFILE("Compute A");
- {
- BT_PROFILE("m_A.resize");
- m_multiBodyA.resize(multiBodyNumConstraints, multiBodyNumConstraints);
- }
- for (int i = 0; i < multiBodyNumConstraints; ++i)
- {
- // Compute the diagonal of A, which is A(i, i)
- const btMultiBodySolverConstraint& constraint = *m_multiBodyAllConstraintPtrArray[i];
- const btScalar diagA = computeConstraintMatrixDiagElementMultiBody(m_tmpSolverBodyPool, m_data, constraint);
- m_multiBodyA.setElem(i, i, diagA);
- // Computes the off-diagonals of A:
- // a. The rest of i-th row of A, from A(i, i+1) to A(i, n)
- // b. The rest of i-th column of A, from A(i+1, i) to A(n, i)
- for (int j = i + 1; j < multiBodyNumConstraints; ++j)
- {
- const btMultiBodySolverConstraint& offDiagConstraint = *m_multiBodyAllConstraintPtrArray[j];
- const btScalar offDiagA = computeConstraintMatrixOffDiagElementMultiBody(m_tmpSolverBodyPool, m_data, constraint, offDiagConstraint);
- // Set the off-diagonal values of A. Note that A is symmetric.
- m_multiBodyA.setElem(i, j, offDiagA);
- m_multiBodyA.setElem(j, i, offDiagA);
- }
- }
- }
- // Add CFM to the diagonal of m_A
- for (int i = 0; i < m_multiBodyA.rows(); ++i)
- {
- m_multiBodyA.setElem(i, i, m_multiBodyA(i, i) + infoGlobal.m_globalCfm / infoGlobal.m_timeStep);
- }
- // 4. Initialize x
- {
- BT_PROFILE("resize/init x");
- m_multiBodyX.resize(multiBodyNumConstraints);
- if (infoGlobal.m_solverMode & SOLVER_USE_WARMSTARTING)
- {
- for (int i = 0; i < multiBodyNumConstraints; ++i)
- {
- const btMultiBodySolverConstraint& constraint = *m_multiBodyAllConstraintPtrArray[i];
- m_multiBodyX[i] = constraint.m_appliedImpulse;
- }
- }
- else
- {
- m_multiBodyX.setZero();
- }
- }
- }
- bool btMultiBodyMLCPConstraintSolver::solveMLCP(const btContactSolverInfo& infoGlobal)
- {
- bool result = true;
- if (m_A.rows() != 0)
- {
- // If using split impulse, we solve 2 separate (M)LCPs
- if (infoGlobal.m_splitImpulse)
- {
- const btMatrixXu Acopy = m_A;
- const btAlignedObjectArray<int> limitDependenciesCopy = m_limitDependencies;
- // TODO(JS): Do we really need these copies when solveMLCP takes them as const?
- result = m_solver->solveMLCP(m_A, m_b, m_x, m_lo, m_hi, m_limitDependencies, infoGlobal.m_numIterations);
- if (result)
- result = m_solver->solveMLCP(Acopy, m_bSplit, m_xSplit, m_lo, m_hi, limitDependenciesCopy, infoGlobal.m_numIterations);
- }
- else
- {
- result = m_solver->solveMLCP(m_A, m_b, m_x, m_lo, m_hi, m_limitDependencies, infoGlobal.m_numIterations);
- }
- }
- if (!result)
- return false;
- if (m_multiBodyA.rows() != 0)
- {
- result = m_solver->solveMLCP(m_multiBodyA, m_multiBodyB, m_multiBodyX, m_multiBodyLo, m_multiBodyHi, m_multiBodyLimitDependencies, infoGlobal.m_numIterations);
- }
- return result;
- }
- btScalar btMultiBodyMLCPConstraintSolver::solveGroupCacheFriendlySetup(
- btCollisionObject** bodies,
- int numBodies,
- btPersistentManifold** manifoldPtr,
- int numManifolds,
- btTypedConstraint** constraints,
- int numConstraints,
- const btContactSolverInfo& infoGlobal,
- btIDebugDraw* debugDrawer)
- {
- // 1. Setup for rigid-bodies
- btMultiBodyConstraintSolver::solveGroupCacheFriendlySetup(
- bodies, numBodies, manifoldPtr, numManifolds, constraints, numConstraints, infoGlobal, debugDrawer);
- // 2. Setup for multi-bodies
- // a. Collect all different kinds of constraint as pointers into one array, m_allConstraintPtrArray
- // b. Set the index array for frictional contact constraints, m_limitDependencies
- {
- BT_PROFILE("gather constraint data");
- int dindex = 0;
- const int numRigidBodyConstraints = m_tmpSolverNonContactConstraintPool.size() + m_tmpSolverContactConstraintPool.size() + m_tmpSolverContactFrictionConstraintPool.size();
- const int numMultiBodyConstraints = m_multiBodyNonContactConstraints.size() + m_multiBodyNormalContactConstraints.size() + m_multiBodyFrictionContactConstraints.size();
- m_allConstraintPtrArray.resize(0);
- m_multiBodyAllConstraintPtrArray.resize(0);
- // i. Setup for rigid bodies
- m_limitDependencies.resize(numRigidBodyConstraints);
- for (int i = 0; i < m_tmpSolverNonContactConstraintPool.size(); ++i)
- {
- m_allConstraintPtrArray.push_back(&m_tmpSolverNonContactConstraintPool[i]);
- m_limitDependencies[dindex++] = -1;
- }
- int firstContactConstraintOffset = dindex;
- // The btSequentialImpulseConstraintSolver moves all friction constraints at the very end, we can also interleave them instead
- if (interleaveContactAndFriction)
- {
- for (int i = 0; i < m_tmpSolverContactConstraintPool.size(); i++)
- {
- const int numFrictionPerContact = m_tmpSolverContactConstraintPool.size() == m_tmpSolverContactFrictionConstraintPool.size() ? 1 : 2;
- m_allConstraintPtrArray.push_back(&m_tmpSolverContactConstraintPool[i]);
- m_limitDependencies[dindex++] = -1;
- m_allConstraintPtrArray.push_back(&m_tmpSolverContactFrictionConstraintPool[i * numFrictionPerContact]);
- int findex = (m_tmpSolverContactFrictionConstraintPool[i * numFrictionPerContact].m_frictionIndex * (1 + numFrictionPerContact));
- m_limitDependencies[dindex++] = findex + firstContactConstraintOffset;
- if (numFrictionPerContact == 2)
- {
- m_allConstraintPtrArray.push_back(&m_tmpSolverContactFrictionConstraintPool[i * numFrictionPerContact + 1]);
- m_limitDependencies[dindex++] = findex + firstContactConstraintOffset;
- }
- }
- }
- else
- {
- for (int i = 0; i < m_tmpSolverContactConstraintPool.size(); i++)
- {
- m_allConstraintPtrArray.push_back(&m_tmpSolverContactConstraintPool[i]);
- m_limitDependencies[dindex++] = -1;
- }
- for (int i = 0; i < m_tmpSolverContactFrictionConstraintPool.size(); i++)
- {
- m_allConstraintPtrArray.push_back(&m_tmpSolverContactFrictionConstraintPool[i]);
- m_limitDependencies[dindex++] = m_tmpSolverContactFrictionConstraintPool[i].m_frictionIndex + firstContactConstraintOffset;
- }
- }
- if (!m_allConstraintPtrArray.size())
- {
- m_A.resize(0, 0);
- m_b.resize(0);
- m_x.resize(0);
- m_lo.resize(0);
- m_hi.resize(0);
- }
- // ii. Setup for multibodies
- dindex = 0;
- m_multiBodyLimitDependencies.resize(numMultiBodyConstraints);
- for (int i = 0; i < m_multiBodyNonContactConstraints.size(); ++i)
- {
- m_multiBodyAllConstraintPtrArray.push_back(&m_multiBodyNonContactConstraints[i]);
- m_multiBodyLimitDependencies[dindex++] = -1;
- }
- firstContactConstraintOffset = dindex;
- // The btSequentialImpulseConstraintSolver moves all friction constraints at the very end, we can also interleave them instead
- if (interleaveContactAndFriction)
- {
- for (int i = 0; i < m_multiBodyNormalContactConstraints.size(); ++i)
- {
- const int numtiBodyNumFrictionPerContact = m_multiBodyNormalContactConstraints.size() == m_multiBodyFrictionContactConstraints.size() ? 1 : 2;
- m_multiBodyAllConstraintPtrArray.push_back(&m_multiBodyNormalContactConstraints[i]);
- m_multiBodyLimitDependencies[dindex++] = -1;
- btMultiBodySolverConstraint& frictionContactConstraint1 = m_multiBodyFrictionContactConstraints[i * numtiBodyNumFrictionPerContact];
- m_multiBodyAllConstraintPtrArray.push_back(&frictionContactConstraint1);
- const int findex = (frictionContactConstraint1.m_frictionIndex * (1 + numtiBodyNumFrictionPerContact)) + firstContactConstraintOffset;
- m_multiBodyLimitDependencies[dindex++] = findex;
- if (numtiBodyNumFrictionPerContact == 2)
- {
- btMultiBodySolverConstraint& frictionContactConstraint2 = m_multiBodyFrictionContactConstraints[i * numtiBodyNumFrictionPerContact + 1];
- m_multiBodyAllConstraintPtrArray.push_back(&frictionContactConstraint2);
- m_multiBodyLimitDependencies[dindex++] = findex;
- }
- }
- }
- else
- {
- for (int i = 0; i < m_multiBodyNormalContactConstraints.size(); ++i)
- {
- m_multiBodyAllConstraintPtrArray.push_back(&m_multiBodyNormalContactConstraints[i]);
- m_multiBodyLimitDependencies[dindex++] = -1;
- }
- for (int i = 0; i < m_multiBodyFrictionContactConstraints.size(); ++i)
- {
- m_multiBodyAllConstraintPtrArray.push_back(&m_multiBodyFrictionContactConstraints[i]);
- m_multiBodyLimitDependencies[dindex++] = m_multiBodyFrictionContactConstraints[i].m_frictionIndex + firstContactConstraintOffset;
- }
- }
- if (!m_multiBodyAllConstraintPtrArray.size())
- {
- m_multiBodyA.resize(0, 0);
- m_multiBodyB.resize(0);
- m_multiBodyX.resize(0);
- m_multiBodyLo.resize(0);
- m_multiBodyHi.resize(0);
- }
- }
- // Construct MLCP terms
- {
- BT_PROFILE("createMLCPFast");
- createMLCPFast(infoGlobal);
- }
- return btScalar(0);
- }
- btScalar btMultiBodyMLCPConstraintSolver::solveGroupCacheFriendlyIterations(btCollisionObject** bodies, int numBodies, btPersistentManifold** manifoldPtr, int numManifolds, btTypedConstraint** constraints, int numConstraints, const btContactSolverInfo& infoGlobal, btIDebugDraw* debugDrawer)
- {
- bool result = true;
- {
- BT_PROFILE("solveMLCP");
- result = solveMLCP(infoGlobal);
- }
- // Fallback to btSequentialImpulseConstraintSolver::solveGroupCacheFriendlyIterations if the solution isn't valid.
- if (!result)
- {
- m_fallback++;
- return btMultiBodyConstraintSolver::solveGroupCacheFriendlyIterations(bodies, numBodies, manifoldPtr, numManifolds, constraints, numConstraints, infoGlobal, debugDrawer);
- }
- {
- BT_PROFILE("process MLCP results");
- for (int i = 0; i < m_allConstraintPtrArray.size(); ++i)
- {
- const btSolverConstraint& c = *m_allConstraintPtrArray[i];
- const btScalar deltaImpulse = m_x[i] - c.m_appliedImpulse;
- c.m_appliedImpulse = m_x[i];
- int sbA = c.m_solverBodyIdA;
- int sbB = c.m_solverBodyIdB;
- btSolverBody& solverBodyA = m_tmpSolverBodyPool[sbA];
- btSolverBody& solverBodyB = m_tmpSolverBodyPool[sbB];
- solverBodyA.internalApplyImpulse(c.m_contactNormal1 * solverBodyA.internalGetInvMass(), c.m_angularComponentA, deltaImpulse);
- solverBodyB.internalApplyImpulse(c.m_contactNormal2 * solverBodyB.internalGetInvMass(), c.m_angularComponentB, deltaImpulse);
- if (infoGlobal.m_splitImpulse)
- {
- const btScalar deltaPushImpulse = m_xSplit[i] - c.m_appliedPushImpulse;
- solverBodyA.internalApplyPushImpulse(c.m_contactNormal1 * solverBodyA.internalGetInvMass(), c.m_angularComponentA, deltaPushImpulse);
- solverBodyB.internalApplyPushImpulse(c.m_contactNormal2 * solverBodyB.internalGetInvMass(), c.m_angularComponentB, deltaPushImpulse);
- c.m_appliedPushImpulse = m_xSplit[i];
- }
- }
- for (int i = 0; i < m_multiBodyAllConstraintPtrArray.size(); ++i)
- {
- btMultiBodySolverConstraint& c = *m_multiBodyAllConstraintPtrArray[i];
- const btScalar deltaImpulse = m_multiBodyX[i] - c.m_appliedImpulse;
- c.m_appliedImpulse = m_multiBodyX[i];
- btMultiBody* multiBodyA = c.m_multiBodyA;
- if (multiBodyA)
- {
- const int ndofA = multiBodyA->getNumDofs() + 6;
- applyDeltaVee(&m_data.m_deltaVelocitiesUnitImpulse[c.m_jacAindex], deltaImpulse, c.m_deltaVelAindex, ndofA);
- #ifdef DIRECTLY_UPDATE_VELOCITY_DURING_SOLVER_ITERATIONS
- //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
- //it would make the multibody solver more like the regular one with m_deltaVelocities being equivalent to btSolverBody::m_deltaLinearVelocity/m_deltaAngularVelocity
- multiBodyA->applyDeltaVeeMultiDof2(&m_data.m_deltaVelocitiesUnitImpulse[c.m_jacAindex], deltaImpulse);
- #endif // DIRECTLY_UPDATE_VELOCITY_DURING_SOLVER_ITERATIONS
- }
- else
- {
- const int sbA = c.m_solverBodyIdA;
- btSolverBody& solverBodyA = m_tmpSolverBodyPool[sbA];
- solverBodyA.internalApplyImpulse(c.m_contactNormal1 * solverBodyA.internalGetInvMass(), c.m_angularComponentA, deltaImpulse);
- }
- btMultiBody* multiBodyB = c.m_multiBodyB;
- if (multiBodyB)
- {
- const int ndofB = multiBodyB->getNumDofs() + 6;
- applyDeltaVee(&m_data.m_deltaVelocitiesUnitImpulse[c.m_jacBindex], deltaImpulse, c.m_deltaVelBindex, ndofB);
- #ifdef DIRECTLY_UPDATE_VELOCITY_DURING_SOLVER_ITERATIONS
- //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
- //it would make the multibody solver more like the regular one with m_deltaVelocities being equivalent to btSolverBody::m_deltaLinearVelocity/m_deltaAngularVelocity
- multiBodyB->applyDeltaVeeMultiDof2(&m_data.m_deltaVelocitiesUnitImpulse[c.m_jacBindex], deltaImpulse);
- #endif // DIRECTLY_UPDATE_VELOCITY_DURING_SOLVER_ITERATIONS
- }
- else
- {
- const int sbB = c.m_solverBodyIdB;
- btSolverBody& solverBodyB = m_tmpSolverBodyPool[sbB];
- solverBodyB.internalApplyImpulse(c.m_contactNormal2 * solverBodyB.internalGetInvMass(), c.m_angularComponentB, deltaImpulse);
- }
- }
- }
- return btScalar(0);
- }
- btMultiBodyMLCPConstraintSolver::btMultiBodyMLCPConstraintSolver(btMLCPSolverInterface* solver)
- : m_solver(solver), m_fallback(0)
- {
- // Do nothing
- }
- btMultiBodyMLCPConstraintSolver::~btMultiBodyMLCPConstraintSolver()
- {
- // Do nothing
- }
- void btMultiBodyMLCPConstraintSolver::setMLCPSolver(btMLCPSolverInterface* solver)
- {
- m_solver = solver;
- }
- int btMultiBodyMLCPConstraintSolver::getNumFallbacks() const
- {
- return m_fallback;
- }
- void btMultiBodyMLCPConstraintSolver::setNumFallbacks(int num)
- {
- m_fallback = num;
- }
- btConstraintSolverType btMultiBodyMLCPConstraintSolver::getSolverType() const
- {
- return BT_MLCP_SOLVER;
- }
|