2 Bullet Continuous Collision Detection and Physics Library
3 Copyright (c) 2013 Erwin Coumans 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 "btMultiBodyConstraintSolver.h"
17 #include "BulletCollision/NarrowPhaseCollision/btPersistentManifold.h"
18 #include "btMultiBodyLinkCollider.h"
20 #include "BulletDynamics/ConstraintSolver/btSolverBody.h"
21 #include "btMultiBodyConstraint.h"
22 #include "BulletDynamics/ConstraintSolver/btContactSolverInfo.h"
24 #include "LinearMath/btQuickprof.h"
25 #include "BulletDynamics/Featherstone/btMultiBodySolverConstraint.h"
26 #include "LinearMath/btScalar.h"
28 btScalar btMultiBodyConstraintSolver::solveSingleIteration(int iteration, btCollisionObject** bodies, int numBodies, btPersistentManifold** manifoldPtr, int numManifolds, btTypedConstraint** constraints, int numConstraints, const btContactSolverInfo& infoGlobal, btIDebugDraw* debugDrawer)
30 btScalar leastSquaredResidual = btSequentialImpulseConstraintSolver::solveSingleIteration(iteration, bodies, numBodies, manifoldPtr, numManifolds, constraints, numConstraints, infoGlobal, debugDrawer);
32 //solve featherstone non-contact constraints
33 btScalar nonContactResidual = 0;
34 //printf("m_multiBodyNonContactConstraints = %d\n",m_multiBodyNonContactConstraints.size());
35 for (int i = 0; i < infoGlobal.m_numNonContactInnerIterations; ++i)
37 // reset the nonContactResdual to 0 at start of each inner iteration
38 nonContactResidual = 0;
39 for (int j = 0; j < m_multiBodyNonContactConstraints.size(); j++)
41 int index = iteration & 1 ? j : m_multiBodyNonContactConstraints.size() - 1 - j;
43 btMultiBodySolverConstraint& constraint = m_multiBodyNonContactConstraints[index];
45 btScalar residual = resolveSingleConstraintRowGeneric(constraint);
46 nonContactResidual = btMax(nonContactResidual, residual * residual);
48 if (constraint.m_multiBodyA)
49 constraint.m_multiBodyA->setPosUpdated(false);
50 if (constraint.m_multiBodyB)
51 constraint.m_multiBodyB->setPosUpdated(false);
54 leastSquaredResidual = btMax(leastSquaredResidual, nonContactResidual);
56 //solve featherstone normal contact
57 for (int j0 = 0; j0 < m_multiBodyNormalContactConstraints.size(); j0++)
59 int index = j0; //iteration&1? j0 : m_multiBodyNormalContactConstraints.size()-1-j0;
61 btMultiBodySolverConstraint& constraint = m_multiBodyNormalContactConstraints[index];
62 btScalar residual = 0.f;
64 if (iteration < infoGlobal.m_numIterations)
66 residual = resolveSingleConstraintRowGeneric(constraint);
69 leastSquaredResidual = btMax(leastSquaredResidual, residual * residual);
71 if (constraint.m_multiBodyA)
72 constraint.m_multiBodyA->setPosUpdated(false);
73 if (constraint.m_multiBodyB)
74 constraint.m_multiBodyB->setPosUpdated(false);
77 //solve featherstone frictional contact
78 if (infoGlobal.m_solverMode & SOLVER_USE_2_FRICTION_DIRECTIONS && ((infoGlobal.m_solverMode & SOLVER_DISABLE_IMPLICIT_CONE_FRICTION) == 0))
80 for (int j1 = 0; j1 < this->m_multiBodySpinningFrictionContactConstraints.size(); j1++)
82 if (iteration < infoGlobal.m_numIterations)
86 btMultiBodySolverConstraint& frictionConstraint = m_multiBodySpinningFrictionContactConstraints[index];
87 btScalar totalImpulse = m_multiBodyNormalContactConstraints[frictionConstraint.m_frictionIndex].m_appliedImpulse;
88 //adjust friction limits here
89 if (totalImpulse > btScalar(0))
91 frictionConstraint.m_lowerLimit = -(frictionConstraint.m_friction * totalImpulse);
92 frictionConstraint.m_upperLimit = frictionConstraint.m_friction * totalImpulse;
93 btScalar residual = resolveSingleConstraintRowGeneric(frictionConstraint);
94 leastSquaredResidual = btMax(leastSquaredResidual, residual * residual);
96 if (frictionConstraint.m_multiBodyA)
97 frictionConstraint.m_multiBodyA->setPosUpdated(false);
98 if (frictionConstraint.m_multiBodyB)
99 frictionConstraint.m_multiBodyB->setPosUpdated(false);
104 for (int j1 = 0; j1 < this->m_multiBodyTorsionalFrictionContactConstraints.size(); j1++)
106 if (iteration < infoGlobal.m_numIterations)
108 int index = j1; //iteration&1? j1 : m_multiBodyTorsionalFrictionContactConstraints.size()-1-j1;
110 btMultiBodySolverConstraint& frictionConstraint = m_multiBodyTorsionalFrictionContactConstraints[index];
111 btScalar totalImpulse = m_multiBodyNormalContactConstraints[frictionConstraint.m_frictionIndex].m_appliedImpulse;
114 btMultiBodySolverConstraint& frictionConstraintB = m_multiBodyTorsionalFrictionContactConstraints[index2];
115 //adjust friction limits here
116 if (totalImpulse > btScalar(0) && frictionConstraint.m_frictionIndex == frictionConstraintB.m_frictionIndex)
118 frictionConstraint.m_lowerLimit = -(frictionConstraint.m_friction * totalImpulse);
119 frictionConstraint.m_upperLimit = frictionConstraint.m_friction * totalImpulse;
120 frictionConstraintB.m_lowerLimit = -(frictionConstraintB.m_friction * totalImpulse);
121 frictionConstraintB.m_upperLimit = frictionConstraintB.m_friction * totalImpulse;
123 btScalar residual = resolveConeFrictionConstraintRows(frictionConstraint, frictionConstraintB);
124 leastSquaredResidual = btMax(leastSquaredResidual, residual * residual);
126 if (frictionConstraint.m_multiBodyA)
127 frictionConstraint.m_multiBodyA->setPosUpdated(false);
128 if (frictionConstraint.m_multiBodyB)
129 frictionConstraint.m_multiBodyB->setPosUpdated(false);
131 if (frictionConstraintB.m_multiBodyA)
132 frictionConstraintB.m_multiBodyA->setPosUpdated(false);
133 if (frictionConstraintB.m_multiBodyB)
134 frictionConstraintB.m_multiBodyB->setPosUpdated(false);
139 for (int j1 = 0; j1 < this->m_multiBodyFrictionContactConstraints.size(); j1++)
141 if (iteration < infoGlobal.m_numIterations)
143 int index = j1; //iteration&1? j1 : m_multiBodyFrictionContactConstraints.size()-1-j1;
144 btMultiBodySolverConstraint& frictionConstraint = m_multiBodyFrictionContactConstraints[index];
146 btScalar totalImpulse = m_multiBodyNormalContactConstraints[frictionConstraint.m_frictionIndex].m_appliedImpulse;
148 int index2 = j1; //iteration&1? j1 : m_multiBodyFrictionContactConstraints.size()-1-j1;
149 btMultiBodySolverConstraint& frictionConstraintB = m_multiBodyFrictionContactConstraints[index2];
150 btAssert(frictionConstraint.m_frictionIndex == frictionConstraintB.m_frictionIndex);
152 if (frictionConstraint.m_frictionIndex == frictionConstraintB.m_frictionIndex)
154 frictionConstraint.m_lowerLimit = -(frictionConstraint.m_friction * totalImpulse);
155 frictionConstraint.m_upperLimit = frictionConstraint.m_friction * totalImpulse;
156 frictionConstraintB.m_lowerLimit = -(frictionConstraintB.m_friction * totalImpulse);
157 frictionConstraintB.m_upperLimit = frictionConstraintB.m_friction * totalImpulse;
158 btScalar residual = resolveConeFrictionConstraintRows(frictionConstraint, frictionConstraintB);
159 leastSquaredResidual = btMax(leastSquaredResidual, residual * residual);
161 if (frictionConstraintB.m_multiBodyA)
162 frictionConstraintB.m_multiBodyA->setPosUpdated(false);
163 if (frictionConstraintB.m_multiBodyB)
164 frictionConstraintB.m_multiBodyB->setPosUpdated(false);
166 if (frictionConstraint.m_multiBodyA)
167 frictionConstraint.m_multiBodyA->setPosUpdated(false);
168 if (frictionConstraint.m_multiBodyB)
169 frictionConstraint.m_multiBodyB->setPosUpdated(false);
176 for (int j1 = 0; j1 < this->m_multiBodyFrictionContactConstraints.size(); j1++)
178 if (iteration < infoGlobal.m_numIterations)
180 int index = j1; //iteration&1? j1 : m_multiBodyFrictionContactConstraints.size()-1-j1;
182 btMultiBodySolverConstraint& frictionConstraint = m_multiBodyFrictionContactConstraints[index];
183 btScalar totalImpulse = m_multiBodyNormalContactConstraints[frictionConstraint.m_frictionIndex].m_appliedImpulse;
184 //adjust friction limits here
185 if (totalImpulse > btScalar(0))
187 frictionConstraint.m_lowerLimit = -(frictionConstraint.m_friction * totalImpulse);
188 frictionConstraint.m_upperLimit = frictionConstraint.m_friction * totalImpulse;
189 btScalar residual = resolveSingleConstraintRowGeneric(frictionConstraint);
190 leastSquaredResidual = btMax(leastSquaredResidual, residual * residual);
192 if (frictionConstraint.m_multiBodyA)
193 frictionConstraint.m_multiBodyA->setPosUpdated(false);
194 if (frictionConstraint.m_multiBodyB)
195 frictionConstraint.m_multiBodyB->setPosUpdated(false);
200 return leastSquaredResidual;
203 btScalar btMultiBodyConstraintSolver::solveGroupCacheFriendlySetup(btCollisionObject** bodies, int numBodies, btPersistentManifold** manifoldPtr, int numManifolds, btTypedConstraint** constraints, int numConstraints, const btContactSolverInfo& infoGlobal, btIDebugDraw* debugDrawer)
205 m_multiBodyNonContactConstraints.resize(0);
206 m_multiBodyNormalContactConstraints.resize(0);
207 m_multiBodyFrictionContactConstraints.resize(0);
208 m_multiBodyTorsionalFrictionContactConstraints.resize(0);
209 m_multiBodySpinningFrictionContactConstraints.resize(0);
211 m_data.m_jacobians.resize(0);
212 m_data.m_deltaVelocitiesUnitImpulse.resize(0);
213 m_data.m_deltaVelocities.resize(0);
215 for (int i = 0; i < numBodies; i++)
217 const btMultiBodyLinkCollider* fcA = btMultiBodyLinkCollider::upcast(bodies[i]);
220 fcA->m_multiBody->setCompanionId(-1);
224 btScalar val = btSequentialImpulseConstraintSolver::solveGroupCacheFriendlySetup(bodies, numBodies, manifoldPtr, numManifolds, constraints, numConstraints, infoGlobal, debugDrawer);
229 void btMultiBodyConstraintSolver::applyDeltaVee(btScalar* delta_vee, btScalar impulse, int velocityIndex, int ndof)
231 for (int i = 0; i < ndof; ++i)
232 m_data.m_deltaVelocities[velocityIndex + i] += delta_vee[i] * impulse;
235 btScalar btMultiBodyConstraintSolver::resolveSingleConstraintRowGeneric(const btMultiBodySolverConstraint& c)
237 btScalar deltaImpulse = c.m_rhs - btScalar(c.m_appliedImpulse) * c.m_cfm;
238 btScalar deltaVelADotn = 0;
239 btScalar deltaVelBDotn = 0;
240 btSolverBody* bodyA = 0;
241 btSolverBody* bodyB = 0;
247 ndofA = c.m_multiBodyA->getNumDofs() + 6;
248 for (int i = 0; i < ndofA; ++i)
249 deltaVelADotn += m_data.m_jacobians[c.m_jacAindex + i] * m_data.m_deltaVelocities[c.m_deltaVelAindex + i];
251 else if (c.m_solverBodyIdA >= 0)
253 bodyA = &m_tmpSolverBodyPool[c.m_solverBodyIdA];
254 deltaVelADotn += c.m_contactNormal1.dot(bodyA->internalGetDeltaLinearVelocity()) + c.m_relpos1CrossNormal.dot(bodyA->internalGetDeltaAngularVelocity());
259 ndofB = c.m_multiBodyB->getNumDofs() + 6;
260 for (int i = 0; i < ndofB; ++i)
261 deltaVelBDotn += m_data.m_jacobians[c.m_jacBindex + i] * m_data.m_deltaVelocities[c.m_deltaVelBindex + i];
263 else if (c.m_solverBodyIdB >= 0)
265 bodyB = &m_tmpSolverBodyPool[c.m_solverBodyIdB];
266 deltaVelBDotn += c.m_contactNormal2.dot(bodyB->internalGetDeltaLinearVelocity()) + c.m_relpos2CrossNormal.dot(bodyB->internalGetDeltaAngularVelocity());
269 deltaImpulse -= deltaVelADotn * c.m_jacDiagABInv; //m_jacDiagABInv = 1./denom
270 deltaImpulse -= deltaVelBDotn * c.m_jacDiagABInv;
271 const btScalar sum = btScalar(c.m_appliedImpulse) + deltaImpulse;
273 if (sum < c.m_lowerLimit)
275 deltaImpulse = c.m_lowerLimit - c.m_appliedImpulse;
276 c.m_appliedImpulse = c.m_lowerLimit;
278 else if (sum > c.m_upperLimit)
280 deltaImpulse = c.m_upperLimit - c.m_appliedImpulse;
281 c.m_appliedImpulse = c.m_upperLimit;
285 c.m_appliedImpulse = sum;
290 applyDeltaVee(&m_data.m_deltaVelocitiesUnitImpulse[c.m_jacAindex], deltaImpulse, c.m_deltaVelAindex, ndofA);
291 #ifdef DIRECTLY_UPDATE_VELOCITY_DURING_SOLVER_ITERATIONS
292 //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
293 //it would make the multibody solver more like the regular one with m_deltaVelocities being equivalent to btSolverBody::m_deltaLinearVelocity/m_deltaAngularVelocity
294 c.m_multiBodyA->applyDeltaVeeMultiDof2(&m_data.m_deltaVelocitiesUnitImpulse[c.m_jacAindex], deltaImpulse);
295 #endif //DIRECTLY_UPDATE_VELOCITY_DURING_SOLVER_ITERATIONS
297 else if (c.m_solverBodyIdA >= 0)
299 bodyA->internalApplyImpulse(c.m_contactNormal1 * bodyA->internalGetInvMass(), c.m_angularComponentA, deltaImpulse);
303 applyDeltaVee(&m_data.m_deltaVelocitiesUnitImpulse[c.m_jacBindex], deltaImpulse, c.m_deltaVelBindex, ndofB);
304 #ifdef DIRECTLY_UPDATE_VELOCITY_DURING_SOLVER_ITERATIONS
305 //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
306 //it would make the multibody solver more like the regular one with m_deltaVelocities being equivalent to btSolverBody::m_deltaLinearVelocity/m_deltaAngularVelocity
307 c.m_multiBodyB->applyDeltaVeeMultiDof2(&m_data.m_deltaVelocitiesUnitImpulse[c.m_jacBindex], deltaImpulse);
308 #endif //DIRECTLY_UPDATE_VELOCITY_DURING_SOLVER_ITERATIONS
310 else if (c.m_solverBodyIdB >= 0)
312 bodyB->internalApplyImpulse(c.m_contactNormal2 * bodyB->internalGetInvMass(), c.m_angularComponentB, deltaImpulse);
314 btScalar deltaVel = deltaImpulse / c.m_jacDiagABInv;
318 btScalar btMultiBodyConstraintSolver::resolveConeFrictionConstraintRows(const btMultiBodySolverConstraint& cA1, const btMultiBodySolverConstraint& cB)
322 btSolverBody* bodyA = 0;
323 btSolverBody* bodyB = 0;
324 btScalar deltaImpulseB = 0.f;
327 deltaImpulseB = cB.m_rhs - btScalar(cB.m_appliedImpulse) * cB.m_cfm;
328 btScalar deltaVelADotn = 0;
329 btScalar deltaVelBDotn = 0;
332 ndofA = cB.m_multiBodyA->getNumDofs() + 6;
333 for (int i = 0; i < ndofA; ++i)
334 deltaVelADotn += m_data.m_jacobians[cB.m_jacAindex + i] * m_data.m_deltaVelocities[cB.m_deltaVelAindex + i];
336 else if (cB.m_solverBodyIdA >= 0)
338 bodyA = &m_tmpSolverBodyPool[cB.m_solverBodyIdA];
339 deltaVelADotn += cB.m_contactNormal1.dot(bodyA->internalGetDeltaLinearVelocity()) + cB.m_relpos1CrossNormal.dot(bodyA->internalGetDeltaAngularVelocity());
344 ndofB = cB.m_multiBodyB->getNumDofs() + 6;
345 for (int i = 0; i < ndofB; ++i)
346 deltaVelBDotn += m_data.m_jacobians[cB.m_jacBindex + i] * m_data.m_deltaVelocities[cB.m_deltaVelBindex + i];
348 else if (cB.m_solverBodyIdB >= 0)
350 bodyB = &m_tmpSolverBodyPool[cB.m_solverBodyIdB];
351 deltaVelBDotn += cB.m_contactNormal2.dot(bodyB->internalGetDeltaLinearVelocity()) + cB.m_relpos2CrossNormal.dot(bodyB->internalGetDeltaAngularVelocity());
354 deltaImpulseB -= deltaVelADotn * cB.m_jacDiagABInv; //m_jacDiagABInv = 1./denom
355 deltaImpulseB -= deltaVelBDotn * cB.m_jacDiagABInv;
356 sumB = btScalar(cB.m_appliedImpulse) + deltaImpulseB;
359 btScalar deltaImpulseA = 0.f;
361 const btMultiBodySolverConstraint& cA = cA1;
364 deltaImpulseA = cA.m_rhs - btScalar(cA.m_appliedImpulse) * cA.m_cfm;
365 btScalar deltaVelADotn = 0;
366 btScalar deltaVelBDotn = 0;
369 ndofA = cA.m_multiBodyA->getNumDofs() + 6;
370 for (int i = 0; i < ndofA; ++i)
371 deltaVelADotn += m_data.m_jacobians[cA.m_jacAindex + i] * m_data.m_deltaVelocities[cA.m_deltaVelAindex + i];
373 else if (cA.m_solverBodyIdA >= 0)
375 bodyA = &m_tmpSolverBodyPool[cA.m_solverBodyIdA];
376 deltaVelADotn += cA.m_contactNormal1.dot(bodyA->internalGetDeltaLinearVelocity()) + cA.m_relpos1CrossNormal.dot(bodyA->internalGetDeltaAngularVelocity());
381 ndofB = cA.m_multiBodyB->getNumDofs() + 6;
382 for (int i = 0; i < ndofB; ++i)
383 deltaVelBDotn += m_data.m_jacobians[cA.m_jacBindex + i] * m_data.m_deltaVelocities[cA.m_deltaVelBindex + i];
385 else if (cA.m_solverBodyIdB >= 0)
387 bodyB = &m_tmpSolverBodyPool[cA.m_solverBodyIdB];
388 deltaVelBDotn += cA.m_contactNormal2.dot(bodyB->internalGetDeltaLinearVelocity()) + cA.m_relpos2CrossNormal.dot(bodyB->internalGetDeltaAngularVelocity());
391 deltaImpulseA -= deltaVelADotn * cA.m_jacDiagABInv; //m_jacDiagABInv = 1./denom
392 deltaImpulseA -= deltaVelBDotn * cA.m_jacDiagABInv;
393 sumA = btScalar(cA.m_appliedImpulse) + deltaImpulseA;
397 if (sumA * sumA + sumB * sumB >= cA.m_lowerLimit * cB.m_lowerLimit)
399 btScalar angle = btAtan2(sumA, sumB);
400 btScalar sumAclipped = btFabs(cA.m_lowerLimit * btSin(angle));
401 btScalar sumBclipped = btFabs(cB.m_lowerLimit * btCos(angle));
403 if (sumA < -sumAclipped)
405 deltaImpulseA = -sumAclipped - cA.m_appliedImpulse;
406 cA.m_appliedImpulse = -sumAclipped;
408 else if (sumA > sumAclipped)
410 deltaImpulseA = sumAclipped - cA.m_appliedImpulse;
411 cA.m_appliedImpulse = sumAclipped;
415 cA.m_appliedImpulse = sumA;
418 if (sumB < -sumBclipped)
420 deltaImpulseB = -sumBclipped - cB.m_appliedImpulse;
421 cB.m_appliedImpulse = -sumBclipped;
423 else if (sumB > sumBclipped)
425 deltaImpulseB = sumBclipped - cB.m_appliedImpulse;
426 cB.m_appliedImpulse = sumBclipped;
430 cB.m_appliedImpulse = sumB;
432 //deltaImpulseA = sumAclipped-cA.m_appliedImpulse;
433 //cA.m_appliedImpulse = sumAclipped;
434 //deltaImpulseB = sumBclipped-cB.m_appliedImpulse;
435 //cB.m_appliedImpulse = sumBclipped;
439 cA.m_appliedImpulse = sumA;
440 cB.m_appliedImpulse = sumB;
445 applyDeltaVee(&m_data.m_deltaVelocitiesUnitImpulse[cA.m_jacAindex], deltaImpulseA, cA.m_deltaVelAindex, ndofA);
446 #ifdef DIRECTLY_UPDATE_VELOCITY_DURING_SOLVER_ITERATIONS
447 //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
448 //it would make the multibody solver more like the regular one with m_deltaVelocities being equivalent to btSolverBody::m_deltaLinearVelocity/m_deltaAngularVelocity
449 cA.m_multiBodyA->applyDeltaVeeMultiDof2(&m_data.m_deltaVelocitiesUnitImpulse[cA.m_jacAindex], deltaImpulseA);
450 #endif //DIRECTLY_UPDATE_VELOCITY_DURING_SOLVER_ITERATIONS
452 else if (cA.m_solverBodyIdA >= 0)
454 bodyA->internalApplyImpulse(cA.m_contactNormal1 * bodyA->internalGetInvMass(), cA.m_angularComponentA, deltaImpulseA);
458 applyDeltaVee(&m_data.m_deltaVelocitiesUnitImpulse[cA.m_jacBindex], deltaImpulseA, cA.m_deltaVelBindex, ndofB);
459 #ifdef DIRECTLY_UPDATE_VELOCITY_DURING_SOLVER_ITERATIONS
460 //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
461 //it would make the multibody solver more like the regular one with m_deltaVelocities being equivalent to btSolverBody::m_deltaLinearVelocity/m_deltaAngularVelocity
462 cA.m_multiBodyB->applyDeltaVeeMultiDof2(&m_data.m_deltaVelocitiesUnitImpulse[cA.m_jacBindex], deltaImpulseA);
463 #endif //DIRECTLY_UPDATE_VELOCITY_DURING_SOLVER_ITERATIONS
465 else if (cA.m_solverBodyIdB >= 0)
467 bodyB->internalApplyImpulse(cA.m_contactNormal2 * bodyB->internalGetInvMass(), cA.m_angularComponentB, deltaImpulseA);
472 applyDeltaVee(&m_data.m_deltaVelocitiesUnitImpulse[cB.m_jacAindex], deltaImpulseB, cB.m_deltaVelAindex, ndofA);
473 #ifdef DIRECTLY_UPDATE_VELOCITY_DURING_SOLVER_ITERATIONS
474 //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
475 //it would make the multibody solver more like the regular one with m_deltaVelocities being equivalent to btSolverBody::m_deltaLinearVelocity/m_deltaAngularVelocity
476 cB.m_multiBodyA->applyDeltaVeeMultiDof2(&m_data.m_deltaVelocitiesUnitImpulse[cB.m_jacAindex], deltaImpulseB);
477 #endif //DIRECTLY_UPDATE_VELOCITY_DURING_SOLVER_ITERATIONS
479 else if (cB.m_solverBodyIdA >= 0)
481 bodyA->internalApplyImpulse(cB.m_contactNormal1 * bodyA->internalGetInvMass(), cB.m_angularComponentA, deltaImpulseB);
485 applyDeltaVee(&m_data.m_deltaVelocitiesUnitImpulse[cB.m_jacBindex], deltaImpulseB, cB.m_deltaVelBindex, ndofB);
486 #ifdef DIRECTLY_UPDATE_VELOCITY_DURING_SOLVER_ITERATIONS
487 //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
488 //it would make the multibody solver more like the regular one with m_deltaVelocities being equivalent to btSolverBody::m_deltaLinearVelocity/m_deltaAngularVelocity
489 cB.m_multiBodyB->applyDeltaVeeMultiDof2(&m_data.m_deltaVelocitiesUnitImpulse[cB.m_jacBindex], deltaImpulseB);
490 #endif //DIRECTLY_UPDATE_VELOCITY_DURING_SOLVER_ITERATIONS
492 else if (cB.m_solverBodyIdB >= 0)
494 bodyB->internalApplyImpulse(cB.m_contactNormal2 * bodyB->internalGetInvMass(), cB.m_angularComponentB, deltaImpulseB);
497 btScalar deltaVel = deltaImpulseA / cA.m_jacDiagABInv + deltaImpulseB / cB.m_jacDiagABInv;
501 void btMultiBodyConstraintSolver::setupMultiBodyContactConstraint(btMultiBodySolverConstraint& solverConstraint, const btVector3& contactNormal, const btScalar& appliedImpulse, btManifoldPoint& cp, const btContactSolverInfo& infoGlobal, btScalar& relaxation, bool isFriction, btScalar desiredVelocity, btScalar cfmSlip)
503 BT_PROFILE("setupMultiBodyContactConstraint");
507 btMultiBody* multiBodyA = solverConstraint.m_multiBodyA;
508 btMultiBody* multiBodyB = solverConstraint.m_multiBodyB;
510 const btVector3& pos1 = cp.getPositionWorldOnA();
511 const btVector3& pos2 = cp.getPositionWorldOnB();
513 btSolverBody* bodyA = multiBodyA ? 0 : &m_tmpSolverBodyPool[solverConstraint.m_solverBodyIdA];
514 btSolverBody* bodyB = multiBodyB ? 0 : &m_tmpSolverBodyPool[solverConstraint.m_solverBodyIdB];
516 btRigidBody* rb0 = multiBodyA ? 0 : bodyA->m_originalBody;
517 btRigidBody* rb1 = multiBodyB ? 0 : bodyB->m_originalBody;
520 rel_pos1 = pos1 - bodyA->getWorldTransform().getOrigin();
522 rel_pos2 = pos2 - bodyB->getWorldTransform().getOrigin();
524 relaxation = infoGlobal.m_sor;
526 btScalar invTimeStep = btScalar(1) / infoGlobal.m_timeStep;
528 //cfm = 1 / ( dt * kp + kd )
529 //erp = dt * kp / ( dt * kp + kd )
535 cfm = infoGlobal.m_frictionCFM;
536 erp = infoGlobal.m_frictionERP;
540 cfm = infoGlobal.m_globalCfm;
541 erp = infoGlobal.m_erp2;
543 if ((cp.m_contactPointFlags & BT_CONTACT_FLAG_HAS_CONTACT_CFM) || (cp.m_contactPointFlags & BT_CONTACT_FLAG_HAS_CONTACT_ERP))
545 if (cp.m_contactPointFlags & BT_CONTACT_FLAG_HAS_CONTACT_CFM)
546 cfm = cp.m_contactCFM;
547 if (cp.m_contactPointFlags & BT_CONTACT_FLAG_HAS_CONTACT_ERP)
548 erp = cp.m_contactERP;
552 if (cp.m_contactPointFlags & BT_CONTACT_FLAG_CONTACT_STIFFNESS_DAMPING)
554 btScalar denom = (infoGlobal.m_timeStep * cp.m_combinedContactStiffness1 + cp.m_combinedContactDamping1);
555 if (denom < SIMD_EPSILON)
557 denom = SIMD_EPSILON;
559 cfm = btScalar(1) / denom;
560 erp = (infoGlobal.m_timeStep * cp.m_combinedContactStiffness1) / denom;
569 if (solverConstraint.m_linkA < 0)
571 rel_pos1 = pos1 - multiBodyA->getBasePos();
575 rel_pos1 = pos1 - multiBodyA->getLink(solverConstraint.m_linkA).m_cachedWorldTransform.getOrigin();
577 const int ndofA = multiBodyA->getNumDofs() + 6;
579 solverConstraint.m_deltaVelAindex = multiBodyA->getCompanionId();
581 if (solverConstraint.m_deltaVelAindex < 0)
583 solverConstraint.m_deltaVelAindex = m_data.m_deltaVelocities.size();
584 multiBodyA->setCompanionId(solverConstraint.m_deltaVelAindex);
585 m_data.m_deltaVelocities.resize(m_data.m_deltaVelocities.size() + ndofA);
589 btAssert(m_data.m_deltaVelocities.size() >= solverConstraint.m_deltaVelAindex + ndofA);
592 solverConstraint.m_jacAindex = m_data.m_jacobians.size();
593 m_data.m_jacobians.resize(m_data.m_jacobians.size() + ndofA);
594 m_data.m_deltaVelocitiesUnitImpulse.resize(m_data.m_deltaVelocitiesUnitImpulse.size() + ndofA);
595 btAssert(m_data.m_jacobians.size() == m_data.m_deltaVelocitiesUnitImpulse.size());
597 btScalar* jac1 = &m_data.m_jacobians[solverConstraint.m_jacAindex];
598 multiBodyA->fillContactJacobianMultiDof(solverConstraint.m_linkA, cp.getPositionWorldOnA(), contactNormal, jac1, m_data.scratch_r, m_data.scratch_v, m_data.scratch_m);
599 btScalar* delta = &m_data.m_deltaVelocitiesUnitImpulse[solverConstraint.m_jacAindex];
600 multiBodyA->calcAccelerationDeltasMultiDof(&m_data.m_jacobians[solverConstraint.m_jacAindex], delta, m_data.scratch_r, m_data.scratch_v);
602 btVector3 torqueAxis0 = rel_pos1.cross(contactNormal);
603 solverConstraint.m_relpos1CrossNormal = torqueAxis0;
604 solverConstraint.m_contactNormal1 = contactNormal;
608 btVector3 torqueAxis0 = rel_pos1.cross(contactNormal);
609 solverConstraint.m_relpos1CrossNormal = torqueAxis0;
610 solverConstraint.m_contactNormal1 = contactNormal;
611 solverConstraint.m_angularComponentA = rb0 ? rb0->getInvInertiaTensorWorld() * torqueAxis0 * rb0->getAngularFactor() : btVector3(0, 0, 0);
616 if (solverConstraint.m_linkB < 0)
618 rel_pos2 = pos2 - multiBodyB->getBasePos();
622 rel_pos2 = pos2 - multiBodyB->getLink(solverConstraint.m_linkB).m_cachedWorldTransform.getOrigin();
625 const int ndofB = multiBodyB->getNumDofs() + 6;
627 solverConstraint.m_deltaVelBindex = multiBodyB->getCompanionId();
628 if (solverConstraint.m_deltaVelBindex < 0)
630 solverConstraint.m_deltaVelBindex = m_data.m_deltaVelocities.size();
631 multiBodyB->setCompanionId(solverConstraint.m_deltaVelBindex);
632 m_data.m_deltaVelocities.resize(m_data.m_deltaVelocities.size() + ndofB);
635 solverConstraint.m_jacBindex = m_data.m_jacobians.size();
637 m_data.m_jacobians.resize(m_data.m_jacobians.size() + ndofB);
638 m_data.m_deltaVelocitiesUnitImpulse.resize(m_data.m_deltaVelocitiesUnitImpulse.size() + ndofB);
639 btAssert(m_data.m_jacobians.size() == m_data.m_deltaVelocitiesUnitImpulse.size());
641 multiBodyB->fillContactJacobianMultiDof(solverConstraint.m_linkB, cp.getPositionWorldOnB(), -contactNormal, &m_data.m_jacobians[solverConstraint.m_jacBindex], m_data.scratch_r, m_data.scratch_v, m_data.scratch_m);
642 multiBodyB->calcAccelerationDeltasMultiDof(&m_data.m_jacobians[solverConstraint.m_jacBindex], &m_data.m_deltaVelocitiesUnitImpulse[solverConstraint.m_jacBindex], m_data.scratch_r, m_data.scratch_v);
644 btVector3 torqueAxis1 = rel_pos2.cross(contactNormal);
645 solverConstraint.m_relpos2CrossNormal = -torqueAxis1;
646 solverConstraint.m_contactNormal2 = -contactNormal;
650 btVector3 torqueAxis1 = rel_pos2.cross(contactNormal);
651 solverConstraint.m_relpos2CrossNormal = -torqueAxis1;
652 solverConstraint.m_contactNormal2 = -contactNormal;
654 solverConstraint.m_angularComponentB = rb1 ? rb1->getInvInertiaTensorWorld() * -torqueAxis1 * rb1->getAngularFactor() : btVector3(0, 0, 0);
659 btScalar denom0 = 0.f;
660 btScalar denom1 = 0.f;
663 btScalar* lambdaA = 0;
664 btScalar* lambdaB = 0;
668 ndofA = multiBodyA->getNumDofs() + 6;
669 jacA = &m_data.m_jacobians[solverConstraint.m_jacAindex];
670 lambdaA = &m_data.m_deltaVelocitiesUnitImpulse[solverConstraint.m_jacAindex];
671 for (int i = 0; i < ndofA; ++i)
673 btScalar j = jacA[i];
674 btScalar l = lambdaA[i];
682 vec = (solverConstraint.m_angularComponentA).cross(rel_pos1);
683 denom0 = rb0->getInvMass() + contactNormal.dot(vec);
688 const int ndofB = multiBodyB->getNumDofs() + 6;
689 jacB = &m_data.m_jacobians[solverConstraint.m_jacBindex];
690 lambdaB = &m_data.m_deltaVelocitiesUnitImpulse[solverConstraint.m_jacBindex];
691 for (int i = 0; i < ndofB; ++i)
693 btScalar j = jacB[i];
694 btScalar l = lambdaB[i];
702 vec = (-solverConstraint.m_angularComponentB).cross(rel_pos2);
703 denom1 = rb1->getInvMass() + contactNormal.dot(vec);
707 btScalar d = denom0 + denom1 + cfm;
708 if (d > SIMD_EPSILON)
710 solverConstraint.m_jacDiagABInv = relaxation / (d);
714 //disable the constraint row to handle singularity/redundant constraint
715 solverConstraint.m_jacDiagABInv = 0.f;
719 //compute rhs and remaining solverConstraint fields
721 btScalar restitution = 0.f;
722 btScalar distance = 0;
725 distance = cp.getDistance() + infoGlobal.m_linearSlop;
729 if (cp.m_contactPointFlags & BT_CONTACT_FLAG_FRICTION_ANCHOR)
731 distance = (cp.getPositionWorldOnA() - cp.getPositionWorldOnB()).dot(contactNormal);
735 btScalar rel_vel = 0.f;
739 btVector3 vel1, vel2;
742 ndofA = multiBodyA->getNumDofs() + 6;
743 btScalar* jacA = &m_data.m_jacobians[solverConstraint.m_jacAindex];
744 for (int i = 0; i < ndofA; ++i)
745 rel_vel += multiBodyA->getVelocityVector()[i] * jacA[i];
751 rel_vel += (rb0->getVelocityInLocalPoint(rel_pos1) +
752 (rb0->getTotalTorque() * rb0->getInvInertiaTensorWorld() * infoGlobal.m_timeStep).cross(rel_pos1) +
753 rb0->getTotalForce() * rb0->getInvMass() * infoGlobal.m_timeStep)
754 .dot(solverConstraint.m_contactNormal1);
759 ndofB = multiBodyB->getNumDofs() + 6;
760 btScalar* jacB = &m_data.m_jacobians[solverConstraint.m_jacBindex];
761 for (int i = 0; i < ndofB; ++i)
762 rel_vel += multiBodyB->getVelocityVector()[i] * jacB[i];
768 rel_vel += (rb1->getVelocityInLocalPoint(rel_pos2) +
769 (rb1->getTotalTorque() * rb1->getInvInertiaTensorWorld() * infoGlobal.m_timeStep).cross(rel_pos2) +
770 rb1->getTotalForce() * rb1->getInvMass() * infoGlobal.m_timeStep)
771 .dot(solverConstraint.m_contactNormal2);
775 solverConstraint.m_friction = cp.m_combinedFriction;
779 restitution = restitutionCurve(rel_vel, cp.m_combinedRestitution, infoGlobal.m_restitutionVelocityThreshold);
780 if (restitution <= btScalar(0.))
788 btScalar positionalError = 0.f;
789 btScalar velocityError = restitution - rel_vel; // * damping; //note for friction restitution is always set to 0 (check above) so it is acutally velocityError = -rel_vel for friction
792 positionalError = -distance * erp / infoGlobal.m_timeStep;
799 velocityError -= distance / infoGlobal.m_timeStep;
803 positionalError = -distance * erp / infoGlobal.m_timeStep;
807 btScalar penetrationImpulse = positionalError * solverConstraint.m_jacDiagABInv;
808 btScalar velocityImpulse = velocityError * solverConstraint.m_jacDiagABInv;
812 // if (!infoGlobal.m_splitImpulse || (penetration > infoGlobal.m_splitImpulsePenetrationThreshold))
814 //combine position and velocity into rhs
815 solverConstraint.m_rhs = penetrationImpulse + velocityImpulse;
816 solverConstraint.m_rhsPenetration = 0.f;
820 //split position and velocity into rhs and m_rhsPenetration
821 solverConstraint.m_rhs = velocityImpulse;
822 solverConstraint.m_rhsPenetration = penetrationImpulse;
825 solverConstraint.m_lowerLimit = 0;
826 solverConstraint.m_upperLimit = 1e10f;
830 solverConstraint.m_rhs = penetrationImpulse + velocityImpulse;
831 solverConstraint.m_rhsPenetration = 0.f;
832 solverConstraint.m_lowerLimit = -solverConstraint.m_friction;
833 solverConstraint.m_upperLimit = solverConstraint.m_friction;
836 solverConstraint.m_cfm = cfm * solverConstraint.m_jacDiagABInv;
839 if (infoGlobal.m_solverMode & SOLVER_USE_ARTICULATED_WARMSTARTING)
841 if (btFabs(cp.m_prevRHS) > 1e-5 && cp.m_prevRHS < 2* solverConstraint.m_rhs && solverConstraint.m_rhs < 2*cp.m_prevRHS)
843 solverConstraint.m_appliedImpulse = isFriction ? 0 : cp.m_appliedImpulse / cp.m_prevRHS * solverConstraint.m_rhs * infoGlobal.m_articulatedWarmstartingFactor;
844 if (solverConstraint.m_appliedImpulse < 0)
845 solverConstraint.m_appliedImpulse = 0;
849 solverConstraint.m_appliedImpulse = 0.f;
852 if (solverConstraint.m_appliedImpulse)
856 btScalar impulse = solverConstraint.m_appliedImpulse;
857 btScalar* deltaV = &m_data.m_deltaVelocitiesUnitImpulse[solverConstraint.m_jacAindex];
858 multiBodyA->applyDeltaVeeMultiDof2(deltaV, impulse);
860 applyDeltaVee(deltaV, impulse, solverConstraint.m_deltaVelAindex, ndofA);
865 bodyA->internalApplyImpulse(solverConstraint.m_contactNormal1 * bodyA->internalGetInvMass() * rb0->getLinearFactor(), solverConstraint.m_angularComponentA, solverConstraint.m_appliedImpulse);
869 btScalar impulse = solverConstraint.m_appliedImpulse;
870 btScalar* deltaV = &m_data.m_deltaVelocitiesUnitImpulse[solverConstraint.m_jacBindex];
871 multiBodyB->applyDeltaVeeMultiDof2(deltaV, impulse);
872 applyDeltaVee(deltaV, impulse, solverConstraint.m_deltaVelBindex, ndofB);
877 bodyB->internalApplyImpulse(-solverConstraint.m_contactNormal2 * bodyB->internalGetInvMass() * rb1->getLinearFactor(), -solverConstraint.m_angularComponentB, -(btScalar)solverConstraint.m_appliedImpulse);
883 solverConstraint.m_appliedImpulse = 0.f;
884 solverConstraint.m_appliedPushImpulse = 0.f;
888 void btMultiBodyConstraintSolver::setupMultiBodyTorsionalFrictionConstraint(btMultiBodySolverConstraint& solverConstraint,
889 const btVector3& constraintNormal,
891 btScalar combinedTorsionalFriction,
892 const btContactSolverInfo& infoGlobal,
893 btScalar& relaxation,
894 bool isFriction, btScalar desiredVelocity, btScalar cfmSlip)
896 BT_PROFILE("setupMultiBodyRollingFrictionConstraint");
900 btMultiBody* multiBodyA = solverConstraint.m_multiBodyA;
901 btMultiBody* multiBodyB = solverConstraint.m_multiBodyB;
903 const btVector3& pos1 = cp.getPositionWorldOnA();
904 const btVector3& pos2 = cp.getPositionWorldOnB();
906 btSolverBody* bodyA = multiBodyA ? 0 : &m_tmpSolverBodyPool[solverConstraint.m_solverBodyIdA];
907 btSolverBody* bodyB = multiBodyB ? 0 : &m_tmpSolverBodyPool[solverConstraint.m_solverBodyIdB];
909 btRigidBody* rb0 = multiBodyA ? 0 : bodyA->m_originalBody;
910 btRigidBody* rb1 = multiBodyB ? 0 : bodyB->m_originalBody;
913 rel_pos1 = pos1 - bodyA->getWorldTransform().getOrigin();
915 rel_pos2 = pos2 - bodyB->getWorldTransform().getOrigin();
917 relaxation = infoGlobal.m_sor;
919 // btScalar invTimeStep = btScalar(1)/infoGlobal.m_timeStep;
923 if (solverConstraint.m_linkA < 0)
925 rel_pos1 = pos1 - multiBodyA->getBasePos();
929 rel_pos1 = pos1 - multiBodyA->getLink(solverConstraint.m_linkA).m_cachedWorldTransform.getOrigin();
931 const int ndofA = multiBodyA->getNumDofs() + 6;
933 solverConstraint.m_deltaVelAindex = multiBodyA->getCompanionId();
935 if (solverConstraint.m_deltaVelAindex < 0)
937 solverConstraint.m_deltaVelAindex = m_data.m_deltaVelocities.size();
938 multiBodyA->setCompanionId(solverConstraint.m_deltaVelAindex);
939 m_data.m_deltaVelocities.resize(m_data.m_deltaVelocities.size() + ndofA);
943 btAssert(m_data.m_deltaVelocities.size() >= solverConstraint.m_deltaVelAindex + ndofA);
946 solverConstraint.m_jacAindex = m_data.m_jacobians.size();
947 m_data.m_jacobians.resize(m_data.m_jacobians.size() + ndofA);
948 m_data.m_deltaVelocitiesUnitImpulse.resize(m_data.m_deltaVelocitiesUnitImpulse.size() + ndofA);
949 btAssert(m_data.m_jacobians.size() == m_data.m_deltaVelocitiesUnitImpulse.size());
951 btScalar* jac1 = &m_data.m_jacobians[solverConstraint.m_jacAindex];
952 multiBodyA->fillConstraintJacobianMultiDof(solverConstraint.m_linkA, cp.getPositionWorldOnA(), constraintNormal, btVector3(0, 0, 0), jac1, m_data.scratch_r, m_data.scratch_v, m_data.scratch_m);
953 btScalar* delta = &m_data.m_deltaVelocitiesUnitImpulse[solverConstraint.m_jacAindex];
954 multiBodyA->calcAccelerationDeltasMultiDof(&m_data.m_jacobians[solverConstraint.m_jacAindex], delta, m_data.scratch_r, m_data.scratch_v);
956 btVector3 torqueAxis0 = constraintNormal;
957 solverConstraint.m_relpos1CrossNormal = torqueAxis0;
958 solverConstraint.m_contactNormal1 = btVector3(0, 0, 0);
962 btVector3 torqueAxis0 = constraintNormal;
963 solverConstraint.m_relpos1CrossNormal = torqueAxis0;
964 solverConstraint.m_contactNormal1 = btVector3(0, 0, 0);
965 solverConstraint.m_angularComponentA = rb0 ? rb0->getInvInertiaTensorWorld() * torqueAxis0 * rb0->getAngularFactor() : btVector3(0, 0, 0);
970 if (solverConstraint.m_linkB < 0)
972 rel_pos2 = pos2 - multiBodyB->getBasePos();
976 rel_pos2 = pos2 - multiBodyB->getLink(solverConstraint.m_linkB).m_cachedWorldTransform.getOrigin();
979 const int ndofB = multiBodyB->getNumDofs() + 6;
981 solverConstraint.m_deltaVelBindex = multiBodyB->getCompanionId();
982 if (solverConstraint.m_deltaVelBindex < 0)
984 solverConstraint.m_deltaVelBindex = m_data.m_deltaVelocities.size();
985 multiBodyB->setCompanionId(solverConstraint.m_deltaVelBindex);
986 m_data.m_deltaVelocities.resize(m_data.m_deltaVelocities.size() + ndofB);
989 solverConstraint.m_jacBindex = m_data.m_jacobians.size();
991 m_data.m_jacobians.resize(m_data.m_jacobians.size() + ndofB);
992 m_data.m_deltaVelocitiesUnitImpulse.resize(m_data.m_deltaVelocitiesUnitImpulse.size() + ndofB);
993 btAssert(m_data.m_jacobians.size() == m_data.m_deltaVelocitiesUnitImpulse.size());
995 multiBodyB->fillConstraintJacobianMultiDof(solverConstraint.m_linkB, cp.getPositionWorldOnB(), -constraintNormal, btVector3(0, 0, 0), &m_data.m_jacobians[solverConstraint.m_jacBindex], m_data.scratch_r, m_data.scratch_v, m_data.scratch_m);
996 multiBodyB->calcAccelerationDeltasMultiDof(&m_data.m_jacobians[solverConstraint.m_jacBindex], &m_data.m_deltaVelocitiesUnitImpulse[solverConstraint.m_jacBindex], m_data.scratch_r, m_data.scratch_v);
998 btVector3 torqueAxis1 = -constraintNormal;
999 solverConstraint.m_relpos2CrossNormal = torqueAxis1;
1000 solverConstraint.m_contactNormal2 = -btVector3(0, 0, 0);
1004 btVector3 torqueAxis1 = -constraintNormal;
1005 solverConstraint.m_relpos2CrossNormal = torqueAxis1;
1006 solverConstraint.m_contactNormal2 = -btVector3(0, 0, 0);
1008 solverConstraint.m_angularComponentB = rb1 ? rb1->getInvInertiaTensorWorld() * torqueAxis1 * rb1->getAngularFactor() : btVector3(0, 0, 0);
1012 btScalar denom0 = 0.f;
1013 btScalar denom1 = 0.f;
1016 btScalar* lambdaA = 0;
1017 btScalar* lambdaB = 0;
1021 ndofA = multiBodyA->getNumDofs() + 6;
1022 jacA = &m_data.m_jacobians[solverConstraint.m_jacAindex];
1023 lambdaA = &m_data.m_deltaVelocitiesUnitImpulse[solverConstraint.m_jacAindex];
1024 for (int i = 0; i < ndofA; ++i)
1026 btScalar j = jacA[i];
1027 btScalar l = lambdaA[i];
1035 btVector3 iMJaA = rb0 ? rb0->getInvInertiaTensorWorld() * solverConstraint.m_relpos1CrossNormal : btVector3(0, 0, 0);
1036 denom0 = iMJaA.dot(solverConstraint.m_relpos1CrossNormal);
1041 const int ndofB = multiBodyB->getNumDofs() + 6;
1042 jacB = &m_data.m_jacobians[solverConstraint.m_jacBindex];
1043 lambdaB = &m_data.m_deltaVelocitiesUnitImpulse[solverConstraint.m_jacBindex];
1044 for (int i = 0; i < ndofB; ++i)
1046 btScalar j = jacB[i];
1047 btScalar l = lambdaB[i];
1055 btVector3 iMJaB = rb1 ? rb1->getInvInertiaTensorWorld() * solverConstraint.m_relpos2CrossNormal : btVector3(0, 0, 0);
1056 denom1 = iMJaB.dot(solverConstraint.m_relpos2CrossNormal);
1060 btScalar d = denom0 + denom1 + infoGlobal.m_globalCfm;
1061 if (d > SIMD_EPSILON)
1063 solverConstraint.m_jacDiagABInv = relaxation / (d);
1067 //disable the constraint row to handle singularity/redundant constraint
1068 solverConstraint.m_jacDiagABInv = 0.f;
1072 //compute rhs and remaining solverConstraint fields
1074 btScalar restitution = 0.f;
1075 btScalar penetration = isFriction ? 0 : cp.getDistance();
1077 btScalar rel_vel = 0.f;
1081 btVector3 vel1, vel2;
1084 ndofA = multiBodyA->getNumDofs() + 6;
1085 btScalar* jacA = &m_data.m_jacobians[solverConstraint.m_jacAindex];
1086 for (int i = 0; i < ndofA; ++i)
1087 rel_vel += multiBodyA->getVelocityVector()[i] * jacA[i];
1093 btSolverBody* solverBodyA = &m_tmpSolverBodyPool[solverConstraint.m_solverBodyIdA];
1094 rel_vel += solverConstraint.m_contactNormal1.dot(rb0 ? solverBodyA->m_linearVelocity + solverBodyA->m_externalForceImpulse : btVector3(0, 0, 0)) + solverConstraint.m_relpos1CrossNormal.dot(rb0 ? solverBodyA->m_angularVelocity : btVector3(0, 0, 0));
1099 ndofB = multiBodyB->getNumDofs() + 6;
1100 btScalar* jacB = &m_data.m_jacobians[solverConstraint.m_jacBindex];
1101 for (int i = 0; i < ndofB; ++i)
1102 rel_vel += multiBodyB->getVelocityVector()[i] * jacB[i];
1108 btSolverBody* solverBodyB = &m_tmpSolverBodyPool[solverConstraint.m_solverBodyIdB];
1109 rel_vel += solverConstraint.m_contactNormal2.dot(rb1 ? solverBodyB->m_linearVelocity + solverBodyB->m_externalForceImpulse : btVector3(0, 0, 0)) + solverConstraint.m_relpos2CrossNormal.dot(rb1 ? solverBodyB->m_angularVelocity : btVector3(0, 0, 0));
1113 solverConstraint.m_friction = combinedTorsionalFriction;
1117 restitution = restitutionCurve(rel_vel, cp.m_combinedRestitution, infoGlobal.m_restitutionVelocityThreshold);
1118 if (restitution <= btScalar(0.))
1125 solverConstraint.m_appliedImpulse = 0.f;
1126 solverConstraint.m_appliedPushImpulse = 0.f;
1129 btScalar velocityError = 0 - rel_vel; // * damping; //note for friction restitution is always set to 0 (check above) so it is acutally velocityError = -rel_vel for friction
1131 btScalar velocityImpulse = velocityError * solverConstraint.m_jacDiagABInv;
1133 solverConstraint.m_rhs = velocityImpulse;
1134 solverConstraint.m_rhsPenetration = 0.f;
1135 solverConstraint.m_lowerLimit = -solverConstraint.m_friction;
1136 solverConstraint.m_upperLimit = solverConstraint.m_friction;
1138 solverConstraint.m_cfm = infoGlobal.m_globalCfm * solverConstraint.m_jacDiagABInv;
1142 btMultiBodySolverConstraint& btMultiBodyConstraintSolver::addMultiBodyFrictionConstraint(const btVector3& normalAxis, const btScalar& appliedImpulse, btPersistentManifold* manifold, int frictionIndex, btManifoldPoint& cp, btCollisionObject* colObj0, btCollisionObject* colObj1, btScalar relaxation, const btContactSolverInfo& infoGlobal, btScalar desiredVelocity, btScalar cfmSlip)
1144 BT_PROFILE("addMultiBodyFrictionConstraint");
1145 btMultiBodySolverConstraint& solverConstraint = m_multiBodyFrictionContactConstraints.expandNonInitializing();
1146 solverConstraint.m_orgConstraint = 0;
1147 solverConstraint.m_orgDofIndex = -1;
1149 solverConstraint.m_frictionIndex = frictionIndex;
1150 bool isFriction = true;
1152 const btMultiBodyLinkCollider* fcA = btMultiBodyLinkCollider::upcast(manifold->getBody0());
1153 const btMultiBodyLinkCollider* fcB = btMultiBodyLinkCollider::upcast(manifold->getBody1());
1155 btMultiBody* mbA = fcA ? fcA->m_multiBody : 0;
1156 btMultiBody* mbB = fcB ? fcB->m_multiBody : 0;
1158 int solverBodyIdA = mbA ? -1 : getOrInitSolverBody(*colObj0, infoGlobal.m_timeStep);
1159 int solverBodyIdB = mbB ? -1 : getOrInitSolverBody(*colObj1, infoGlobal.m_timeStep);
1161 solverConstraint.m_solverBodyIdA = solverBodyIdA;
1162 solverConstraint.m_solverBodyIdB = solverBodyIdB;
1163 solverConstraint.m_multiBodyA = mbA;
1165 solverConstraint.m_linkA = fcA->m_link;
1167 solverConstraint.m_multiBodyB = mbB;
1169 solverConstraint.m_linkB = fcB->m_link;
1171 solverConstraint.m_originalContactPoint = &cp;
1173 setupMultiBodyContactConstraint(solverConstraint, normalAxis, 0, cp, infoGlobal, relaxation, isFriction, desiredVelocity, cfmSlip);
1174 return solverConstraint;
1177 btMultiBodySolverConstraint& btMultiBodyConstraintSolver::addMultiBodyTorsionalFrictionConstraint(const btVector3& normalAxis, btPersistentManifold* manifold, int frictionIndex, btManifoldPoint& cp,
1178 btScalar combinedTorsionalFriction,
1179 btCollisionObject* colObj0, btCollisionObject* colObj1, btScalar relaxation, const btContactSolverInfo& infoGlobal, btScalar desiredVelocity, btScalar cfmSlip)
1181 BT_PROFILE("addMultiBodyRollingFrictionConstraint");
1183 bool useTorsionalAndConeFriction = (infoGlobal.m_solverMode & SOLVER_USE_2_FRICTION_DIRECTIONS && ((infoGlobal.m_solverMode & SOLVER_DISABLE_IMPLICIT_CONE_FRICTION) == 0));
1185 btMultiBodySolverConstraint& solverConstraint = useTorsionalAndConeFriction ? m_multiBodyTorsionalFrictionContactConstraints.expandNonInitializing() : m_multiBodyFrictionContactConstraints.expandNonInitializing();
1186 solverConstraint.m_orgConstraint = 0;
1187 solverConstraint.m_orgDofIndex = -1;
1189 solverConstraint.m_frictionIndex = frictionIndex;
1190 bool isFriction = true;
1192 const btMultiBodyLinkCollider* fcA = btMultiBodyLinkCollider::upcast(manifold->getBody0());
1193 const btMultiBodyLinkCollider* fcB = btMultiBodyLinkCollider::upcast(manifold->getBody1());
1195 btMultiBody* mbA = fcA ? fcA->m_multiBody : 0;
1196 btMultiBody* mbB = fcB ? fcB->m_multiBody : 0;
1198 int solverBodyIdA = mbA ? -1 : getOrInitSolverBody(*colObj0, infoGlobal.m_timeStep);
1199 int solverBodyIdB = mbB ? -1 : getOrInitSolverBody(*colObj1, infoGlobal.m_timeStep);
1201 solverConstraint.m_solverBodyIdA = solverBodyIdA;
1202 solverConstraint.m_solverBodyIdB = solverBodyIdB;
1203 solverConstraint.m_multiBodyA = mbA;
1205 solverConstraint.m_linkA = fcA->m_link;
1207 solverConstraint.m_multiBodyB = mbB;
1209 solverConstraint.m_linkB = fcB->m_link;
1211 solverConstraint.m_originalContactPoint = &cp;
1213 setupMultiBodyTorsionalFrictionConstraint(solverConstraint, normalAxis, cp, combinedTorsionalFriction, infoGlobal, relaxation, isFriction, desiredVelocity, cfmSlip);
1214 return solverConstraint;
1217 btMultiBodySolverConstraint& btMultiBodyConstraintSolver::addMultiBodySpinningFrictionConstraint(const btVector3& normalAxis, btPersistentManifold* manifold, int frictionIndex, btManifoldPoint& cp,
1218 btScalar combinedTorsionalFriction,
1219 btCollisionObject* colObj0, btCollisionObject* colObj1, btScalar relaxation, const btContactSolverInfo& infoGlobal, btScalar desiredVelocity, btScalar cfmSlip)
1221 BT_PROFILE("addMultiBodyRollingFrictionConstraint");
1223 btMultiBodySolverConstraint& solverConstraint = m_multiBodySpinningFrictionContactConstraints.expandNonInitializing();
1224 solverConstraint.m_orgConstraint = 0;
1225 solverConstraint.m_orgDofIndex = -1;
1227 solverConstraint.m_frictionIndex = frictionIndex;
1228 bool isFriction = true;
1230 const btMultiBodyLinkCollider* fcA = btMultiBodyLinkCollider::upcast(manifold->getBody0());
1231 const btMultiBodyLinkCollider* fcB = btMultiBodyLinkCollider::upcast(manifold->getBody1());
1233 btMultiBody* mbA = fcA ? fcA->m_multiBody : 0;
1234 btMultiBody* mbB = fcB ? fcB->m_multiBody : 0;
1236 int solverBodyIdA = mbA ? -1 : getOrInitSolverBody(*colObj0, infoGlobal.m_timeStep);
1237 int solverBodyIdB = mbB ? -1 : getOrInitSolverBody(*colObj1, infoGlobal.m_timeStep);
1239 solverConstraint.m_solverBodyIdA = solverBodyIdA;
1240 solverConstraint.m_solverBodyIdB = solverBodyIdB;
1241 solverConstraint.m_multiBodyA = mbA;
1243 solverConstraint.m_linkA = fcA->m_link;
1245 solverConstraint.m_multiBodyB = mbB;
1247 solverConstraint.m_linkB = fcB->m_link;
1249 solverConstraint.m_originalContactPoint = &cp;
1251 setupMultiBodyTorsionalFrictionConstraint(solverConstraint, normalAxis, cp, combinedTorsionalFriction, infoGlobal, relaxation, isFriction, desiredVelocity, cfmSlip);
1252 return solverConstraint;
1254 void btMultiBodyConstraintSolver::convertMultiBodyContact(btPersistentManifold* manifold, const btContactSolverInfo& infoGlobal)
1256 const btMultiBodyLinkCollider* fcA = btMultiBodyLinkCollider::upcast(manifold->getBody0());
1257 const btMultiBodyLinkCollider* fcB = btMultiBodyLinkCollider::upcast(manifold->getBody1());
1259 btMultiBody* mbA = fcA ? fcA->m_multiBody : 0;
1260 btMultiBody* mbB = fcB ? fcB->m_multiBody : 0;
1262 btCollisionObject *colObj0 = 0, *colObj1 = 0;
1264 colObj0 = (btCollisionObject*)manifold->getBody0();
1265 colObj1 = (btCollisionObject*)manifold->getBody1();
1267 int solverBodyIdA = mbA ? -1 : getOrInitSolverBody(*colObj0, infoGlobal.m_timeStep);
1268 int solverBodyIdB = mbB ? -1 : getOrInitSolverBody(*colObj1, infoGlobal.m_timeStep);
1270 // btSolverBody* solverBodyA = mbA ? 0 : &m_tmpSolverBodyPool[solverBodyIdA];
1271 // btSolverBody* solverBodyB = mbB ? 0 : &m_tmpSolverBodyPool[solverBodyIdB];
1273 ///avoid collision response between two static objects
1274 // if (!solverBodyA || (solverBodyA->m_invMass.isZero() && (!solverBodyB || solverBodyB->m_invMass.isZero())))
1277 //only a single rollingFriction per manifold
1278 int rollingFriction = 4;
1280 for (int j = 0; j < manifold->getNumContacts(); j++)
1282 btManifoldPoint& cp = manifold->getContactPoint(j);
1284 if (cp.getDistance() <= manifold->getContactProcessingThreshold())
1286 btScalar relaxation;
1288 int frictionIndex = m_multiBodyNormalContactConstraints.size();
1290 btMultiBodySolverConstraint& solverConstraint = m_multiBodyNormalContactConstraints.expandNonInitializing();
1292 // btRigidBody* rb0 = btRigidBody::upcast(colObj0);
1293 // btRigidBody* rb1 = btRigidBody::upcast(colObj1);
1294 solverConstraint.m_orgConstraint = 0;
1295 solverConstraint.m_orgDofIndex = -1;
1296 solverConstraint.m_solverBodyIdA = solverBodyIdA;
1297 solverConstraint.m_solverBodyIdB = solverBodyIdB;
1298 solverConstraint.m_multiBodyA = mbA;
1300 solverConstraint.m_linkA = fcA->m_link;
1302 solverConstraint.m_multiBodyB = mbB;
1304 solverConstraint.m_linkB = fcB->m_link;
1306 solverConstraint.m_originalContactPoint = &cp;
1308 bool isFriction = false;
1309 setupMultiBodyContactConstraint(solverConstraint, cp.m_normalWorldOnB, cp.m_appliedImpulse, cp, infoGlobal, relaxation, isFriction);
1311 // const btVector3& pos1 = cp.getPositionWorldOnA();
1312 // const btVector3& pos2 = cp.getPositionWorldOnB();
1314 /////setup the friction constraints
1315 #define ENABLE_FRICTION
1316 #ifdef ENABLE_FRICTION
1317 solverConstraint.m_frictionIndex = m_multiBodyFrictionContactConstraints.size();
1319 ///Bullet has several options to set the friction directions
1320 ///By default, each contact has only a single friction direction that is recomputed automatically every frame
1321 ///based on the relative linear velocity.
1322 ///If the relative velocity is zero, it will automatically compute a friction direction.
1324 ///You can also enable two friction directions, using the SOLVER_USE_2_FRICTION_DIRECTIONS.
1325 ///In that case, the second friction direction will be orthogonal to both contact normal and first friction direction.
1327 ///If you choose SOLVER_DISABLE_VELOCITY_DEPENDENT_FRICTION_DIRECTION, then the friction will be independent from the relative projected velocity.
1329 ///The user can manually override the friction directions for certain contacts using a contact callback,
1330 ///and set the cp.m_lateralFrictionInitialized to true
1331 ///In that case, you can set the target relative motion in each friction direction (cp.m_contactMotion1 and cp.m_contactMotion2)
1332 ///this will give a conveyor belt effect
1335 btPlaneSpace1(cp.m_normalWorldOnB, cp.m_lateralFrictionDir1, cp.m_lateralFrictionDir2);
1336 cp.m_lateralFrictionDir1.normalize();
1337 cp.m_lateralFrictionDir2.normalize();
1339 if (rollingFriction > 0)
1341 if (cp.m_combinedSpinningFriction > 0)
1343 addMultiBodySpinningFrictionConstraint(cp.m_normalWorldOnB, manifold, frictionIndex, cp, cp.m_combinedSpinningFriction, colObj0, colObj1, relaxation, infoGlobal);
1345 if (cp.m_combinedRollingFriction > 0)
1347 applyAnisotropicFriction(colObj0, cp.m_lateralFrictionDir1, btCollisionObject::CF_ANISOTROPIC_ROLLING_FRICTION);
1348 applyAnisotropicFriction(colObj1, cp.m_lateralFrictionDir1, btCollisionObject::CF_ANISOTROPIC_ROLLING_FRICTION);
1349 applyAnisotropicFriction(colObj0, cp.m_lateralFrictionDir2, btCollisionObject::CF_ANISOTROPIC_ROLLING_FRICTION);
1350 applyAnisotropicFriction(colObj1, cp.m_lateralFrictionDir2, btCollisionObject::CF_ANISOTROPIC_ROLLING_FRICTION);
1352 addMultiBodyTorsionalFrictionConstraint(cp.m_lateralFrictionDir1, manifold, frictionIndex, cp, cp.m_combinedRollingFriction, colObj0, colObj1, relaxation, infoGlobal);
1353 addMultiBodyTorsionalFrictionConstraint(cp.m_lateralFrictionDir2, manifold, frictionIndex, cp, cp.m_combinedRollingFriction, colObj0, colObj1, relaxation, infoGlobal);
1357 if (!(infoGlobal.m_solverMode & SOLVER_ENABLE_FRICTION_DIRECTION_CACHING) || !(cp.m_contactPointFlags & BT_CONTACT_FLAG_LATERAL_FRICTION_INITIALIZED))
1359 cp.m_lateralFrictionDir1 = vel - cp.m_normalWorldOnB * rel_vel;
1360 btScalar lat_rel_vel = cp.m_lateralFrictionDir1.length2();
1361 if (!(infoGlobal.m_solverMode & SOLVER_DISABLE_VELOCITY_DEPENDENT_FRICTION_DIRECTION) && lat_rel_vel > SIMD_EPSILON)
1363 cp.m_lateralFrictionDir1 *= 1.f/btSqrt(lat_rel_vel);
1364 if((infoGlobal.m_solverMode & SOLVER_USE_2_FRICTION_DIRECTIONS))
1366 cp.m_lateralFrictionDir2 = cp.m_lateralFrictionDir1.cross(cp.m_normalWorldOnB);
1367 cp.m_lateralFrictionDir2.normalize();//??
1368 applyAnisotropicFriction(colObj0,cp.m_lateralFrictionDir2,btCollisionObject::CF_ANISOTROPIC_FRICTION);
1369 applyAnisotropicFriction(colObj1,cp.m_lateralFrictionDir2,btCollisionObject::CF_ANISOTROPIC_FRICTION);
1370 addMultiBodyFrictionConstraint(cp.m_lateralFrictionDir2,solverBodyIdA,solverBodyIdB,frictionIndex,cp,rel_pos1,rel_pos2,colObj0,colObj1, relaxation);
1374 applyAnisotropicFriction(colObj0,cp.m_lateralFrictionDir1,btCollisionObject::CF_ANISOTROPIC_FRICTION);
1375 applyAnisotropicFriction(colObj1,cp.m_lateralFrictionDir1,btCollisionObject::CF_ANISOTROPIC_FRICTION);
1376 addMultiBodyFrictionConstraint(cp.m_lateralFrictionDir1,solverBodyIdA,solverBodyIdB,frictionIndex,cp,rel_pos1,rel_pos2,colObj0,colObj1, relaxation);
1381 applyAnisotropicFriction(colObj0, cp.m_lateralFrictionDir1, btCollisionObject::CF_ANISOTROPIC_FRICTION);
1382 applyAnisotropicFriction(colObj1, cp.m_lateralFrictionDir1, btCollisionObject::CF_ANISOTROPIC_FRICTION);
1383 addMultiBodyFrictionConstraint(cp.m_lateralFrictionDir1, cp.m_appliedImpulseLateral1, manifold, frictionIndex, cp, colObj0, colObj1, relaxation, infoGlobal);
1385 if ((infoGlobal.m_solverMode & SOLVER_USE_2_FRICTION_DIRECTIONS))
1387 applyAnisotropicFriction(colObj0, cp.m_lateralFrictionDir2, btCollisionObject::CF_ANISOTROPIC_FRICTION);
1388 applyAnisotropicFriction(colObj1, cp.m_lateralFrictionDir2, btCollisionObject::CF_ANISOTROPIC_FRICTION);
1389 addMultiBodyFrictionConstraint(cp.m_lateralFrictionDir2, cp.m_appliedImpulseLateral2, manifold, frictionIndex, cp, colObj0, colObj1, relaxation, infoGlobal);
1392 if ((infoGlobal.m_solverMode & SOLVER_USE_2_FRICTION_DIRECTIONS) && (infoGlobal.m_solverMode & SOLVER_DISABLE_VELOCITY_DEPENDENT_FRICTION_DIRECTION))
1394 cp.m_contactPointFlags |= BT_CONTACT_FLAG_LATERAL_FRICTION_INITIALIZED;
1400 addMultiBodyFrictionConstraint(cp.m_lateralFrictionDir1, cp.m_appliedImpulseLateral1, manifold, frictionIndex, cp, colObj0, colObj1, relaxation, infoGlobal, cp.m_contactMotion1, cp.m_frictionCFM);
1402 if ((infoGlobal.m_solverMode & SOLVER_USE_2_FRICTION_DIRECTIONS))
1403 addMultiBodyFrictionConstraint(cp.m_lateralFrictionDir2, cp.m_appliedImpulseLateral2, manifold, frictionIndex, cp, colObj0, colObj1, relaxation, infoGlobal, cp.m_contactMotion2, cp.m_frictionCFM);
1404 solverConstraint.m_appliedImpulse = 0.f;
1405 solverConstraint.m_appliedPushImpulse = 0.f;
1408 #endif //ENABLE_FRICTION
1412 // Reset quantities related to warmstart as 0.
1413 cp.m_appliedImpulse = 0;
1419 void btMultiBodyConstraintSolver::convertContacts(btPersistentManifold** manifoldPtr, int numManifolds, const btContactSolverInfo& infoGlobal)
1421 for (int i = 0; i < numManifolds; i++)
1423 btPersistentManifold* manifold = manifoldPtr[i];
1424 const btMultiBodyLinkCollider* fcA = btMultiBodyLinkCollider::upcast(manifold->getBody0());
1425 const btMultiBodyLinkCollider* fcB = btMultiBodyLinkCollider::upcast(manifold->getBody1());
1428 //the contact doesn't involve any Featherstone btMultiBody, so deal with the regular btRigidBody/btCollisionObject case
1429 convertContact(manifold, infoGlobal);
1433 convertMultiBodyContact(manifold, infoGlobal);
1437 //also convert the multibody constraints, if any
1439 for (int i = 0; i < m_tmpNumMultiBodyConstraints; i++)
1441 btMultiBodyConstraint* c = m_tmpMultiBodyConstraints[i];
1442 m_data.m_solverBodyPool = &m_tmpSolverBodyPool;
1443 m_data.m_fixedBodyId = m_fixedBodyId;
1445 c->createConstraintRows(m_multiBodyNonContactConstraints, m_data, infoGlobal);
1448 // Warmstart for noncontact constraints
1449 if (infoGlobal.m_solverMode & SOLVER_USE_ARTICULATED_WARMSTARTING)
1451 for (int i = 0; i < m_multiBodyNonContactConstraints.size(); i++)
1453 btMultiBodySolverConstraint& solverConstraint =
1454 m_multiBodyNonContactConstraints[i];
1455 solverConstraint.m_appliedImpulse =
1456 solverConstraint.m_orgConstraint->getAppliedImpulse(solverConstraint.m_orgDofIndex) *
1457 infoGlobal.m_articulatedWarmstartingFactor;
1459 btMultiBody* multiBodyA = solverConstraint.m_multiBodyA;
1460 btMultiBody* multiBodyB = solverConstraint.m_multiBodyB;
1461 if (solverConstraint.m_appliedImpulse)
1465 int ndofA = multiBodyA->getNumDofs() + 6;
1467 &m_data.m_deltaVelocitiesUnitImpulse[solverConstraint.m_jacAindex];
1468 btScalar impulse = solverConstraint.m_appliedImpulse;
1469 multiBodyA->applyDeltaVeeMultiDof2(deltaV, impulse);
1470 applyDeltaVee(deltaV, impulse, solverConstraint.m_deltaVelAindex, ndofA);
1474 int ndofB = multiBodyB->getNumDofs() + 6;
1476 &m_data.m_deltaVelocitiesUnitImpulse[solverConstraint.m_jacBindex];
1477 btScalar impulse = solverConstraint.m_appliedImpulse;
1478 multiBodyB->applyDeltaVeeMultiDof2(deltaV, impulse);
1479 applyDeltaVee(deltaV, impulse, solverConstraint.m_deltaVelBindex, ndofB);
1486 for (int i = 0; i < m_multiBodyNonContactConstraints.size(); i++)
1488 btMultiBodySolverConstraint& solverConstraint = m_multiBodyNonContactConstraints[i];
1489 solverConstraint.m_appliedImpulse = 0;
1494 btScalar btMultiBodyConstraintSolver::solveGroup(btCollisionObject** bodies, int numBodies, btPersistentManifold** manifold, int numManifolds, btTypedConstraint** constraints, int numConstraints, const btContactSolverInfo& info, btIDebugDraw* debugDrawer, btDispatcher* dispatcher)
1496 //printf("btMultiBodyConstraintSolver::solveGroup: numBodies=%d, numConstraints=%d\n", numBodies, numConstraints);
1497 return btSequentialImpulseConstraintSolver::solveGroup(bodies, numBodies, manifold, numManifolds, constraints, numConstraints, info, debugDrawer, dispatcher);
1501 static void applyJointFeedback(btMultiBodyJacobianData& data, const btMultiBodySolverConstraint& solverConstraint, int jacIndex, btMultiBody* mb, btScalar appliedImpulse)
1503 if (appliedImpulse!=0 && mb->internalNeedsJointFeedback())
1505 //todo: get rid of those temporary memory allocations for the joint feedback
1506 btAlignedObjectArray<btScalar> forceVector;
1507 int numDofsPlusBase = 6+mb->getNumDofs();
1508 forceVector.resize(numDofsPlusBase);
1509 for (int i=0;i<numDofsPlusBase;i++)
1511 forceVector[i] = data.m_jacobians[jacIndex+i]*appliedImpulse;
1513 btAlignedObjectArray<btScalar> output;
1514 output.resize(numDofsPlusBase);
1515 bool applyJointFeedback = true;
1516 mb->calcAccelerationDeltasMultiDof(&forceVector[0],&output[0],data.scratch_r,data.scratch_v,applyJointFeedback);
1521 void btMultiBodyConstraintSolver::writeBackSolverBodyToMultiBody(btMultiBodySolverConstraint& c, btScalar deltaTime)
1525 //bod->addBaseForce(m_gravity * bod->getBaseMass());
1526 //bod->addLinkForce(j, m_gravity * bod->getLinkMass(j));
1528 if (c.m_orgConstraint)
1530 c.m_orgConstraint->internalSetAppliedImpulse(c.m_orgDofIndex, c.m_appliedImpulse);
1535 c.m_multiBodyA->setCompanionId(-1);
1536 btVector3 force = c.m_contactNormal1 * (c.m_appliedImpulse / deltaTime);
1537 btVector3 torque = c.m_relpos1CrossNormal * (c.m_appliedImpulse / deltaTime);
1540 c.m_multiBodyA->addBaseConstraintForce(force);
1541 c.m_multiBodyA->addBaseConstraintTorque(torque);
1545 c.m_multiBodyA->addLinkConstraintForce(c.m_linkA, force);
1546 //b3Printf("force = %f,%f,%f\n",force[0],force[1],force[2]);//[0],torque[1],torque[2]);
1547 c.m_multiBodyA->addLinkConstraintTorque(c.m_linkA, torque);
1554 c.m_multiBodyB->setCompanionId(-1);
1555 btVector3 force = c.m_contactNormal2 * (c.m_appliedImpulse / deltaTime);
1556 btVector3 torque = c.m_relpos2CrossNormal * (c.m_appliedImpulse / deltaTime);
1559 c.m_multiBodyB->addBaseConstraintForce(force);
1560 c.m_multiBodyB->addBaseConstraintTorque(torque);
1565 c.m_multiBodyB->addLinkConstraintForce(c.m_linkB, force);
1566 //b3Printf("t = %f,%f,%f\n",force[0],force[1],force[2]);//[0],torque[1],torque[2]);
1567 c.m_multiBodyB->addLinkConstraintTorque(c.m_linkB, torque);
1574 #ifndef DIRECTLY_UPDATE_VELOCITY_DURING_SOLVER_ITERATIONS
1578 c.m_multiBodyA->applyDeltaVeeMultiDof(&m_data.m_deltaVelocitiesUnitImpulse[c.m_jacAindex], c.m_appliedImpulse);
1583 c.m_multiBodyB->applyDeltaVeeMultiDof(&m_data.m_deltaVelocitiesUnitImpulse[c.m_jacBindex], c.m_appliedImpulse);
1588 btScalar btMultiBodyConstraintSolver::solveGroupCacheFriendlyFinish(btCollisionObject** bodies, int numBodies, const btContactSolverInfo& infoGlobal)
1590 BT_PROFILE("btMultiBodyConstraintSolver::solveGroupCacheFriendlyFinish");
1591 int numPoolConstraints = m_multiBodyNormalContactConstraints.size();
1593 //write back the delta v to the multi bodies, either as applied impulse (direct velocity change)
1594 //or as applied force, so we can measure the joint reaction forces easier
1595 for (int i = 0; i < numPoolConstraints; i++)
1597 btMultiBodySolverConstraint& solverConstraint = m_multiBodyNormalContactConstraints[i];
1598 writeBackSolverBodyToMultiBody(solverConstraint, infoGlobal.m_timeStep);
1600 writeBackSolverBodyToMultiBody(m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex], infoGlobal.m_timeStep);
1602 if ((infoGlobal.m_solverMode & SOLVER_USE_2_FRICTION_DIRECTIONS))
1604 writeBackSolverBodyToMultiBody(m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex + 1], infoGlobal.m_timeStep);
1608 for (int i = 0; i < m_multiBodyNonContactConstraints.size(); i++)
1610 btMultiBodySolverConstraint& solverConstraint = m_multiBodyNonContactConstraints[i];
1611 writeBackSolverBodyToMultiBody(solverConstraint, infoGlobal.m_timeStep);
1616 BT_PROFILE("warm starting write back");
1617 for (int j = 0; j < numPoolConstraints; j++)
1619 const btMultiBodySolverConstraint& solverConstraint = m_multiBodyNormalContactConstraints[j];
1620 btManifoldPoint* pt = (btManifoldPoint*)solverConstraint.m_originalContactPoint;
1622 pt->m_appliedImpulse = solverConstraint.m_appliedImpulse;
1623 pt->m_prevRHS = solverConstraint.m_rhs;
1624 pt->m_appliedImpulseLateral1 = m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex].m_appliedImpulse;
1626 //printf("pt->m_appliedImpulseLateral1 = %f\n", pt->m_appliedImpulseLateral1);
1627 if ((infoGlobal.m_solverMode & SOLVER_USE_2_FRICTION_DIRECTIONS))
1629 pt->m_appliedImpulseLateral2 = m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex + 1].m_appliedImpulse;
1632 pt->m_appliedImpulseLateral2 = 0;
1638 //multibody joint feedback
1640 BT_PROFILE("multi body joint feedback");
1641 for (int j=0;j<numPoolConstraints;j++)
1643 const btMultiBodySolverConstraint& solverConstraint = m_multiBodyNormalContactConstraints[j];
1645 //apply the joint feedback into all links of the btMultiBody
1646 //todo: double-check the signs of the applied impulse
1648 if(solverConstraint.m_multiBodyA && solverConstraint.m_multiBodyA->isMultiDof())
1650 applyJointFeedback(m_data,solverConstraint, solverConstraint.m_jacAindex,solverConstraint.m_multiBodyA, solverConstraint.m_appliedImpulse*btSimdScalar(1./infoGlobal.m_timeStep));
1652 if(solverConstraint.m_multiBodyB && solverConstraint.m_multiBodyB->isMultiDof())
1654 applyJointFeedback(m_data,solverConstraint, solverConstraint.m_jacBindex,solverConstraint.m_multiBodyB,solverConstraint.m_appliedImpulse*btSimdScalar(-1./infoGlobal.m_timeStep));
1657 if (m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex].m_multiBodyA && m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex].m_multiBodyA->isMultiDof())
1659 applyJointFeedback(m_data,m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex],
1660 m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex].m_jacAindex,
1661 m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex].m_multiBodyA,
1662 m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex].m_appliedImpulse*btSimdScalar(1./infoGlobal.m_timeStep));
1665 if (m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex].m_multiBodyB && m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex].m_multiBodyB->isMultiDof())
1667 applyJointFeedback(m_data,m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex],
1668 m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex].m_jacBindex,
1669 m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex].m_multiBodyB,
1670 m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex].m_appliedImpulse*btSimdScalar(-1./infoGlobal.m_timeStep));
1673 if ((infoGlobal.m_solverMode & SOLVER_USE_2_FRICTION_DIRECTIONS))
1675 if (m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex+1].m_multiBodyA && m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex+1].m_multiBodyA->isMultiDof())
1677 applyJointFeedback(m_data,m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex+1],
1678 m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex+1].m_jacAindex,
1679 m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex+1].m_multiBodyA,
1680 m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex+1].m_appliedImpulse*btSimdScalar(1./infoGlobal.m_timeStep));
1683 if (m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex+1].m_multiBodyB && m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex+1].m_multiBodyB->isMultiDof())
1685 applyJointFeedback(m_data,m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex+1],
1686 m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex+1].m_jacBindex,
1687 m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex+1].m_multiBodyB,
1688 m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex+1].m_appliedImpulse*btSimdScalar(-1./infoGlobal.m_timeStep));
1694 for (int i=0;i<m_multiBodyNonContactConstraints.size();i++)
1696 const btMultiBodySolverConstraint& solverConstraint = m_multiBodyNonContactConstraints[i];
1697 if(solverConstraint.m_multiBodyA && solverConstraint.m_multiBodyA->isMultiDof())
1699 applyJointFeedback(m_data,solverConstraint, solverConstraint.m_jacAindex,solverConstraint.m_multiBodyA, solverConstraint.m_appliedImpulse*btSimdScalar(1./infoGlobal.m_timeStep));
1701 if(solverConstraint.m_multiBodyB && solverConstraint.m_multiBodyB->isMultiDof())
1703 applyJointFeedback(m_data,solverConstraint, solverConstraint.m_jacBindex,solverConstraint.m_multiBodyB,solverConstraint.m_appliedImpulse*btSimdScalar(1./infoGlobal.m_timeStep));
1708 numPoolConstraints = m_multiBodyNonContactConstraints.size();
1711 //@todo: m_originalContactPoint is not initialized for btMultiBodySolverConstraint
1712 for (int i=0;i<numPoolConstraints;i++)
1714 const btMultiBodySolverConstraint& c = m_multiBodyNonContactConstraints[i];
1716 btTypedConstraint* constr = (btTypedConstraint*)c.m_originalContactPoint;
1717 btJointFeedback* fb = constr->getJointFeedback();
1720 fb->m_appliedForceBodyA += c.m_contactNormal1*c.m_appliedImpulse*constr->getRigidBodyA().getLinearFactor()/infoGlobal.m_timeStep;
1721 fb->m_appliedForceBodyB += c.m_contactNormal2*c.m_appliedImpulse*constr->getRigidBodyB().getLinearFactor()/infoGlobal.m_timeStep;
1722 fb->m_appliedTorqueBodyA += c.m_relpos1CrossNormal* constr->getRigidBodyA().getAngularFactor()*c.m_appliedImpulse/infoGlobal.m_timeStep;
1723 fb->m_appliedTorqueBodyB += c.m_relpos2CrossNormal* constr->getRigidBodyB().getAngularFactor()*c.m_appliedImpulse/infoGlobal.m_timeStep; /*RGM ???? */
1727 constr->internalSetAppliedImpulse(c.m_appliedImpulse);
1728 if (btFabs(c.m_appliedImpulse)>=constr->getBreakingImpulseThreshold())
1730 constr->setEnabled(false);
1737 return btSequentialImpulseConstraintSolver::solveGroupCacheFriendlyFinish(bodies, numBodies, infoGlobal);
1740 void btMultiBodyConstraintSolver::solveMultiBodyGroup(btCollisionObject** bodies, int numBodies, btPersistentManifold** manifold, int numManifolds, btTypedConstraint** constraints, int numConstraints, btMultiBodyConstraint** multiBodyConstraints, int numMultiBodyConstraints, const btContactSolverInfo& info, btIDebugDraw* debugDrawer, btDispatcher* dispatcher)
1742 //printf("solveMultiBodyGroup: numBodies=%d, numConstraints=%d, numManifolds=%d, numMultiBodyConstraints=%d\n", numBodies, numConstraints, numManifolds, numMultiBodyConstraints);
1744 //printf("solveMultiBodyGroup start\n");
1745 m_tmpMultiBodyConstraints = multiBodyConstraints;
1746 m_tmpNumMultiBodyConstraints = numMultiBodyConstraints;
1748 btSequentialImpulseConstraintSolver::solveGroup(bodies, numBodies, manifold, numManifolds, constraints, numConstraints, info, debugDrawer, dispatcher);
1750 m_tmpMultiBodyConstraints = 0;
1751 m_tmpNumMultiBodyConstraints = 0;