2017-08-01 14:30:58 +02:00
|
|
|
/*
|
|
|
|
Bullet Continuous Collision Detection and Physics Library
|
|
|
|
Copyright (c) 2003-2013 Erwin Coumans 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.
|
|
|
|
*/
|
|
|
|
///original version written by Erwin Coumans, October 2013
|
|
|
|
|
|
|
|
#include "btMLCPSolver.h"
|
|
|
|
#include "LinearMath/btMatrixX.h"
|
|
|
|
#include "LinearMath/btQuickprof.h"
|
|
|
|
#include "btSolveProjectedGaussSeidel.h"
|
|
|
|
|
2019-01-03 14:26:51 +01:00
|
|
|
btMLCPSolver::btMLCPSolver(btMLCPSolverInterface* solver)
|
|
|
|
: m_solver(solver),
|
|
|
|
m_fallback(0)
|
2017-08-01 14:30:58 +02:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
btMLCPSolver::~btMLCPSolver()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
bool gUseMatrixMultiply = false;
|
|
|
|
bool interleaveContactAndFriction = false;
|
|
|
|
|
2019-01-03 14:26:51 +01:00
|
|
|
btScalar btMLCPSolver::solveGroupCacheFriendlySetup(btCollisionObject** bodies, int numBodiesUnUsed, btPersistentManifold** manifoldPtr, int numManifolds, btTypedConstraint** constraints, int numConstraints, const btContactSolverInfo& infoGlobal, btIDebugDraw* debugDrawer)
|
2017-08-01 14:30:58 +02:00
|
|
|
{
|
2019-01-03 14:26:51 +01:00
|
|
|
btSequentialImpulseConstraintSolver::solveGroupCacheFriendlySetup(bodies, numBodiesUnUsed, manifoldPtr, numManifolds, constraints, numConstraints, infoGlobal, debugDrawer);
|
2017-08-01 14:30:58 +02:00
|
|
|
|
|
|
|
{
|
|
|
|
BT_PROFILE("gather constraint data");
|
|
|
|
|
2019-01-03 14:26:51 +01:00
|
|
|
int numFrictionPerContact = m_tmpSolverContactConstraintPool.size() == m_tmpSolverContactFrictionConstraintPool.size() ? 1 : 2;
|
2017-08-01 14:30:58 +02:00
|
|
|
|
2019-01-03 14:26:51 +01:00
|
|
|
// int numBodies = m_tmpSolverBodyPool.size();
|
2017-08-01 14:30:58 +02:00
|
|
|
m_allConstraintPtrArray.resize(0);
|
2019-01-03 14:26:51 +01:00
|
|
|
m_limitDependencies.resize(m_tmpSolverNonContactConstraintPool.size() + m_tmpSolverContactConstraintPool.size() + m_tmpSolverContactFrictionConstraintPool.size());
|
|
|
|
btAssert(m_limitDependencies.size() == m_tmpSolverNonContactConstraintPool.size() + m_tmpSolverContactConstraintPool.size() + m_tmpSolverContactFrictionConstraintPool.size());
|
|
|
|
// printf("m_limitDependencies.size() = %d\n",m_limitDependencies.size());
|
2017-08-01 14:30:58 +02:00
|
|
|
|
|
|
|
int dindex = 0;
|
2019-01-03 14:26:51 +01:00
|
|
|
for (int i = 0; i < m_tmpSolverNonContactConstraintPool.size(); i++)
|
2017-08-01 14:30:58 +02:00
|
|
|
{
|
|
|
|
m_allConstraintPtrArray.push_back(&m_tmpSolverNonContactConstraintPool[i]);
|
|
|
|
m_limitDependencies[dindex++] = -1;
|
|
|
|
}
|
2019-01-03 14:26:51 +01:00
|
|
|
|
2017-08-01 14:30:58 +02:00
|
|
|
///The btSequentialImpulseConstraintSolver moves all friction constraints at the very end, we can also interleave them instead
|
2019-01-03 14:26:51 +01:00
|
|
|
|
|
|
|
int firstContactConstraintOffset = dindex;
|
2017-08-01 14:30:58 +02:00
|
|
|
|
|
|
|
if (interleaveContactAndFriction)
|
|
|
|
{
|
2019-01-03 14:26:51 +01:00
|
|
|
for (int i = 0; i < m_tmpSolverContactConstraintPool.size(); i++)
|
2017-08-01 14:30:58 +02:00
|
|
|
{
|
|
|
|
m_allConstraintPtrArray.push_back(&m_tmpSolverContactConstraintPool[i]);
|
|
|
|
m_limitDependencies[dindex++] = -1;
|
2019-01-03 14:26:51 +01:00
|
|
|
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)
|
2017-08-01 14:30:58 +02:00
|
|
|
{
|
2019-01-03 14:26:51 +01:00
|
|
|
m_allConstraintPtrArray.push_back(&m_tmpSolverContactFrictionConstraintPool[i * numFrictionPerContact + 1]);
|
|
|
|
m_limitDependencies[dindex++] = findex + firstContactConstraintOffset;
|
2017-08-01 14:30:58 +02:00
|
|
|
}
|
|
|
|
}
|
2019-01-03 14:26:51 +01:00
|
|
|
}
|
|
|
|
else
|
2017-08-01 14:30:58 +02:00
|
|
|
{
|
2019-01-03 14:26:51 +01:00
|
|
|
for (int i = 0; i < m_tmpSolverContactConstraintPool.size(); i++)
|
2017-08-01 14:30:58 +02:00
|
|
|
{
|
|
|
|
m_allConstraintPtrArray.push_back(&m_tmpSolverContactConstraintPool[i]);
|
|
|
|
m_limitDependencies[dindex++] = -1;
|
|
|
|
}
|
2019-01-03 14:26:51 +01:00
|
|
|
for (int i = 0; i < m_tmpSolverContactFrictionConstraintPool.size(); i++)
|
2017-08-01 14:30:58 +02:00
|
|
|
{
|
|
|
|
m_allConstraintPtrArray.push_back(&m_tmpSolverContactFrictionConstraintPool[i]);
|
2019-01-03 14:26:51 +01:00
|
|
|
m_limitDependencies[dindex++] = m_tmpSolverContactFrictionConstraintPool[i].m_frictionIndex + firstContactConstraintOffset;
|
2017-08-01 14:30:58 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!m_allConstraintPtrArray.size())
|
|
|
|
{
|
2019-01-03 14:26:51 +01:00
|
|
|
m_A.resize(0, 0);
|
2017-08-01 14:30:58 +02:00
|
|
|
m_b.resize(0);
|
|
|
|
m_x.resize(0);
|
|
|
|
m_lo.resize(0);
|
|
|
|
m_hi.resize(0);
|
|
|
|
return 0.f;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (gUseMatrixMultiply)
|
|
|
|
{
|
|
|
|
BT_PROFILE("createMLCP");
|
|
|
|
createMLCP(infoGlobal);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
BT_PROFILE("createMLCPFast");
|
|
|
|
createMLCPFast(infoGlobal);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0.f;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool btMLCPSolver::solveMLCP(const btContactSolverInfo& infoGlobal)
|
|
|
|
{
|
|
|
|
bool result = true;
|
|
|
|
|
2019-01-03 14:26:51 +01:00
|
|
|
if (m_A.rows() == 0)
|
2017-08-01 14:30:58 +02:00
|
|
|
return true;
|
|
|
|
|
|
|
|
//if using split impulse, we solve 2 separate (M)LCPs
|
|
|
|
if (infoGlobal.m_splitImpulse)
|
|
|
|
{
|
|
|
|
btMatrixXu Acopy = m_A;
|
|
|
|
btAlignedObjectArray<int> limitDependenciesCopy = m_limitDependencies;
|
2019-01-03 14:26:51 +01:00
|
|
|
// printf("solve first LCP\n");
|
|
|
|
result = m_solver->solveMLCP(m_A, m_b, m_x, m_lo, m_hi, m_limitDependencies, infoGlobal.m_numIterations);
|
2017-08-01 14:30:58 +02:00
|
|
|
if (result)
|
2019-01-03 14:26:51 +01:00
|
|
|
result = m_solver->solveMLCP(Acopy, m_bSplit, m_xSplit, m_lo, m_hi, limitDependenciesCopy, infoGlobal.m_numIterations);
|
|
|
|
}
|
|
|
|
else
|
2017-08-01 14:30:58 +02:00
|
|
|
{
|
2019-01-03 14:26:51 +01:00
|
|
|
result = m_solver->solveMLCP(m_A, m_b, m_x, m_lo, m_hi, m_limitDependencies, infoGlobal.m_numIterations);
|
2017-08-01 14:30:58 +02:00
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct btJointNode
|
|
|
|
{
|
2019-01-03 14:26:51 +01:00
|
|
|
int jointIndex; // pointer to enclosing dxJoint object
|
|
|
|
int otherBodyIndex; // *other* body this joint is connected to
|
|
|
|
int nextJointNodeIndex; //-1 for null
|
2017-08-01 14:30:58 +02:00
|
|
|
int constraintRowIndex;
|
|
|
|
};
|
|
|
|
|
|
|
|
void btMLCPSolver::createMLCPFast(const btContactSolverInfo& infoGlobal)
|
|
|
|
{
|
|
|
|
int numContactRows = interleaveContactAndFriction ? 3 : 1;
|
|
|
|
|
|
|
|
int numConstraintRows = m_allConstraintPtrArray.size();
|
|
|
|
int n = numConstraintRows;
|
|
|
|
{
|
|
|
|
BT_PROFILE("init b (rhs)");
|
|
|
|
m_b.resize(numConstraintRows);
|
|
|
|
m_bSplit.resize(numConstraintRows);
|
|
|
|
m_b.setZero();
|
|
|
|
m_bSplit.setZero();
|
2019-01-03 14:26:51 +01:00
|
|
|
for (int i = 0; i < numConstraintRows; i++)
|
2017-08-01 14:30:58 +02:00
|
|
|
{
|
|
|
|
btScalar jacDiag = m_allConstraintPtrArray[i]->m_jacDiagABInv;
|
|
|
|
if (!btFuzzyZero(jacDiag))
|
|
|
|
{
|
|
|
|
btScalar rhs = m_allConstraintPtrArray[i]->m_rhs;
|
|
|
|
btScalar rhsPenetration = m_allConstraintPtrArray[i]->m_rhsPenetration;
|
2019-01-03 14:26:51 +01:00
|
|
|
m_b[i] = rhs / jacDiag;
|
|
|
|
m_bSplit[i] = rhsPenetration / jacDiag;
|
2017-08-01 14:30:58 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-03 14:26:51 +01:00
|
|
|
// btScalar* w = 0;
|
|
|
|
// int nub = 0;
|
2017-08-01 14:30:58 +02:00
|
|
|
|
|
|
|
m_lo.resize(numConstraintRows);
|
|
|
|
m_hi.resize(numConstraintRows);
|
2019-01-03 14:26:51 +01:00
|
|
|
|
2017-08-01 14:30:58 +02:00
|
|
|
{
|
|
|
|
BT_PROFILE("init lo/ho");
|
|
|
|
|
2019-01-03 14:26:51 +01:00
|
|
|
for (int i = 0; i < numConstraintRows; i++)
|
2017-08-01 14:30:58 +02:00
|
|
|
{
|
2019-01-03 14:26:51 +01:00
|
|
|
if (0) //m_limitDependencies[i]>=0)
|
2017-08-01 14:30:58 +02:00
|
|
|
{
|
|
|
|
m_lo[i] = -BT_INFINITY;
|
|
|
|
m_hi[i] = BT_INFINITY;
|
2019-01-03 14:26:51 +01:00
|
|
|
}
|
|
|
|
else
|
2017-08-01 14:30:58 +02:00
|
|
|
{
|
|
|
|
m_lo[i] = m_allConstraintPtrArray[i]->m_lowerLimit;
|
|
|
|
m_hi[i] = m_allConstraintPtrArray[i]->m_upperLimit;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
2019-01-03 14:26:51 +01:00
|
|
|
int m = m_allConstraintPtrArray.size();
|
2017-08-01 14:30:58 +02:00
|
|
|
|
|
|
|
int numBodies = m_tmpSolverBodyPool.size();
|
|
|
|
btAlignedObjectArray<int> bodyJointNodeArray;
|
|
|
|
{
|
|
|
|
BT_PROFILE("bodyJointNodeArray.resize");
|
2019-01-03 14:26:51 +01:00
|
|
|
bodyJointNodeArray.resize(numBodies, -1);
|
2017-08-01 14:30:58 +02:00
|
|
|
}
|
|
|
|
btAlignedObjectArray<btJointNode> jointNodeArray;
|
|
|
|
{
|
|
|
|
BT_PROFILE("jointNodeArray.reserve");
|
2019-01-03 14:26:51 +01:00
|
|
|
jointNodeArray.reserve(2 * m_allConstraintPtrArray.size());
|
2017-08-01 14:30:58 +02:00
|
|
|
}
|
|
|
|
|
2019-01-03 14:26:51 +01:00
|
|
|
btMatrixXu& J3 = m_scratchJ3;
|
2017-08-01 14:30:58 +02:00
|
|
|
{
|
|
|
|
BT_PROFILE("J3.resize");
|
2019-01-03 14:26:51 +01:00
|
|
|
J3.resize(2 * m, 8);
|
2017-08-01 14:30:58 +02:00
|
|
|
}
|
2019-01-03 14:26:51 +01:00
|
|
|
btMatrixXu& JinvM3 = m_scratchJInvM3;
|
2017-08-01 14:30:58 +02:00
|
|
|
{
|
|
|
|
BT_PROFILE("JinvM3.resize/setZero");
|
|
|
|
|
2019-01-03 14:26:51 +01:00
|
|
|
JinvM3.resize(2 * m, 8);
|
2017-08-01 14:30:58 +02:00
|
|
|
JinvM3.setZero();
|
|
|
|
J3.setZero();
|
|
|
|
}
|
2019-01-03 14:26:51 +01:00
|
|
|
int cur = 0;
|
2017-08-01 14:30:58 +02:00
|
|
|
int rowOffset = 0;
|
2019-01-03 14:26:51 +01:00
|
|
|
btAlignedObjectArray<int>& ofs = m_scratchOfs;
|
2017-08-01 14:30:58 +02:00
|
|
|
{
|
|
|
|
BT_PROFILE("ofs resize");
|
|
|
|
ofs.resize(0);
|
|
|
|
ofs.resizeNoInitialize(m_allConstraintPtrArray.size());
|
2019-01-03 14:26:51 +01:00
|
|
|
}
|
2017-08-01 14:30:58 +02:00
|
|
|
{
|
|
|
|
BT_PROFILE("Compute J and JinvM");
|
2019-01-03 14:26:51 +01:00
|
|
|
int c = 0;
|
2017-08-01 14:30:58 +02:00
|
|
|
|
|
|
|
int numRows = 0;
|
|
|
|
|
2019-01-03 14:26:51 +01:00
|
|
|
for (int i = 0; i < m_allConstraintPtrArray.size(); i += numRows, c++)
|
2017-08-01 14:30:58 +02:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
|
2019-01-03 14:26:51 +01:00
|
|
|
numRows = i < m_tmpSolverNonContactConstraintPool.size() ? m_tmpConstraintSizesPool[c].m_numConstraintRows : numContactRows;
|
2017-08-01 14:30:58 +02:00
|
|
|
if (orgBodyA)
|
|
|
|
{
|
|
|
|
{
|
2019-01-03 14:26:51 +01:00
|
|
|
int slotA = -1;
|
2017-08-01 14:30:58 +02:00
|
|
|
//find free jointNode slot for sbA
|
2019-01-03 14:26:51 +01:00
|
|
|
slotA = jointNodeArray.size();
|
|
|
|
jointNodeArray.expand(); //NonInitializing();
|
2017-08-01 14:30:58 +02:00
|
|
|
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;
|
|
|
|
}
|
2019-01-03 14:26:51 +01:00
|
|
|
for (int row = 0; row < numRows; row++, cur++)
|
2017-08-01 14:30:58 +02:00
|
|
|
{
|
2019-01-03 14:26:51 +01:00
|
|
|
btVector3 normalInvMass = m_allConstraintPtrArray[i + row]->m_contactNormal1 * orgBodyA->getInvMass();
|
|
|
|
btVector3 relPosCrossNormalInvInertia = m_allConstraintPtrArray[i + row]->m_relpos1CrossNormal * orgBodyA->getInvInertiaTensorWorld();
|
2017-08-01 14:30:58 +02:00
|
|
|
|
2019-01-03 14:26:51 +01:00
|
|
|
for (int r = 0; r < 3; r++)
|
2017-08-01 14:30:58 +02:00
|
|
|
{
|
2019-01-03 14:26:51 +01:00
|
|
|
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]);
|
2017-08-01 14:30:58 +02:00
|
|
|
}
|
2019-01-03 14:26:51 +01:00
|
|
|
J3.setElem(cur, 3, 0);
|
|
|
|
JinvM3.setElem(cur, 3, 0);
|
|
|
|
J3.setElem(cur, 7, 0);
|
|
|
|
JinvM3.setElem(cur, 7, 0);
|
2017-08-01 14:30:58 +02:00
|
|
|
}
|
2019-01-03 14:26:51 +01:00
|
|
|
}
|
|
|
|
else
|
2017-08-01 14:30:58 +02:00
|
|
|
{
|
|
|
|
cur += numRows;
|
|
|
|
}
|
|
|
|
if (orgBodyB)
|
|
|
|
{
|
|
|
|
{
|
2019-01-03 14:26:51 +01:00
|
|
|
int slotB = -1;
|
2017-08-01 14:30:58 +02:00
|
|
|
//find free jointNode slot for sbA
|
2019-01-03 14:26:51 +01:00
|
|
|
slotB = jointNodeArray.size();
|
|
|
|
jointNodeArray.expand(); //NonInitializing();
|
2017-08-01 14:30:58 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2019-01-03 14:26:51 +01:00
|
|
|
for (int row = 0; row < numRows; row++, cur++)
|
2017-08-01 14:30:58 +02:00
|
|
|
{
|
2019-01-03 14:26:51 +01:00
|
|
|
btVector3 normalInvMassB = m_allConstraintPtrArray[i + row]->m_contactNormal2 * orgBodyB->getInvMass();
|
|
|
|
btVector3 relPosInvInertiaB = m_allConstraintPtrArray[i + row]->m_relpos2CrossNormal * orgBodyB->getInvInertiaTensorWorld();
|
2017-08-01 14:30:58 +02:00
|
|
|
|
2019-01-03 14:26:51 +01:00
|
|
|
for (int r = 0; r < 3; r++)
|
2017-08-01 14:30:58 +02:00
|
|
|
{
|
2019-01-03 14:26:51 +01:00
|
|
|
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]);
|
2017-08-01 14:30:58 +02:00
|
|
|
}
|
2019-01-03 14:26:51 +01:00
|
|
|
J3.setElem(cur, 3, 0);
|
|
|
|
JinvM3.setElem(cur, 3, 0);
|
|
|
|
J3.setElem(cur, 7, 0);
|
|
|
|
JinvM3.setElem(cur, 7, 0);
|
2017-08-01 14:30:58 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
cur += numRows;
|
|
|
|
}
|
2019-01-03 14:26:51 +01:00
|
|
|
rowOffset += numRows;
|
2017-08-01 14:30:58 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//compute JinvM = J*invM.
|
|
|
|
const btScalar* JinvM = JinvM3.getBufferPointer();
|
|
|
|
|
|
|
|
const btScalar* Jptr = J3.getBufferPointer();
|
|
|
|
{
|
|
|
|
BT_PROFILE("m_A.resize");
|
2019-01-03 14:26:51 +01:00
|
|
|
m_A.resize(n, n);
|
2017-08-01 14:30:58 +02:00
|
|
|
}
|
2019-01-03 14:26:51 +01:00
|
|
|
|
2017-08-01 14:30:58 +02:00
|
|
|
{
|
|
|
|
BT_PROFILE("m_A.setZero");
|
|
|
|
m_A.setZero();
|
|
|
|
}
|
2019-01-03 14:26:51 +01:00
|
|
|
int c = 0;
|
2017-08-01 14:30:58 +02:00
|
|
|
{
|
|
|
|
int numRows = 0;
|
|
|
|
BT_PROFILE("Compute A");
|
2019-01-03 14:26:51 +01:00
|
|
|
for (int i = 0; i < m_allConstraintPtrArray.size(); i += numRows, c++)
|
2017-08-01 14:30:58 +02:00
|
|
|
{
|
|
|
|
int row__ = ofs[c];
|
|
|
|
int sbA = m_allConstraintPtrArray[i]->m_solverBodyIdA;
|
|
|
|
int sbB = m_allConstraintPtrArray[i]->m_solverBodyIdB;
|
2019-01-03 14:26:51 +01:00
|
|
|
// 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;
|
2017-08-01 14:30:58 +02:00
|
|
|
|
2019-01-03 14:26:51 +01:00
|
|
|
const btScalar* JinvMrow = JinvM + 2 * 8 * (size_t)row__;
|
2017-08-01 14:30:58 +02:00
|
|
|
|
|
|
|
{
|
|
|
|
int startJointNodeA = bodyJointNodeArray[sbA];
|
2019-01-03 14:26:51 +01:00
|
|
|
while (startJointNodeA >= 0)
|
2017-08-01 14:30:58 +02:00
|
|
|
{
|
|
|
|
int j0 = jointNodeArray[startJointNodeA].jointIndex;
|
|
|
|
int cr0 = jointNodeArray[startJointNodeA].constraintRowIndex;
|
2019-01-03 14:26:51 +01:00
|
|
|
if (j0 < c)
|
2017-08-01 14:30:58 +02:00
|
|
|
{
|
|
|
|
int numRowsOther = cr0 < m_tmpSolverNonContactConstraintPool.size() ? m_tmpConstraintSizesPool[j0].m_numConstraintRows : numContactRows;
|
2019-01-03 14:26:51 +01:00
|
|
|
size_t ofsother = (m_allConstraintPtrArray[cr0]->m_solverBodyIdB == sbA) ? 8 * numRowsOther : 0;
|
2017-08-01 14:30:58 +02:00
|
|
|
//printf("%d joint i %d and j0: %d: ",count++,i,j0);
|
2019-01-03 14:26:51 +01:00
|
|
|
m_A.multiplyAdd2_p8r(JinvMrow,
|
|
|
|
Jptr + 2 * 8 * (size_t)ofs[j0] + ofsother, numRows, numRowsOther, row__, ofs[j0]);
|
2017-08-01 14:30:58 +02:00
|
|
|
}
|
|
|
|
startJointNodeA = jointNodeArray[startJointNodeA].nextJointNodeIndex;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
int startJointNodeB = bodyJointNodeArray[sbB];
|
2019-01-03 14:26:51 +01:00
|
|
|
while (startJointNodeB >= 0)
|
2017-08-01 14:30:58 +02:00
|
|
|
{
|
|
|
|
int j1 = jointNodeArray[startJointNodeB].jointIndex;
|
|
|
|
int cj1 = jointNodeArray[startJointNodeB].constraintRowIndex;
|
|
|
|
|
2019-01-03 14:26:51 +01:00
|
|
|
if (j1 < c)
|
2017-08-01 14:30:58 +02:00
|
|
|
{
|
2019-01-03 14:26:51 +01:00
|
|
|
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]);
|
2017-08-01 14:30:58 +02:00
|
|
|
}
|
|
|
|
startJointNodeB = jointNodeArray[startJointNodeB].nextJointNodeIndex;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
BT_PROFILE("compute diagonal");
|
|
|
|
// compute diagonal blocks of m_A
|
|
|
|
|
2019-01-03 14:26:51 +01:00
|
|
|
int row__ = 0;
|
2017-08-01 14:30:58 +02:00
|
|
|
int numJointRows = m_allConstraintPtrArray.size();
|
|
|
|
|
2019-01-03 14:26:51 +01:00
|
|
|
int jj = 0;
|
|
|
|
for (; row__ < numJointRows;)
|
2017-08-01 14:30:58 +02:00
|
|
|
{
|
|
|
|
//int sbA = m_allConstraintPtrArray[row__]->m_solverBodyIdA;
|
|
|
|
int sbB = m_allConstraintPtrArray[row__]->m_solverBodyIdB;
|
2019-01-03 14:26:51 +01:00
|
|
|
// btRigidBody* orgBodyA = m_tmpSolverBodyPool[sbA].m_originalBody;
|
2017-08-01 14:30:58 +02:00
|
|
|
btRigidBody* orgBodyB = m_tmpSolverBodyPool[sbB].m_originalBody;
|
|
|
|
|
2019-01-03 14:26:51 +01:00
|
|
|
const unsigned int infom = row__ < m_tmpSolverNonContactConstraintPool.size() ? m_tmpConstraintSizesPool[jj].m_numConstraintRows : numContactRows;
|
2017-08-01 14:30:58 +02:00
|
|
|
|
2019-01-03 14:26:51 +01:00
|
|
|
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)
|
2017-08-01 14:30:58 +02:00
|
|
|
{
|
2019-01-03 14:26:51 +01:00
|
|
|
m_A.multiplyAdd2_p8r(JinvMrow + 8 * (size_t)infom, Jrow + 8 * (size_t)infom, infom, infom, row__, row__);
|
2017-08-01 14:30:58 +02:00
|
|
|
}
|
|
|
|
row__ += infom;
|
|
|
|
jj++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (1)
|
|
|
|
{
|
|
|
|
// add cfm to the diagonal of m_A
|
2019-01-03 14:26:51 +01:00
|
|
|
for (int i = 0; i < m_A.rows(); ++i)
|
2017-08-01 14:30:58 +02:00
|
|
|
{
|
2019-01-03 14:26:51 +01:00
|
|
|
m_A.setElem(i, i, m_A(i, i) + infoGlobal.m_globalCfm / infoGlobal.m_timeStep);
|
2017-08-01 14:30:58 +02:00
|
|
|
}
|
|
|
|
}
|
2019-01-03 14:26:51 +01:00
|
|
|
|
2017-08-01 14:30:58 +02:00
|
|
|
///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);
|
|
|
|
|
2019-01-03 14:26:51 +01:00
|
|
|
if (infoGlobal.m_solverMode & SOLVER_USE_WARMSTARTING)
|
2017-08-01 14:30:58 +02:00
|
|
|
{
|
2019-01-03 14:26:51 +01:00
|
|
|
for (int i = 0; i < m_allConstraintPtrArray.size(); i++)
|
2017-08-01 14:30:58 +02:00
|
|
|
{
|
|
|
|
const btSolverConstraint& c = *m_allConstraintPtrArray[i];
|
2019-01-03 14:26:51 +01:00
|
|
|
m_x[i] = c.m_appliedImpulse;
|
2017-08-01 14:30:58 +02:00
|
|
|
m_xSplit[i] = c.m_appliedPushImpulse;
|
|
|
|
}
|
2019-01-03 14:26:51 +01:00
|
|
|
}
|
|
|
|
else
|
2017-08-01 14:30:58 +02:00
|
|
|
{
|
|
|
|
m_x.setZero();
|
|
|
|
m_xSplit.setZero();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void btMLCPSolver::createMLCP(const btContactSolverInfo& infoGlobal)
|
|
|
|
{
|
|
|
|
int numBodies = this->m_tmpSolverBodyPool.size();
|
|
|
|
int numConstraintRows = m_allConstraintPtrArray.size();
|
|
|
|
|
|
|
|
m_b.resize(numConstraintRows);
|
|
|
|
if (infoGlobal.m_splitImpulse)
|
|
|
|
m_bSplit.resize(numConstraintRows);
|
2019-01-03 14:26:51 +01:00
|
|
|
|
2017-08-01 14:30:58 +02:00
|
|
|
m_bSplit.setZero();
|
|
|
|
m_b.setZero();
|
|
|
|
|
2019-01-03 14:26:51 +01:00
|
|
|
for (int i = 0; i < numConstraintRows; i++)
|
2017-08-01 14:30:58 +02:00
|
|
|
{
|
|
|
|
if (m_allConstraintPtrArray[i]->m_jacDiagABInv)
|
|
|
|
{
|
2019-01-03 14:26:51 +01:00
|
|
|
m_b[i] = m_allConstraintPtrArray[i]->m_rhs / m_allConstraintPtrArray[i]->m_jacDiagABInv;
|
2017-08-01 14:30:58 +02:00
|
|
|
if (infoGlobal.m_splitImpulse)
|
2019-01-03 14:26:51 +01:00
|
|
|
m_bSplit[i] = m_allConstraintPtrArray[i]->m_rhsPenetration / m_allConstraintPtrArray[i]->m_jacDiagABInv;
|
2017-08-01 14:30:58 +02:00
|
|
|
}
|
|
|
|
}
|
2019-01-03 14:26:51 +01:00
|
|
|
|
|
|
|
btMatrixXu& Minv = m_scratchMInv;
|
|
|
|
Minv.resize(6 * numBodies, 6 * numBodies);
|
2017-08-01 14:30:58 +02:00
|
|
|
Minv.setZero();
|
2019-01-03 14:26:51 +01:00
|
|
|
for (int i = 0; i < numBodies; i++)
|
2017-08-01 14:30:58 +02:00
|
|
|
{
|
|
|
|
const btSolverBody& rb = m_tmpSolverBodyPool[i];
|
|
|
|
const btVector3& invMass = rb.m_invMass;
|
2019-01-03 14:26:51 +01:00
|
|
|
setElem(Minv, i * 6 + 0, i * 6 + 0, invMass[0]);
|
|
|
|
setElem(Minv, i * 6 + 1, i * 6 + 1, invMass[1]);
|
|
|
|
setElem(Minv, i * 6 + 2, i * 6 + 2, invMass[2]);
|
2017-08-01 14:30:58 +02:00
|
|
|
btRigidBody* orgBody = m_tmpSolverBodyPool[i].m_originalBody;
|
2019-01-03 14:26:51 +01:00
|
|
|
|
|
|
|
for (int r = 0; r < 3; r++)
|
|
|
|
for (int c = 0; c < 3; c++)
|
|
|
|
setElem(Minv, i * 6 + 3 + r, i * 6 + 3 + c, orgBody ? orgBody->getInvInertiaTensorWorld()[r][c] : 0);
|
2017-08-01 14:30:58 +02:00
|
|
|
}
|
2019-01-03 14:26:51 +01:00
|
|
|
|
|
|
|
btMatrixXu& J = m_scratchJ;
|
|
|
|
J.resize(numConstraintRows, 6 * numBodies);
|
2017-08-01 14:30:58 +02:00
|
|
|
J.setZero();
|
2019-01-03 14:26:51 +01:00
|
|
|
|
2017-08-01 14:30:58 +02:00
|
|
|
m_lo.resize(numConstraintRows);
|
|
|
|
m_hi.resize(numConstraintRows);
|
|
|
|
|
2019-01-03 14:26:51 +01:00
|
|
|
for (int i = 0; i < numConstraintRows; i++)
|
|
|
|
{
|
2017-08-01 14:30:58 +02:00
|
|
|
m_lo[i] = m_allConstraintPtrArray[i]->m_lowerLimit;
|
|
|
|
m_hi[i] = m_allConstraintPtrArray[i]->m_upperLimit;
|
2019-01-03 14:26:51 +01:00
|
|
|
|
2017-08-01 14:30:58 +02:00
|
|
|
int bodyIndex0 = m_allConstraintPtrArray[i]->m_solverBodyIdA;
|
|
|
|
int bodyIndex1 = m_allConstraintPtrArray[i]->m_solverBodyIdB;
|
|
|
|
if (m_tmpSolverBodyPool[bodyIndex0].m_originalBody)
|
|
|
|
{
|
2019-01-03 14:26:51 +01:00
|
|
|
setElem(J, i, 6 * bodyIndex0 + 0, m_allConstraintPtrArray[i]->m_contactNormal1[0]);
|
|
|
|
setElem(J, i, 6 * bodyIndex0 + 1, m_allConstraintPtrArray[i]->m_contactNormal1[1]);
|
|
|
|
setElem(J, i, 6 * bodyIndex0 + 2, m_allConstraintPtrArray[i]->m_contactNormal1[2]);
|
|
|
|
setElem(J, i, 6 * bodyIndex0 + 3, m_allConstraintPtrArray[i]->m_relpos1CrossNormal[0]);
|
|
|
|
setElem(J, i, 6 * bodyIndex0 + 4, m_allConstraintPtrArray[i]->m_relpos1CrossNormal[1]);
|
|
|
|
setElem(J, i, 6 * bodyIndex0 + 5, m_allConstraintPtrArray[i]->m_relpos1CrossNormal[2]);
|
2017-08-01 14:30:58 +02:00
|
|
|
}
|
|
|
|
if (m_tmpSolverBodyPool[bodyIndex1].m_originalBody)
|
|
|
|
{
|
2019-01-03 14:26:51 +01:00
|
|
|
setElem(J, i, 6 * bodyIndex1 + 0, m_allConstraintPtrArray[i]->m_contactNormal2[0]);
|
|
|
|
setElem(J, i, 6 * bodyIndex1 + 1, m_allConstraintPtrArray[i]->m_contactNormal2[1]);
|
|
|
|
setElem(J, i, 6 * bodyIndex1 + 2, m_allConstraintPtrArray[i]->m_contactNormal2[2]);
|
|
|
|
setElem(J, i, 6 * bodyIndex1 + 3, m_allConstraintPtrArray[i]->m_relpos2CrossNormal[0]);
|
|
|
|
setElem(J, i, 6 * bodyIndex1 + 4, m_allConstraintPtrArray[i]->m_relpos2CrossNormal[1]);
|
|
|
|
setElem(J, i, 6 * bodyIndex1 + 5, m_allConstraintPtrArray[i]->m_relpos2CrossNormal[2]);
|
2017-08-01 14:30:58 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-03 14:26:51 +01:00
|
|
|
btMatrixXu& J_transpose = m_scratchJTranspose;
|
|
|
|
J_transpose = J.transpose();
|
|
|
|
|
|
|
|
btMatrixXu& tmp = m_scratchTmp;
|
2021-09-29 15:47:08 +02:00
|
|
|
//Minv.printMatrix("Minv=");
|
2017-08-01 14:30:58 +02:00
|
|
|
{
|
|
|
|
{
|
|
|
|
BT_PROFILE("J*Minv");
|
2019-01-03 14:26:51 +01:00
|
|
|
tmp = J * Minv;
|
2017-08-01 14:30:58 +02:00
|
|
|
}
|
|
|
|
{
|
|
|
|
BT_PROFILE("J*tmp");
|
2019-01-03 14:26:51 +01:00
|
|
|
m_A = tmp * J_transpose;
|
2017-08-01 14:30:58 +02:00
|
|
|
}
|
|
|
|
}
|
2021-09-29 15:47:08 +02:00
|
|
|
//J.printMatrix("J");
|
2017-08-01 14:30:58 +02:00
|
|
|
if (1)
|
|
|
|
{
|
|
|
|
// add cfm to the diagonal of m_A
|
2019-01-03 14:26:51 +01:00
|
|
|
for (int i = 0; i < m_A.rows(); ++i)
|
2017-08-01 14:30:58 +02:00
|
|
|
{
|
2019-01-03 14:26:51 +01:00
|
|
|
m_A.setElem(i, i, m_A(i, i) + infoGlobal.m_globalCfm / infoGlobal.m_timeStep);
|
2017-08-01 14:30:58 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
m_x.resize(numConstraintRows);
|
|
|
|
if (infoGlobal.m_splitImpulse)
|
|
|
|
m_xSplit.resize(numConstraintRows);
|
2019-01-03 14:26:51 +01:00
|
|
|
// m_x.setZero();
|
2017-08-01 14:30:58 +02:00
|
|
|
|
2019-01-03 14:26:51 +01:00
|
|
|
for (int i = 0; i < m_allConstraintPtrArray.size(); i++)
|
2017-08-01 14:30:58 +02:00
|
|
|
{
|
|
|
|
const btSolverConstraint& c = *m_allConstraintPtrArray[i];
|
2019-01-03 14:26:51 +01:00
|
|
|
m_x[i] = c.m_appliedImpulse;
|
2017-08-01 14:30:58 +02:00
|
|
|
if (infoGlobal.m_splitImpulse)
|
|
|
|
m_xSplit[i] = c.m_appliedPushImpulse;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-03 14:26:51 +01:00
|
|
|
btScalar btMLCPSolver::solveGroupCacheFriendlyIterations(btCollisionObject** bodies, int numBodies, btPersistentManifold** manifoldPtr, int numManifolds, btTypedConstraint** constraints, int numConstraints, const btContactSolverInfo& infoGlobal, btIDebugDraw* debugDrawer)
|
2017-08-01 14:30:58 +02:00
|
|
|
{
|
|
|
|
bool result = true;
|
|
|
|
{
|
|
|
|
BT_PROFILE("solveMLCP");
|
2019-01-03 14:26:51 +01:00
|
|
|
// printf("m_A(%d,%d)\n", m_A.rows(),m_A.cols());
|
2017-08-01 14:30:58 +02:00
|
|
|
result = solveMLCP(infoGlobal);
|
|
|
|
}
|
|
|
|
|
|
|
|
//check if solution is valid, and otherwise fallback to btSequentialImpulseConstraintSolver::solveGroupCacheFriendlyIterations
|
|
|
|
if (result)
|
|
|
|
{
|
|
|
|
BT_PROFILE("process MLCP results");
|
2019-01-03 14:26:51 +01:00
|
|
|
for (int i = 0; i < m_allConstraintPtrArray.size(); i++)
|
2017-08-01 14:30:58 +02:00
|
|
|
{
|
|
|
|
{
|
|
|
|
btSolverConstraint& c = *m_allConstraintPtrArray[i];
|
|
|
|
int sbA = c.m_solverBodyIdA;
|
|
|
|
int sbB = c.m_solverBodyIdB;
|
|
|
|
//btRigidBody* orgBodyA = m_tmpSolverBodyPool[sbA].m_originalBody;
|
2019-01-03 14:26:51 +01:00
|
|
|
// btRigidBody* orgBodyB = m_tmpSolverBodyPool[sbB].m_originalBody;
|
2017-08-01 14:30:58 +02:00
|
|
|
|
|
|
|
btSolverBody& solverBodyA = m_tmpSolverBodyPool[sbA];
|
|
|
|
btSolverBody& solverBodyB = m_tmpSolverBodyPool[sbB];
|
2019-01-03 14:26:51 +01:00
|
|
|
|
2017-08-01 14:30:58 +02:00
|
|
|
{
|
2019-01-03 14:26:51 +01:00
|
|
|
btScalar deltaImpulse = m_x[i] - c.m_appliedImpulse;
|
2017-08-01 14:30:58 +02:00
|
|
|
c.m_appliedImpulse = m_x[i];
|
2019-01-03 14:26:51 +01:00
|
|
|
solverBodyA.internalApplyImpulse(c.m_contactNormal1 * solverBodyA.internalGetInvMass(), c.m_angularComponentA, deltaImpulse);
|
|
|
|
solverBodyB.internalApplyImpulse(c.m_contactNormal2 * solverBodyB.internalGetInvMass(), c.m_angularComponentB, deltaImpulse);
|
2017-08-01 14:30:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (infoGlobal.m_splitImpulse)
|
|
|
|
{
|
|
|
|
btScalar deltaImpulse = m_xSplit[i] - c.m_appliedPushImpulse;
|
2019-01-03 14:26:51 +01:00
|
|
|
solverBodyA.internalApplyPushImpulse(c.m_contactNormal1 * solverBodyA.internalGetInvMass(), c.m_angularComponentA, deltaImpulse);
|
|
|
|
solverBodyB.internalApplyPushImpulse(c.m_contactNormal2 * solverBodyB.internalGetInvMass(), c.m_angularComponentB, deltaImpulse);
|
2017-08-01 14:30:58 +02:00
|
|
|
c.m_appliedPushImpulse = m_xSplit[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-01-03 14:26:51 +01:00
|
|
|
// printf("m_fallback = %d\n",m_fallback);
|
2017-08-01 14:30:58 +02:00
|
|
|
m_fallback++;
|
2019-01-03 14:26:51 +01:00
|
|
|
btSequentialImpulseConstraintSolver::solveGroupCacheFriendlyIterations(bodies, numBodies, manifoldPtr, numManifolds, constraints, numConstraints, infoGlobal, debugDrawer);
|
2017-08-01 14:30:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0.f;
|
|
|
|
}
|