Home | History | Annotate | Download | only in Featherstone
      1 /*
      2 Bullet Continuous Collision Detection and Physics Library
      3 Copyright (c) 2013 Erwin Coumans  http://bulletphysics.org
      4 
      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:
     10 
     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.
     14 */
     15 
     16 
     17 #include "btMultiBodyConstraintSolver.h"
     18 #include "BulletCollision/NarrowPhaseCollision/btPersistentManifold.h"
     19 #include "btMultiBodyLinkCollider.h"
     20 
     21 #include "BulletDynamics/ConstraintSolver/btSolverBody.h"
     22 #include "btMultiBodyConstraint.h"
     23 #include "BulletDynamics/ConstraintSolver/btContactSolverInfo.h"
     24 
     25 #include "LinearMath/btQuickprof.h"
     26 
     27 btScalar btMultiBodyConstraintSolver::solveSingleIteration(int iteration, btCollisionObject** bodies ,int numBodies,btPersistentManifold** manifoldPtr, int numManifolds,btTypedConstraint** constraints,int numConstraints,const btContactSolverInfo& infoGlobal,btIDebugDraw* debugDrawer)
     28 {
     29 	btScalar val = btSequentialImpulseConstraintSolver::solveSingleIteration(iteration, bodies ,numBodies,manifoldPtr, numManifolds,constraints,numConstraints,infoGlobal,debugDrawer);
     30 
     31 	//solve featherstone non-contact constraints
     32 
     33 	//printf("m_multiBodyNonContactConstraints = %d\n",m_multiBodyNonContactConstraints.size());
     34 	for (int j=0;j<m_multiBodyNonContactConstraints.size();j++)
     35 	{
     36 		btMultiBodySolverConstraint& constraint = m_multiBodyNonContactConstraints[j];
     37 		//if (iteration < constraint.m_overrideNumSolverIterations)
     38 			//resolveSingleConstraintRowGenericMultiBody(constraint);
     39 		resolveSingleConstraintRowGeneric(constraint);
     40 		if(constraint.m_multiBodyA)
     41 			constraint.m_multiBodyA->setPosUpdated(false);
     42 		if(constraint.m_multiBodyB)
     43 			constraint.m_multiBodyB->setPosUpdated(false);
     44 	}
     45 
     46 	//solve featherstone normal contact
     47 	for (int j=0;j<m_multiBodyNormalContactConstraints.size();j++)
     48 	{
     49 		btMultiBodySolverConstraint& constraint = m_multiBodyNormalContactConstraints[j];
     50 		if (iteration < infoGlobal.m_numIterations)
     51 			resolveSingleConstraintRowGeneric(constraint);
     52 
     53 		if(constraint.m_multiBodyA)
     54 			constraint.m_multiBodyA->setPosUpdated(false);
     55 		if(constraint.m_multiBodyB)
     56 			constraint.m_multiBodyB->setPosUpdated(false);
     57 	}
     58 
     59 	//solve featherstone frictional contact
     60 
     61 	for (int j=0;j<this->m_multiBodyFrictionContactConstraints.size();j++)
     62 	{
     63 		if (iteration < infoGlobal.m_numIterations)
     64 		{
     65 			btMultiBodySolverConstraint& frictionConstraint = m_multiBodyFrictionContactConstraints[j];
     66 			btScalar totalImpulse = m_multiBodyNormalContactConstraints[frictionConstraint.m_frictionIndex].m_appliedImpulse;
     67 			//adjust friction limits here
     68 			if (totalImpulse>btScalar(0))
     69 			{
     70 				frictionConstraint.m_lowerLimit = -(frictionConstraint.m_friction*totalImpulse);
     71 				frictionConstraint.m_upperLimit = frictionConstraint.m_friction*totalImpulse;
     72 				resolveSingleConstraintRowGeneric(frictionConstraint);
     73 
     74 				if(frictionConstraint.m_multiBodyA)
     75 					frictionConstraint.m_multiBodyA->setPosUpdated(false);
     76 				if(frictionConstraint.m_multiBodyB)
     77 					frictionConstraint.m_multiBodyB->setPosUpdated(false);
     78 			}
     79 		}
     80 	}
     81 	return val;
     82 }
     83 
     84 btScalar btMultiBodyConstraintSolver::solveGroupCacheFriendlySetup(btCollisionObject** bodies,int numBodies,btPersistentManifold** manifoldPtr, int numManifolds,btTypedConstraint** constraints,int numConstraints,const btContactSolverInfo& infoGlobal,btIDebugDraw* debugDrawer)
     85 {
     86 	m_multiBodyNonContactConstraints.resize(0);
     87 	m_multiBodyNormalContactConstraints.resize(0);
     88 	m_multiBodyFrictionContactConstraints.resize(0);
     89 	m_data.m_jacobians.resize(0);
     90 	m_data.m_deltaVelocitiesUnitImpulse.resize(0);
     91 	m_data.m_deltaVelocities.resize(0);
     92 
     93 	for (int i=0;i<numBodies;i++)
     94 	{
     95 		const btMultiBodyLinkCollider* fcA = btMultiBodyLinkCollider::upcast(bodies[i]);
     96 		if (fcA)
     97 		{
     98 			fcA->m_multiBody->setCompanionId(-1);
     99 		}
    100 	}
    101 
    102 	btScalar val = btSequentialImpulseConstraintSolver::solveGroupCacheFriendlySetup( bodies,numBodies,manifoldPtr, numManifolds, constraints,numConstraints,infoGlobal,debugDrawer);
    103 
    104 	return val;
    105 }
    106 
    107 void	btMultiBodyConstraintSolver::applyDeltaVee(btScalar* delta_vee, btScalar impulse, int velocityIndex, int ndof)
    108 {
    109     for (int i = 0; i < ndof; ++i)
    110 		m_data.m_deltaVelocities[velocityIndex+i] += delta_vee[i] * impulse;
    111 }
    112 
    113 void btMultiBodyConstraintSolver::resolveSingleConstraintRowGeneric(const btMultiBodySolverConstraint& c)
    114 {
    115 
    116 	btScalar deltaImpulse = c.m_rhs-btScalar(c.m_appliedImpulse)*c.m_cfm;
    117 	btScalar deltaVelADotn=0;
    118 	btScalar deltaVelBDotn=0;
    119 	btSolverBody* bodyA = 0;
    120 	btSolverBody* bodyB = 0;
    121 	int ndofA=0;
    122 	int ndofB=0;
    123 
    124 	if (c.m_multiBodyA)
    125 	{
    126 		ndofA  = (c.m_multiBodyA->isMultiDof() ? c.m_multiBodyA->getNumDofs() : c.m_multiBodyA->getNumLinks()) + 6;
    127 		for (int i = 0; i < ndofA; ++i)
    128 			deltaVelADotn += m_data.m_jacobians[c.m_jacAindex+i] * m_data.m_deltaVelocities[c.m_deltaVelAindex+i];
    129 	} else if(c.m_solverBodyIdA >= 0)
    130 	{
    131 		bodyA = &m_tmpSolverBodyPool[c.m_solverBodyIdA];
    132 		deltaVelADotn += c.m_contactNormal1.dot(bodyA->internalGetDeltaLinearVelocity()) 	+ c.m_relpos1CrossNormal.dot(bodyA->internalGetDeltaAngularVelocity());
    133 	}
    134 
    135 	if (c.m_multiBodyB)
    136 	{
    137 		ndofB  = (c.m_multiBodyB->isMultiDof() ? c.m_multiBodyB->getNumDofs() : c.m_multiBodyB->getNumLinks()) + 6;
    138 		for (int i = 0; i < ndofB; ++i)
    139 			deltaVelBDotn += m_data.m_jacobians[c.m_jacBindex+i] * m_data.m_deltaVelocities[c.m_deltaVelBindex+i];
    140 	} else if(c.m_solverBodyIdB >= 0)
    141 	{
    142 		bodyB = &m_tmpSolverBodyPool[c.m_solverBodyIdB];
    143 		deltaVelBDotn += c.m_contactNormal2.dot(bodyB->internalGetDeltaLinearVelocity())  + c.m_relpos2CrossNormal.dot(bodyB->internalGetDeltaAngularVelocity());
    144 	}
    145 
    146 
    147 	deltaImpulse	-=	deltaVelADotn*c.m_jacDiagABInv;//m_jacDiagABInv = 1./denom
    148 	deltaImpulse	-=	deltaVelBDotn*c.m_jacDiagABInv;
    149 	const btScalar sum = btScalar(c.m_appliedImpulse) + deltaImpulse;
    150 
    151 	if (sum < c.m_lowerLimit)
    152 	{
    153 		deltaImpulse = c.m_lowerLimit-c.m_appliedImpulse;
    154 		c.m_appliedImpulse = c.m_lowerLimit;
    155 	}
    156 	else if (sum > c.m_upperLimit)
    157 	{
    158 		deltaImpulse = c.m_upperLimit-c.m_appliedImpulse;
    159 		c.m_appliedImpulse = c.m_upperLimit;
    160 	}
    161 	else
    162 	{
    163 		c.m_appliedImpulse = sum;
    164 	}
    165 
    166 	if (c.m_multiBodyA)
    167 	{
    168 		applyDeltaVee(&m_data.m_deltaVelocitiesUnitImpulse[c.m_jacAindex],deltaImpulse,c.m_deltaVelAindex,ndofA);
    169 #ifdef DIRECTLY_UPDATE_VELOCITY_DURING_SOLVER_ITERATIONS
    170 		//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
    171 		//it would make the multibody solver more like the regular one with m_deltaVelocities being equivalent to btSolverBody::m_deltaLinearVelocity/m_deltaAngularVelocity
    172 		if(c.m_multiBodyA->isMultiDof())
    173 			c.m_multiBodyA->applyDeltaVeeMultiDof2(&m_data.m_deltaVelocitiesUnitImpulse[c.m_jacAindex],deltaImpulse);
    174 		else
    175 			c.m_multiBodyA->applyDeltaVee(&m_data.m_deltaVelocitiesUnitImpulse[c.m_jacAindex],deltaImpulse);
    176 #endif //DIRECTLY_UPDATE_VELOCITY_DURING_SOLVER_ITERATIONS
    177 	} else if(c.m_solverBodyIdA >= 0)
    178 	{
    179 		bodyA->internalApplyImpulse(c.m_contactNormal1*bodyA->internalGetInvMass(),c.m_angularComponentA,deltaImpulse);
    180 
    181 	}
    182 	if (c.m_multiBodyB)
    183 	{
    184 		applyDeltaVee(&m_data.m_deltaVelocitiesUnitImpulse[c.m_jacBindex],deltaImpulse,c.m_deltaVelBindex,ndofB);
    185 #ifdef DIRECTLY_UPDATE_VELOCITY_DURING_SOLVER_ITERATIONS
    186 		//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
    187 		//it would make the multibody solver more like the regular one with m_deltaVelocities being equivalent to btSolverBody::m_deltaLinearVelocity/m_deltaAngularVelocity
    188 		if(c.m_multiBodyB->isMultiDof())
    189 			c.m_multiBodyB->applyDeltaVeeMultiDof2(&m_data.m_deltaVelocitiesUnitImpulse[c.m_jacBindex],deltaImpulse);
    190 		else
    191 			c.m_multiBodyB->applyDeltaVee(&m_data.m_deltaVelocitiesUnitImpulse[c.m_jacBindex],deltaImpulse);
    192 #endif //DIRECTLY_UPDATE_VELOCITY_DURING_SOLVER_ITERATIONS
    193 	} else if(c.m_solverBodyIdB >= 0)
    194 	{
    195 		bodyB->internalApplyImpulse(c.m_contactNormal2*bodyB->internalGetInvMass(),c.m_angularComponentB,deltaImpulse);
    196 	}
    197 
    198 }
    199 
    200 
    201 void btMultiBodyConstraintSolver::resolveSingleConstraintRowGenericMultiBody(const btMultiBodySolverConstraint& c)
    202 {
    203 
    204 	btScalar deltaImpulse = c.m_rhs-btScalar(c.m_appliedImpulse)*c.m_cfm;
    205 	btScalar deltaVelADotn=0;
    206 	btScalar deltaVelBDotn=0;
    207 	int ndofA=0;
    208 	int ndofB=0;
    209 
    210 	if (c.m_multiBodyA)
    211 	{
    212 		ndofA  = (c.m_multiBodyA->isMultiDof() ? c.m_multiBodyA->getNumDofs() : c.m_multiBodyA->getNumLinks()) + 6;
    213 		for (int i = 0; i < ndofA; ++i)
    214 			deltaVelADotn += m_data.m_jacobians[c.m_jacAindex+i] * m_data.m_deltaVelocities[c.m_deltaVelAindex+i];
    215 	}
    216 
    217 	if (c.m_multiBodyB)
    218 	{
    219 		ndofB  = (c.m_multiBodyB->isMultiDof() ? c.m_multiBodyB->getNumDofs() : c.m_multiBodyB->getNumLinks()) + 6;
    220 		for (int i = 0; i < ndofB; ++i)
    221 			deltaVelBDotn += m_data.m_jacobians[c.m_jacBindex+i] * m_data.m_deltaVelocities[c.m_deltaVelBindex+i];
    222 	}
    223 
    224 
    225 	deltaImpulse	-=	deltaVelADotn*c.m_jacDiagABInv;//m_jacDiagABInv = 1./denom
    226 	deltaImpulse	-=	deltaVelBDotn*c.m_jacDiagABInv;
    227 	const btScalar sum = btScalar(c.m_appliedImpulse) + deltaImpulse;
    228 
    229 	if (sum < c.m_lowerLimit)
    230 	{
    231 		deltaImpulse = c.m_lowerLimit-c.m_appliedImpulse;
    232 		c.m_appliedImpulse = c.m_lowerLimit;
    233 	}
    234 	else if (sum > c.m_upperLimit)
    235 	{
    236 		deltaImpulse = c.m_upperLimit-c.m_appliedImpulse;
    237 		c.m_appliedImpulse = c.m_upperLimit;
    238 	}
    239 	else
    240 	{
    241 		c.m_appliedImpulse = sum;
    242 	}
    243 
    244 	if (c.m_multiBodyA)
    245 	{
    246 		applyDeltaVee(&m_data.m_deltaVelocitiesUnitImpulse[c.m_jacAindex],deltaImpulse,c.m_deltaVelAindex,ndofA);
    247 		c.m_multiBodyA->applyDeltaVee(&m_data.m_deltaVelocitiesUnitImpulse[c.m_jacAindex],deltaImpulse);
    248 	}
    249 	if (c.m_multiBodyB)
    250 	{
    251 		applyDeltaVee(&m_data.m_deltaVelocitiesUnitImpulse[c.m_jacBindex],deltaImpulse,c.m_deltaVelBindex,ndofB);
    252 		c.m_multiBodyB->applyDeltaVee(&m_data.m_deltaVelocitiesUnitImpulse[c.m_jacBindex],deltaImpulse);
    253 	}
    254 }
    255 
    256 
    257 void btMultiBodyConstraintSolver::setupMultiBodyContactConstraint(btMultiBodySolverConstraint& solverConstraint,
    258 																 const btVector3& contactNormal,
    259 																 btManifoldPoint& cp, const btContactSolverInfo& infoGlobal,
    260 																 btScalar& relaxation,
    261 																 bool isFriction, btScalar desiredVelocity, btScalar cfmSlip)
    262 {
    263 
    264 	BT_PROFILE("setupMultiBodyContactConstraint");
    265 	btVector3 rel_pos1;
    266 	btVector3 rel_pos2;
    267 
    268 	btMultiBody* multiBodyA = solverConstraint.m_multiBodyA;
    269 	btMultiBody* multiBodyB = solverConstraint.m_multiBodyB;
    270 
    271 	const btVector3& pos1 = cp.getPositionWorldOnA();
    272 	const btVector3& pos2 = cp.getPositionWorldOnB();
    273 
    274 	btSolverBody* bodyA = multiBodyA ? 0 : &m_tmpSolverBodyPool[solverConstraint.m_solverBodyIdA];
    275 	btSolverBody* bodyB = multiBodyB ? 0 : &m_tmpSolverBodyPool[solverConstraint.m_solverBodyIdB];
    276 
    277 	btRigidBody* rb0 = multiBodyA ? 0 : bodyA->m_originalBody;
    278 	btRigidBody* rb1 = multiBodyB ? 0 : bodyB->m_originalBody;
    279 
    280 	if (bodyA)
    281 		rel_pos1 = pos1 - bodyA->getWorldTransform().getOrigin();
    282 	if (bodyB)
    283 		rel_pos2 = pos2 - bodyB->getWorldTransform().getOrigin();
    284 
    285 	relaxation = 1.f;
    286 
    287 
    288 
    289 
    290 	if (multiBodyA)
    291 	{
    292 		if (solverConstraint.m_linkA<0)
    293 		{
    294 			rel_pos1 = pos1 - multiBodyA->getBasePos();
    295 		} else
    296 		{
    297 			rel_pos1 = pos1 - multiBodyA->getLink(solverConstraint.m_linkA).m_cachedWorldTransform.getOrigin();
    298 		}
    299 		const int ndofA  = (multiBodyA->isMultiDof() ? multiBodyA->getNumDofs() : multiBodyA->getNumLinks()) + 6;
    300 
    301 		solverConstraint.m_deltaVelAindex = multiBodyA->getCompanionId();
    302 
    303 		if (solverConstraint.m_deltaVelAindex <0)
    304 		{
    305 			solverConstraint.m_deltaVelAindex = m_data.m_deltaVelocities.size();
    306 			multiBodyA->setCompanionId(solverConstraint.m_deltaVelAindex);
    307 			m_data.m_deltaVelocities.resize(m_data.m_deltaVelocities.size()+ndofA);
    308 		} else
    309 		{
    310 			btAssert(m_data.m_deltaVelocities.size() >= solverConstraint.m_deltaVelAindex+ndofA);
    311 		}
    312 
    313 		solverConstraint.m_jacAindex = m_data.m_jacobians.size();
    314 		m_data.m_jacobians.resize(m_data.m_jacobians.size()+ndofA);
    315 		m_data.m_deltaVelocitiesUnitImpulse.resize(m_data.m_deltaVelocitiesUnitImpulse.size()+ndofA);
    316 		btAssert(m_data.m_jacobians.size() == m_data.m_deltaVelocitiesUnitImpulse.size());
    317 
    318 		btScalar* jac1=&m_data.m_jacobians[solverConstraint.m_jacAindex];
    319 		if(multiBodyA->isMultiDof())
    320 			multiBodyA->fillContactJacobianMultiDof(solverConstraint.m_linkA, cp.getPositionWorldOnA(), contactNormal, jac1, m_data.scratch_r, m_data.scratch_v, m_data.scratch_m);
    321 		else
    322 			multiBodyA->fillContactJacobian(solverConstraint.m_linkA, cp.getPositionWorldOnA(), contactNormal, jac1, m_data.scratch_r, m_data.scratch_v, m_data.scratch_m);
    323 		btScalar* delta = &m_data.m_deltaVelocitiesUnitImpulse[solverConstraint.m_jacAindex];
    324 		if(multiBodyA->isMultiDof())
    325 			multiBodyA->calcAccelerationDeltasMultiDof(&m_data.m_jacobians[solverConstraint.m_jacAindex],delta,m_data.scratch_r, m_data.scratch_v);
    326 		else
    327 			multiBodyA->calcAccelerationDeltas(&m_data.m_jacobians[solverConstraint.m_jacAindex],delta,m_data.scratch_r, m_data.scratch_v);
    328 
    329 		btVector3 torqueAxis0 = rel_pos1.cross(contactNormal);
    330 		solverConstraint.m_relpos1CrossNormal = torqueAxis0;
    331 		solverConstraint.m_contactNormal1 = contactNormal;
    332 	} else
    333 	{
    334 		btVector3 torqueAxis0 = rel_pos1.cross(contactNormal);
    335 		solverConstraint.m_relpos1CrossNormal = torqueAxis0;
    336 		solverConstraint.m_contactNormal1 = contactNormal;
    337 		solverConstraint.m_angularComponentA = rb0 ? rb0->getInvInertiaTensorWorld()*torqueAxis0*rb0->getAngularFactor() : btVector3(0,0,0);
    338 	}
    339 
    340 
    341 
    342 	if (multiBodyB)
    343 	{
    344 		if (solverConstraint.m_linkB<0)
    345 		{
    346 			rel_pos2 = pos2 - multiBodyB->getBasePos();
    347 		} else
    348 		{
    349 			rel_pos2 = pos2 - multiBodyB->getLink(solverConstraint.m_linkB).m_cachedWorldTransform.getOrigin();
    350 		}
    351 
    352 		const int ndofB  = (multiBodyB->isMultiDof() ? multiBodyB->getNumDofs() : multiBodyB->getNumLinks()) + 6;
    353 
    354 		solverConstraint.m_deltaVelBindex = multiBodyB->getCompanionId();
    355 		if (solverConstraint.m_deltaVelBindex <0)
    356 		{
    357 			solverConstraint.m_deltaVelBindex = m_data.m_deltaVelocities.size();
    358 			multiBodyB->setCompanionId(solverConstraint.m_deltaVelBindex);
    359 			m_data.m_deltaVelocities.resize(m_data.m_deltaVelocities.size()+ndofB);
    360 		}
    361 
    362 		solverConstraint.m_jacBindex = m_data.m_jacobians.size();
    363 
    364 		m_data.m_jacobians.resize(m_data.m_jacobians.size()+ndofB);
    365 		m_data.m_deltaVelocitiesUnitImpulse.resize(m_data.m_deltaVelocitiesUnitImpulse.size()+ndofB);
    366 		btAssert(m_data.m_jacobians.size() == m_data.m_deltaVelocitiesUnitImpulse.size());
    367 
    368 		if(multiBodyB->isMultiDof())
    369 			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);
    370 		else
    371 			multiBodyB->fillContactJacobian(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);
    372 		if(multiBodyB->isMultiDof())
    373 			multiBodyB->calcAccelerationDeltasMultiDof(&m_data.m_jacobians[solverConstraint.m_jacBindex],&m_data.m_deltaVelocitiesUnitImpulse[solverConstraint.m_jacBindex],m_data.scratch_r, m_data.scratch_v);
    374 		else
    375 			multiBodyB->calcAccelerationDeltas(&m_data.m_jacobians[solverConstraint.m_jacBindex],&m_data.m_deltaVelocitiesUnitImpulse[solverConstraint.m_jacBindex],m_data.scratch_r, m_data.scratch_v);
    376 
    377 		btVector3 torqueAxis1 = rel_pos2.cross(contactNormal);
    378 		solverConstraint.m_relpos2CrossNormal = -torqueAxis1;
    379 		solverConstraint.m_contactNormal2 = -contactNormal;
    380 
    381 	} else
    382 	{
    383 		btVector3 torqueAxis1 = rel_pos2.cross(contactNormal);
    384 		solverConstraint.m_relpos2CrossNormal = -torqueAxis1;
    385 		solverConstraint.m_contactNormal2 = -contactNormal;
    386 
    387 		solverConstraint.m_angularComponentB = rb1 ? rb1->getInvInertiaTensorWorld()*-torqueAxis1*rb1->getAngularFactor() : btVector3(0,0,0);
    388 	}
    389 
    390 	{
    391 
    392 		btVector3 vec;
    393 		btScalar denom0 = 0.f;
    394 		btScalar denom1 = 0.f;
    395 		btScalar* jacB = 0;
    396 		btScalar* jacA = 0;
    397 		btScalar* lambdaA =0;
    398 		btScalar* lambdaB =0;
    399 		int ndofA  = 0;
    400 		if (multiBodyA)
    401 		{
    402 			ndofA  = (multiBodyA->isMultiDof() ? multiBodyA->getNumDofs() : multiBodyA->getNumLinks()) + 6;
    403 			jacA = &m_data.m_jacobians[solverConstraint.m_jacAindex];
    404 			lambdaA = &m_data.m_deltaVelocitiesUnitImpulse[solverConstraint.m_jacAindex];
    405 			for (int i = 0; i < ndofA; ++i)
    406 			{
    407 				btScalar j = jacA[i] ;
    408 				btScalar l =lambdaA[i];
    409 				denom0 += j*l;
    410 			}
    411 		} else
    412 		{
    413 			if (rb0)
    414 			{
    415 				vec = ( solverConstraint.m_angularComponentA).cross(rel_pos1);
    416 				denom0 = rb0->getInvMass() + contactNormal.dot(vec);
    417 			}
    418 		}
    419 		if (multiBodyB)
    420 		{
    421 			const int ndofB  = (multiBodyB->isMultiDof() ? multiBodyB->getNumDofs() : multiBodyB->getNumLinks()) + 6;
    422 			jacB = &m_data.m_jacobians[solverConstraint.m_jacBindex];
    423 			lambdaB = &m_data.m_deltaVelocitiesUnitImpulse[solverConstraint.m_jacBindex];
    424 			for (int i = 0; i < ndofB; ++i)
    425 			{
    426 				btScalar j = jacB[i] ;
    427 				btScalar l =lambdaB[i];
    428 				denom1 += j*l;
    429 			}
    430 
    431 		} else
    432 		{
    433 			if (rb1)
    434 			{
    435 				vec = ( -solverConstraint.m_angularComponentB).cross(rel_pos2);
    436 				denom1 = rb1->getInvMass() + contactNormal.dot(vec);
    437 			}
    438 		}
    439 
    440 
    441 
    442 		 btScalar d = denom0+denom1;
    443 		 if (d>SIMD_EPSILON)
    444 		 {
    445 			solverConstraint.m_jacDiagABInv = relaxation/(d);
    446 		 } else
    447 		 {
    448 			//disable the constraint row to handle singularity/redundant constraint
    449 			solverConstraint.m_jacDiagABInv  = 0.f;
    450 		 }
    451 
    452 	}
    453 
    454 
    455 	//compute rhs and remaining solverConstraint fields
    456 
    457 
    458 
    459 	btScalar restitution = 0.f;
    460 	btScalar penetration = isFriction? 0 : cp.getDistance()+infoGlobal.m_linearSlop;
    461 
    462 	btScalar rel_vel = 0.f;
    463 	int ndofA  = 0;
    464 	int ndofB  = 0;
    465 	{
    466 
    467 		btVector3 vel1,vel2;
    468 		if (multiBodyA)
    469 		{
    470 			ndofA  = (multiBodyA->isMultiDof() ? multiBodyA->getNumDofs() : multiBodyA->getNumLinks()) + 6;
    471 			btScalar* jacA = &m_data.m_jacobians[solverConstraint.m_jacAindex];
    472 			for (int i = 0; i < ndofA ; ++i)
    473 				rel_vel += multiBodyA->getVelocityVector()[i] * jacA[i];
    474 		} else
    475 		{
    476 			if (rb0)
    477 			{
    478 				rel_vel += rb0->getVelocityInLocalPoint(rel_pos1).dot(solverConstraint.m_contactNormal1);
    479 			}
    480 		}
    481 		if (multiBodyB)
    482 		{
    483 			ndofB  = (multiBodyB->isMultiDof() ? multiBodyB->getNumDofs() : multiBodyB->getNumLinks()) + 6;
    484 			btScalar* jacB = &m_data.m_jacobians[solverConstraint.m_jacBindex];
    485 			for (int i = 0; i < ndofB ; ++i)
    486 				rel_vel += multiBodyB->getVelocityVector()[i] * jacB[i];
    487 
    488 		} else
    489 		{
    490 			if (rb1)
    491 			{
    492 				rel_vel += rb1->getVelocityInLocalPoint(rel_pos2).dot(solverConstraint.m_contactNormal2);
    493 			}
    494 		}
    495 
    496 		solverConstraint.m_friction = cp.m_combinedFriction;
    497 
    498 		if(!isFriction)
    499 		{
    500 			restitution =  restitutionCurve(rel_vel, cp.m_combinedRestitution);
    501 			if (restitution <= btScalar(0.))
    502 			{
    503 				restitution = 0.f;
    504 			}
    505 		}
    506 	}
    507 
    508 
    509 	///warm starting (or zero if disabled)
    510 	//disable warmstarting for btMultiBody, it has issues gaining energy (==explosion)
    511 	if (0)//infoGlobal.m_solverMode & SOLVER_USE_WARMSTARTING)
    512 	{
    513 		solverConstraint.m_appliedImpulse = isFriction ? 0 : cp.m_appliedImpulse * infoGlobal.m_warmstartingFactor;
    514 
    515 		if (solverConstraint.m_appliedImpulse)
    516 		{
    517 			if (multiBodyA)
    518 			{
    519 				btScalar impulse = solverConstraint.m_appliedImpulse;
    520 				btScalar* deltaV = &m_data.m_deltaVelocitiesUnitImpulse[solverConstraint.m_jacAindex];
    521 				if(multiBodyA->isMultiDof())
    522 					multiBodyA->applyDeltaVeeMultiDof(deltaV,impulse);
    523 				else
    524 					multiBodyA->applyDeltaVee(deltaV,impulse);
    525 				applyDeltaVee(deltaV,impulse,solverConstraint.m_deltaVelAindex,ndofA);
    526 			} else
    527 			{
    528 				if (rb0)
    529 					bodyA->internalApplyImpulse(solverConstraint.m_contactNormal1*bodyA->internalGetInvMass()*rb0->getLinearFactor(),solverConstraint.m_angularComponentA,solverConstraint.m_appliedImpulse);
    530 			}
    531 			if (multiBodyB)
    532 			{
    533 				btScalar impulse = solverConstraint.m_appliedImpulse;
    534 				btScalar* deltaV = &m_data.m_deltaVelocitiesUnitImpulse[solverConstraint.m_jacBindex];
    535 				if(multiBodyB->isMultiDof())
    536 					multiBodyB->applyDeltaVeeMultiDof(deltaV,impulse);
    537 				else
    538 					multiBodyB->applyDeltaVee(deltaV,impulse);
    539 				applyDeltaVee(deltaV,impulse,solverConstraint.m_deltaVelBindex,ndofB);
    540 			} else
    541 			{
    542 				if (rb1)
    543 					bodyB->internalApplyImpulse(-solverConstraint.m_contactNormal2*bodyB->internalGetInvMass()*rb1->getLinearFactor(),-solverConstraint.m_angularComponentB,-(btScalar)solverConstraint.m_appliedImpulse);
    544 			}
    545 		}
    546 	} else
    547 	{
    548 		solverConstraint.m_appliedImpulse = 0.f;
    549 	}
    550 
    551 	solverConstraint.m_appliedPushImpulse = 0.f;
    552 
    553 	{
    554 
    555 		btScalar positionalError = 0.f;
    556 		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
    557 
    558 		btScalar erp = infoGlobal.m_erp2;
    559 		if (!infoGlobal.m_splitImpulse || (penetration > infoGlobal.m_splitImpulsePenetrationThreshold))
    560 		{
    561 			erp = infoGlobal.m_erp;
    562 		}
    563 
    564 		if (penetration>0)
    565 		{
    566 			positionalError = 0;
    567 			velocityError -= penetration / infoGlobal.m_timeStep;
    568 
    569 		} else
    570 		{
    571 			positionalError = -penetration * erp/infoGlobal.m_timeStep;
    572 		}
    573 
    574 		btScalar  penetrationImpulse = positionalError*solverConstraint.m_jacDiagABInv;
    575 		btScalar velocityImpulse = velocityError *solverConstraint.m_jacDiagABInv;
    576 
    577 		if(!isFriction)
    578 		{
    579 			if (!infoGlobal.m_splitImpulse || (penetration > infoGlobal.m_splitImpulsePenetrationThreshold))
    580 			{
    581 				//combine position and velocity into rhs
    582 				solverConstraint.m_rhs = penetrationImpulse+velocityImpulse;
    583 				solverConstraint.m_rhsPenetration = 0.f;
    584 
    585 			} else
    586 			{
    587 				//split position and velocity into rhs and m_rhsPenetration
    588 				solverConstraint.m_rhs = velocityImpulse;
    589 				solverConstraint.m_rhsPenetration = penetrationImpulse;
    590 			}
    591 
    592 			solverConstraint.m_lowerLimit = 0;
    593 			solverConstraint.m_upperLimit = 1e10f;
    594 		}
    595 		else
    596 		{
    597 			solverConstraint.m_rhs = velocityImpulse;
    598 			solverConstraint.m_rhsPenetration = 0.f;
    599 			solverConstraint.m_lowerLimit = -solverConstraint.m_friction;
    600 			solverConstraint.m_upperLimit = solverConstraint.m_friction;
    601 		}
    602 
    603 		solverConstraint.m_cfm = 0.f;			//why not use cfmSlip?
    604 	}
    605 
    606 }
    607 
    608 
    609 
    610 
    611 btMultiBodySolverConstraint&	btMultiBodyConstraintSolver::addMultiBodyFrictionConstraint(const btVector3& normalAxis,btPersistentManifold* manifold,int frictionIndex,btManifoldPoint& cp,btCollisionObject* colObj0,btCollisionObject* colObj1, btScalar relaxation, const btContactSolverInfo& infoGlobal, btScalar desiredVelocity, btScalar cfmSlip)
    612 {
    613 	BT_PROFILE("addMultiBodyFrictionConstraint");
    614 	btMultiBodySolverConstraint& solverConstraint = m_multiBodyFrictionContactConstraints.expandNonInitializing();
    615     solverConstraint.m_orgConstraint = 0;
    616     solverConstraint.m_orgDofIndex = -1;
    617 
    618 	solverConstraint.m_frictionIndex = frictionIndex;
    619 	bool isFriction = true;
    620 
    621 	const btMultiBodyLinkCollider* fcA = btMultiBodyLinkCollider::upcast(manifold->getBody0());
    622 	const btMultiBodyLinkCollider* fcB = btMultiBodyLinkCollider::upcast(manifold->getBody1());
    623 
    624 	btMultiBody* mbA = fcA? fcA->m_multiBody : 0;
    625 	btMultiBody* mbB = fcB? fcB->m_multiBody : 0;
    626 
    627 	int solverBodyIdA = mbA? -1 : getOrInitSolverBody(*colObj0,infoGlobal.m_timeStep);
    628 	int solverBodyIdB = mbB ? -1 : getOrInitSolverBody(*colObj1,infoGlobal.m_timeStep);
    629 
    630 	solverConstraint.m_solverBodyIdA = solverBodyIdA;
    631 	solverConstraint.m_solverBodyIdB = solverBodyIdB;
    632 	solverConstraint.m_multiBodyA = mbA;
    633 	if (mbA)
    634 		solverConstraint.m_linkA = fcA->m_link;
    635 
    636 	solverConstraint.m_multiBodyB = mbB;
    637 	if (mbB)
    638 		solverConstraint.m_linkB = fcB->m_link;
    639 
    640 	solverConstraint.m_originalContactPoint = &cp;
    641 
    642 	setupMultiBodyContactConstraint(solverConstraint, normalAxis, cp, infoGlobal,relaxation,isFriction, desiredVelocity, cfmSlip);
    643 	return solverConstraint;
    644 }
    645 
    646 void	btMultiBodyConstraintSolver::convertMultiBodyContact(btPersistentManifold* manifold,const btContactSolverInfo& infoGlobal)
    647 {
    648 	const btMultiBodyLinkCollider* fcA = btMultiBodyLinkCollider::upcast(manifold->getBody0());
    649 	const btMultiBodyLinkCollider* fcB = btMultiBodyLinkCollider::upcast(manifold->getBody1());
    650 
    651 	btMultiBody* mbA = fcA? fcA->m_multiBody : 0;
    652 	btMultiBody* mbB = fcB? fcB->m_multiBody : 0;
    653 
    654 	btCollisionObject* colObj0=0,*colObj1=0;
    655 
    656 	colObj0 = (btCollisionObject*)manifold->getBody0();
    657 	colObj1 = (btCollisionObject*)manifold->getBody1();
    658 
    659 	int solverBodyIdA = mbA? -1 : getOrInitSolverBody(*colObj0,infoGlobal.m_timeStep);
    660 	int solverBodyIdB = mbB ? -1 : getOrInitSolverBody(*colObj1,infoGlobal.m_timeStep);
    661 
    662 //	btSolverBody* solverBodyA = mbA ? 0 : &m_tmpSolverBodyPool[solverBodyIdA];
    663 //	btSolverBody* solverBodyB = mbB ? 0 : &m_tmpSolverBodyPool[solverBodyIdB];
    664 
    665 
    666 	///avoid collision response between two static objects
    667 //	if (!solverBodyA || (solverBodyA->m_invMass.isZero() && (!solverBodyB || solverBodyB->m_invMass.isZero())))
    668 	//	return;
    669 
    670 
    671 
    672 	for (int j=0;j<manifold->getNumContacts();j++)
    673 	{
    674 
    675 		btManifoldPoint& cp = manifold->getContactPoint(j);
    676 
    677 		if (cp.getDistance() <= manifold->getContactProcessingThreshold())
    678 		{
    679 
    680 			btScalar relaxation;
    681 
    682 			int frictionIndex = m_multiBodyNormalContactConstraints.size();
    683 
    684 			btMultiBodySolverConstraint& solverConstraint = m_multiBodyNormalContactConstraints.expandNonInitializing();
    685 
    686 	//		btRigidBody* rb0 = btRigidBody::upcast(colObj0);
    687 	//		btRigidBody* rb1 = btRigidBody::upcast(colObj1);
    688             solverConstraint.m_orgConstraint = 0;
    689             solverConstraint.m_orgDofIndex = -1;
    690 			solverConstraint.m_solverBodyIdA = solverBodyIdA;
    691 			solverConstraint.m_solverBodyIdB = solverBodyIdB;
    692 			solverConstraint.m_multiBodyA = mbA;
    693 			if (mbA)
    694 				solverConstraint.m_linkA = fcA->m_link;
    695 
    696 			solverConstraint.m_multiBodyB = mbB;
    697 			if (mbB)
    698 				solverConstraint.m_linkB = fcB->m_link;
    699 
    700 			solverConstraint.m_originalContactPoint = &cp;
    701 
    702 			bool isFriction = false;
    703 			setupMultiBodyContactConstraint(solverConstraint, cp.m_normalWorldOnB,cp, infoGlobal, relaxation, isFriction);
    704 
    705 //			const btVector3& pos1 = cp.getPositionWorldOnA();
    706 //			const btVector3& pos2 = cp.getPositionWorldOnB();
    707 
    708 			/////setup the friction constraints
    709 #define ENABLE_FRICTION
    710 #ifdef ENABLE_FRICTION
    711 			solverConstraint.m_frictionIndex = frictionIndex;
    712 #if ROLLING_FRICTION
    713 	int rollingFriction=1;
    714 			btVector3 angVelA(0,0,0),angVelB(0,0,0);
    715 			if (rb0)
    716 				angVelA = rb0->getAngularVelocity();
    717 			if (rb1)
    718 				angVelB = rb1->getAngularVelocity();
    719 			btVector3 relAngVel = angVelB-angVelA;
    720 
    721 			if ((cp.m_combinedRollingFriction>0.f) && (rollingFriction>0))
    722 			{
    723 				//only a single rollingFriction per manifold
    724 				rollingFriction--;
    725 				if (relAngVel.length()>infoGlobal.m_singleAxisRollingFrictionThreshold)
    726 				{
    727 					relAngVel.normalize();
    728 					applyAnisotropicFriction(colObj0,relAngVel,btCollisionObject::CF_ANISOTROPIC_ROLLING_FRICTION);
    729 					applyAnisotropicFriction(colObj1,relAngVel,btCollisionObject::CF_ANISOTROPIC_ROLLING_FRICTION);
    730 					if (relAngVel.length()>0.001)
    731 						addRollingFrictionConstraint(relAngVel,solverBodyIdA,solverBodyIdB,frictionIndex,cp,rel_pos1,rel_pos2,colObj0,colObj1, relaxation);
    732 
    733 				} else
    734 				{
    735 					addRollingFrictionConstraint(cp.m_normalWorldOnB,solverBodyIdA,solverBodyIdB,frictionIndex,cp,rel_pos1,rel_pos2,colObj0,colObj1, relaxation);
    736 					btVector3 axis0,axis1;
    737 					btPlaneSpace1(cp.m_normalWorldOnB,axis0,axis1);
    738 					applyAnisotropicFriction(colObj0,axis0,btCollisionObject::CF_ANISOTROPIC_ROLLING_FRICTION);
    739 					applyAnisotropicFriction(colObj1,axis0,btCollisionObject::CF_ANISOTROPIC_ROLLING_FRICTION);
    740 					applyAnisotropicFriction(colObj0,axis1,btCollisionObject::CF_ANISOTROPIC_ROLLING_FRICTION);
    741 					applyAnisotropicFriction(colObj1,axis1,btCollisionObject::CF_ANISOTROPIC_ROLLING_FRICTION);
    742 					if (axis0.length()>0.001)
    743 						addRollingFrictionConstraint(axis0,solverBodyIdA,solverBodyIdB,frictionIndex,cp,rel_pos1,rel_pos2,colObj0,colObj1, relaxation);
    744 					if (axis1.length()>0.001)
    745 						addRollingFrictionConstraint(axis1,solverBodyIdA,solverBodyIdB,frictionIndex,cp,rel_pos1,rel_pos2,colObj0,colObj1, relaxation);
    746 
    747 				}
    748 			}
    749 #endif //ROLLING_FRICTION
    750 
    751 			///Bullet has several options to set the friction directions
    752 			///By default, each contact has only a single friction direction that is recomputed automatically very frame
    753 			///based on the relative linear velocity.
    754 			///If the relative velocity it zero, it will automatically compute a friction direction.
    755 
    756 			///You can also enable two friction directions, using the SOLVER_USE_2_FRICTION_DIRECTIONS.
    757 			///In that case, the second friction direction will be orthogonal to both contact normal and first friction direction.
    758 			///
    759 			///If you choose SOLVER_DISABLE_VELOCITY_DEPENDENT_FRICTION_DIRECTION, then the friction will be independent from the relative projected velocity.
    760 			///
    761 			///The user can manually override the friction directions for certain contacts using a contact callback,
    762 			///and set the cp.m_lateralFrictionInitialized to true
    763 			///In that case, you can set the target relative motion in each friction direction (cp.m_contactMotion1 and cp.m_contactMotion2)
    764 			///this will give a conveyor belt effect
    765 			///
    766 			if (!(infoGlobal.m_solverMode & SOLVER_ENABLE_FRICTION_DIRECTION_CACHING) || !cp.m_lateralFrictionInitialized)
    767 			{/*
    768 				cp.m_lateralFrictionDir1 = vel - cp.m_normalWorldOnB * rel_vel;
    769 				btScalar lat_rel_vel = cp.m_lateralFrictionDir1.length2();
    770 				if (!(infoGlobal.m_solverMode & SOLVER_DISABLE_VELOCITY_DEPENDENT_FRICTION_DIRECTION) && lat_rel_vel > SIMD_EPSILON)
    771 				{
    772 					cp.m_lateralFrictionDir1 *= 1.f/btSqrt(lat_rel_vel);
    773 					if((infoGlobal.m_solverMode & SOLVER_USE_2_FRICTION_DIRECTIONS))
    774 					{
    775 						cp.m_lateralFrictionDir2 = cp.m_lateralFrictionDir1.cross(cp.m_normalWorldOnB);
    776 						cp.m_lateralFrictionDir2.normalize();//??
    777 						applyAnisotropicFriction(colObj0,cp.m_lateralFrictionDir2,btCollisionObject::CF_ANISOTROPIC_FRICTION);
    778 						applyAnisotropicFriction(colObj1,cp.m_lateralFrictionDir2,btCollisionObject::CF_ANISOTROPIC_FRICTION);
    779 						addMultiBodyFrictionConstraint(cp.m_lateralFrictionDir2,solverBodyIdA,solverBodyIdB,frictionIndex,cp,rel_pos1,rel_pos2,colObj0,colObj1, relaxation);
    780 
    781 					}
    782 
    783 					applyAnisotropicFriction(colObj0,cp.m_lateralFrictionDir1,btCollisionObject::CF_ANISOTROPIC_FRICTION);
    784 					applyAnisotropicFriction(colObj1,cp.m_lateralFrictionDir1,btCollisionObject::CF_ANISOTROPIC_FRICTION);
    785 					addMultiBodyFrictionConstraint(cp.m_lateralFrictionDir1,solverBodyIdA,solverBodyIdB,frictionIndex,cp,rel_pos1,rel_pos2,colObj0,colObj1, relaxation);
    786 
    787 				} else
    788 				*/
    789 				{
    790 					btPlaneSpace1(cp.m_normalWorldOnB,cp.m_lateralFrictionDir1,cp.m_lateralFrictionDir2);
    791 
    792 					applyAnisotropicFriction(colObj0,cp.m_lateralFrictionDir1,btCollisionObject::CF_ANISOTROPIC_FRICTION);
    793 					applyAnisotropicFriction(colObj1,cp.m_lateralFrictionDir1,btCollisionObject::CF_ANISOTROPIC_FRICTION);
    794 					addMultiBodyFrictionConstraint(cp.m_lateralFrictionDir1,manifold,frictionIndex,cp,colObj0,colObj1, relaxation,infoGlobal);
    795 
    796 					if ((infoGlobal.m_solverMode & SOLVER_USE_2_FRICTION_DIRECTIONS))
    797 					{
    798 						applyAnisotropicFriction(colObj0,cp.m_lateralFrictionDir2,btCollisionObject::CF_ANISOTROPIC_FRICTION);
    799 						applyAnisotropicFriction(colObj1,cp.m_lateralFrictionDir2,btCollisionObject::CF_ANISOTROPIC_FRICTION);
    800 						addMultiBodyFrictionConstraint(cp.m_lateralFrictionDir2,manifold,frictionIndex,cp,colObj0,colObj1, relaxation,infoGlobal);
    801 					}
    802 
    803 					if ((infoGlobal.m_solverMode & SOLVER_USE_2_FRICTION_DIRECTIONS) && (infoGlobal.m_solverMode & SOLVER_DISABLE_VELOCITY_DEPENDENT_FRICTION_DIRECTION))
    804 					{
    805 						cp.m_lateralFrictionInitialized = true;
    806 					}
    807 				}
    808 
    809 			} else
    810 			{
    811 				addMultiBodyFrictionConstraint(cp.m_lateralFrictionDir1,manifold,frictionIndex,cp,colObj0,colObj1, relaxation,infoGlobal,cp.m_contactMotion1, cp.m_contactCFM1);
    812 
    813 				if ((infoGlobal.m_solverMode & SOLVER_USE_2_FRICTION_DIRECTIONS))
    814 					addMultiBodyFrictionConstraint(cp.m_lateralFrictionDir2,manifold,frictionIndex,cp,colObj0,colObj1, relaxation, infoGlobal,cp.m_contactMotion2, cp.m_contactCFM2);
    815 
    816 				//setMultiBodyFrictionConstraintImpulse( solverConstraint, solverBodyIdA, solverBodyIdB, cp, infoGlobal);
    817 				//todo:
    818 				solverConstraint.m_appliedImpulse = 0.f;
    819 				solverConstraint.m_appliedPushImpulse = 0.f;
    820 			}
    821 
    822 
    823 #endif //ENABLE_FRICTION
    824 
    825 		}
    826 	}
    827 }
    828 
    829 void btMultiBodyConstraintSolver::convertContacts(btPersistentManifold** manifoldPtr,int numManifolds, const btContactSolverInfo& infoGlobal)
    830 {
    831 	//btPersistentManifold* manifold = 0;
    832 
    833 	for (int i=0;i<numManifolds;i++)
    834 	{
    835 		btPersistentManifold* manifold= manifoldPtr[i];
    836 		const btMultiBodyLinkCollider* fcA = btMultiBodyLinkCollider::upcast(manifold->getBody0());
    837 		const btMultiBodyLinkCollider* fcB = btMultiBodyLinkCollider::upcast(manifold->getBody1());
    838 		if (!fcA && !fcB)
    839 		{
    840 			//the contact doesn't involve any Featherstone btMultiBody, so deal with the regular btRigidBody/btCollisionObject case
    841 			convertContact(manifold,infoGlobal);
    842 		} else
    843 		{
    844 			convertMultiBodyContact(manifold,infoGlobal);
    845 		}
    846 	}
    847 
    848 	//also convert the multibody constraints, if any
    849 
    850 
    851 	for (int i=0;i<m_tmpNumMultiBodyConstraints;i++)
    852 	{
    853 		btMultiBodyConstraint* c = m_tmpMultiBodyConstraints[i];
    854 		m_data.m_solverBodyPool = &m_tmpSolverBodyPool;
    855 		m_data.m_fixedBodyId = m_fixedBodyId;
    856 
    857 		c->createConstraintRows(m_multiBodyNonContactConstraints,m_data,	infoGlobal);
    858 	}
    859 
    860 }
    861 
    862 
    863 
    864 btScalar btMultiBodyConstraintSolver::solveGroup(btCollisionObject** bodies,int numBodies,btPersistentManifold** manifold,int numManifolds,btTypedConstraint** constraints,int numConstraints,const btContactSolverInfo& info, btIDebugDraw* debugDrawer,btDispatcher* dispatcher)
    865 {
    866 	return btSequentialImpulseConstraintSolver::solveGroup(bodies,numBodies,manifold,numManifolds,constraints,numConstraints,info,debugDrawer,dispatcher);
    867 }
    868 
    869 #if 0
    870 static void applyJointFeedback(btMultiBodyJacobianData& data, const btMultiBodySolverConstraint& solverConstraint, int jacIndex, btMultiBody* mb, btScalar appliedImpulse)
    871 {
    872 	if (appliedImpulse!=0 && mb->internalNeedsJointFeedback())
    873 	{
    874 		//todo: get rid of those temporary memory allocations for the joint feedback
    875 		btAlignedObjectArray<btScalar> forceVector;
    876 		int numDofsPlusBase = 6+mb->getNumDofs();
    877 		forceVector.resize(numDofsPlusBase);
    878 		for (int i=0;i<numDofsPlusBase;i++)
    879 		{
    880 			forceVector[i] = data.m_jacobians[jacIndex+i]*appliedImpulse;
    881 		}
    882 		btAlignedObjectArray<btScalar> output;
    883 		output.resize(numDofsPlusBase);
    884 		bool applyJointFeedback = true;
    885 		mb->calcAccelerationDeltasMultiDof(&forceVector[0],&output[0],data.scratch_r,data.scratch_v,applyJointFeedback);
    886 	}
    887 }
    888 #endif
    889 
    890 void btMultiBodyConstraintSolver::writeBackSolverBodyToMultiBody(btMultiBodySolverConstraint& c, btScalar deltaTime)
    891 {
    892 #if 1
    893 
    894 	//bod->addBaseForce(m_gravity * bod->getBaseMass());
    895 	//bod->addLinkForce(j, m_gravity * bod->getLinkMass(j));
    896 
    897 	if (c.m_orgConstraint)
    898 	{
    899 		c.m_orgConstraint->internalSetAppliedImpulse(c.m_orgDofIndex,c.m_appliedImpulse);
    900 	}
    901 
    902 
    903 	if (c.m_multiBodyA)
    904 	{
    905 
    906 		if(c.m_multiBodyA->isMultiDof())
    907 		{
    908 			c.m_multiBodyA->setCompanionId(-1);
    909 			btVector3 force = c.m_contactNormal1*(c.m_appliedImpulse/deltaTime);
    910 			btVector3 torque = c.m_relpos1CrossNormal*(c.m_appliedImpulse/deltaTime);
    911 			if (c.m_linkA<0)
    912 			{
    913 				c.m_multiBodyA->addBaseConstraintForce(force);
    914 				c.m_multiBodyA->addBaseConstraintTorque(torque);
    915 			} else
    916 			{
    917 				c.m_multiBodyA->addLinkConstraintForce(c.m_linkA,force);
    918 					//b3Printf("force = %f,%f,%f\n",force[0],force[1],force[2]);//[0],torque[1],torque[2]);
    919 				c.m_multiBodyA->addLinkConstraintTorque(c.m_linkA,torque);
    920 			}
    921 		}
    922 	}
    923 
    924 	if (c.m_multiBodyB)
    925 	{
    926 		if(c.m_multiBodyB->isMultiDof())
    927 		{
    928 			{
    929 				c.m_multiBodyB->setCompanionId(-1);
    930 				btVector3 force = c.m_contactNormal2*(c.m_appliedImpulse/deltaTime);
    931 				btVector3 torque = c.m_relpos2CrossNormal*(c.m_appliedImpulse/deltaTime);
    932 				if (c.m_linkB<0)
    933 				{
    934 					c.m_multiBodyB->addBaseConstraintForce(force);
    935 					c.m_multiBodyB->addBaseConstraintTorque(torque);
    936 				} else
    937 				{
    938 					{
    939 						c.m_multiBodyB->addLinkConstraintForce(c.m_linkB,force);
    940 						//b3Printf("t = %f,%f,%f\n",force[0],force[1],force[2]);//[0],torque[1],torque[2]);
    941 						c.m_multiBodyB->addLinkConstraintTorque(c.m_linkB,torque);
    942 					}
    943 
    944 				}
    945 			}
    946 		}
    947 	}
    948 #endif
    949 
    950 #ifndef DIRECTLY_UPDATE_VELOCITY_DURING_SOLVER_ITERATIONS
    951 
    952 	if (c.m_multiBodyA)
    953 	{
    954 
    955 		if(c.m_multiBodyA->isMultiDof())
    956 		{
    957 			c.m_multiBodyA->applyDeltaVeeMultiDof(&m_data.m_deltaVelocitiesUnitImpulse[c.m_jacAindex],c.m_appliedImpulse);
    958 		}
    959 		else
    960 		{
    961 			c.m_multiBodyA->applyDeltaVee(&m_data.m_deltaVelocitiesUnitImpulse[c.m_jacAindex],c.m_appliedImpulse);
    962 		}
    963 	}
    964 
    965 	if (c.m_multiBodyB)
    966 	{
    967 		if(c.m_multiBodyB->isMultiDof())
    968 		{
    969 			c.m_multiBodyB->applyDeltaVeeMultiDof(&m_data.m_deltaVelocitiesUnitImpulse[c.m_jacBindex],c.m_appliedImpulse);
    970 		}
    971 		else
    972 		{
    973 			c.m_multiBodyB->applyDeltaVee(&m_data.m_deltaVelocitiesUnitImpulse[c.m_jacBindex],c.m_appliedImpulse);
    974 		}
    975 	}
    976 #endif
    977 
    978 
    979 
    980 }
    981 
    982 btScalar btMultiBodyConstraintSolver::solveGroupCacheFriendlyFinish(btCollisionObject** bodies,int numBodies,const btContactSolverInfo& infoGlobal)
    983 {
    984 	BT_PROFILE("btMultiBodyConstraintSolver::solveGroupCacheFriendlyFinish");
    985 	int numPoolConstraints = m_multiBodyNormalContactConstraints.size();
    986 
    987 
    988 	//write back the delta v to the multi bodies, either as applied impulse (direct velocity change)
    989 	//or as applied force, so we can measure the joint reaction forces easier
    990 	for (int i=0;i<numPoolConstraints;i++)
    991 	{
    992 		btMultiBodySolverConstraint& solverConstraint = m_multiBodyNormalContactConstraints[i];
    993 		writeBackSolverBodyToMultiBody(solverConstraint,infoGlobal.m_timeStep);
    994 
    995 		writeBackSolverBodyToMultiBody(m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex],infoGlobal.m_timeStep);
    996 
    997 		if ((infoGlobal.m_solverMode & SOLVER_USE_2_FRICTION_DIRECTIONS))
    998 		{
    999 			writeBackSolverBodyToMultiBody(m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex+1],infoGlobal.m_timeStep);
   1000 		}
   1001 	}
   1002 
   1003 
   1004 	for (int i=0;i<m_multiBodyNonContactConstraints.size();i++)
   1005 	{
   1006 		btMultiBodySolverConstraint& solverConstraint = m_multiBodyNonContactConstraints[i];
   1007 		writeBackSolverBodyToMultiBody(solverConstraint,infoGlobal.m_timeStep);
   1008 	}
   1009 
   1010 
   1011 	if (infoGlobal.m_solverMode & SOLVER_USE_WARMSTARTING)
   1012 	{
   1013 		BT_PROFILE("warm starting write back");
   1014 		for (int j=0;j<numPoolConstraints;j++)
   1015 		{
   1016 			const btMultiBodySolverConstraint& solverConstraint = m_multiBodyNormalContactConstraints[j];
   1017 			btManifoldPoint* pt = (btManifoldPoint*) solverConstraint.m_originalContactPoint;
   1018 			btAssert(pt);
   1019 			pt->m_appliedImpulse = solverConstraint.m_appliedImpulse;
   1020 			pt->m_appliedImpulseLateral1 = m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex].m_appliedImpulse;
   1021 
   1022 			//printf("pt->m_appliedImpulseLateral1 = %f\n", pt->m_appliedImpulseLateral1);
   1023 			if ((infoGlobal.m_solverMode & SOLVER_USE_2_FRICTION_DIRECTIONS))
   1024 			{
   1025 				pt->m_appliedImpulseLateral2 = m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex+1].m_appliedImpulse;
   1026 			}
   1027 			//do a callback here?
   1028 		}
   1029 	}
   1030 #if 0
   1031 	//multibody joint feedback
   1032 	{
   1033 		BT_PROFILE("multi body joint feedback");
   1034 		for (int j=0;j<numPoolConstraints;j++)
   1035 		{
   1036 			const btMultiBodySolverConstraint& solverConstraint = m_multiBodyNormalContactConstraints[j];
   1037 
   1038 			//apply the joint feedback into all links of the btMultiBody
   1039 			//todo: double-check the signs of the applied impulse
   1040 
   1041 			if(solverConstraint.m_multiBodyA && solverConstraint.m_multiBodyA->isMultiDof())
   1042 			{
   1043 				applyJointFeedback(m_data,solverConstraint, solverConstraint.m_jacAindex,solverConstraint.m_multiBodyA, solverConstraint.m_appliedImpulse*btSimdScalar(1./infoGlobal.m_timeStep));
   1044 			}
   1045 			if(solverConstraint.m_multiBodyB && solverConstraint.m_multiBodyB->isMultiDof())
   1046 			{
   1047 				applyJointFeedback(m_data,solverConstraint, solverConstraint.m_jacBindex,solverConstraint.m_multiBodyB,solverConstraint.m_appliedImpulse*btSimdScalar(-1./infoGlobal.m_timeStep));
   1048 			}
   1049 #if 0
   1050 			if (m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex].m_multiBodyA && m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex].m_multiBodyA->isMultiDof())
   1051 			{
   1052 				applyJointFeedback(m_data,m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex],
   1053 					m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex].m_jacAindex,
   1054 					m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex].m_multiBodyA,
   1055 					m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex].m_appliedImpulse*btSimdScalar(1./infoGlobal.m_timeStep));
   1056 
   1057 			}
   1058 			if (m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex].m_multiBodyB && m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex].m_multiBodyB->isMultiDof())
   1059 			{
   1060 				applyJointFeedback(m_data,m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex],
   1061 					m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex].m_jacBindex,
   1062 					m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex].m_multiBodyB,
   1063 					m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex].m_appliedImpulse*btSimdScalar(-1./infoGlobal.m_timeStep));
   1064 			}
   1065 
   1066 			if ((infoGlobal.m_solverMode & SOLVER_USE_2_FRICTION_DIRECTIONS))
   1067 			{
   1068 				if (m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex+1].m_multiBodyA && m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex+1].m_multiBodyA->isMultiDof())
   1069 				{
   1070 					applyJointFeedback(m_data,m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex+1],
   1071 						m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex+1].m_jacAindex,
   1072 						m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex+1].m_multiBodyA,
   1073 						m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex+1].m_appliedImpulse*btSimdScalar(1./infoGlobal.m_timeStep));
   1074 				}
   1075 
   1076 				if (m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex+1].m_multiBodyB && m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex+1].m_multiBodyB->isMultiDof())
   1077 				{
   1078 					applyJointFeedback(m_data,m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex+1],
   1079 						m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex+1].m_jacBindex,
   1080 						m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex+1].m_multiBodyB,
   1081 						m_multiBodyFrictionContactConstraints[solverConstraint.m_frictionIndex+1].m_appliedImpulse*btSimdScalar(-1./infoGlobal.m_timeStep));
   1082 				}
   1083 			}
   1084 #endif
   1085 		}
   1086 
   1087 		for (int i=0;i<m_multiBodyNonContactConstraints.size();i++)
   1088 		{
   1089 			const btMultiBodySolverConstraint& solverConstraint = m_multiBodyNonContactConstraints[i];
   1090 			if(solverConstraint.m_multiBodyA && solverConstraint.m_multiBodyA->isMultiDof())
   1091 			{
   1092 				applyJointFeedback(m_data,solverConstraint, solverConstraint.m_jacAindex,solverConstraint.m_multiBodyA, solverConstraint.m_appliedImpulse*btSimdScalar(1./infoGlobal.m_timeStep));
   1093 			}
   1094 			if(solverConstraint.m_multiBodyB && solverConstraint.m_multiBodyB->isMultiDof())
   1095 			{
   1096 				applyJointFeedback(m_data,solverConstraint, solverConstraint.m_jacBindex,solverConstraint.m_multiBodyB,solverConstraint.m_appliedImpulse*btSimdScalar(1./infoGlobal.m_timeStep));
   1097 			}
   1098 		}
   1099 	}
   1100 
   1101 	numPoolConstraints = m_multiBodyNonContactConstraints.size();
   1102 
   1103 #if 0
   1104 	//@todo: m_originalContactPoint is not initialized for btMultiBodySolverConstraint
   1105 	for (int i=0;i<numPoolConstraints;i++)
   1106 	{
   1107 		const btMultiBodySolverConstraint& c = m_multiBodyNonContactConstraints[i];
   1108 
   1109 		btTypedConstraint* constr = (btTypedConstraint*)c.m_originalContactPoint;
   1110 		btJointFeedback* fb = constr->getJointFeedback();
   1111 		if (fb)
   1112 		{
   1113 			fb->m_appliedForceBodyA += c.m_contactNormal1*c.m_appliedImpulse*constr->getRigidBodyA().getLinearFactor()/infoGlobal.m_timeStep;
   1114 			fb->m_appliedForceBodyB += c.m_contactNormal2*c.m_appliedImpulse*constr->getRigidBodyB().getLinearFactor()/infoGlobal.m_timeStep;
   1115 			fb->m_appliedTorqueBodyA += c.m_relpos1CrossNormal* constr->getRigidBodyA().getAngularFactor()*c.m_appliedImpulse/infoGlobal.m_timeStep;
   1116 			fb->m_appliedTorqueBodyB += c.m_relpos2CrossNormal* constr->getRigidBodyB().getAngularFactor()*c.m_appliedImpulse/infoGlobal.m_timeStep; /*RGM ???? */
   1117 
   1118 		}
   1119 
   1120 		constr->internalSetAppliedImpulse(c.m_appliedImpulse);
   1121 		if (btFabs(c.m_appliedImpulse)>=constr->getBreakingImpulseThreshold())
   1122 		{
   1123 			constr->setEnabled(false);
   1124 		}
   1125 
   1126 	}
   1127 #endif
   1128 #endif
   1129 
   1130 	return btSequentialImpulseConstraintSolver::solveGroupCacheFriendlyFinish(bodies,numBodies,infoGlobal);
   1131 }
   1132 
   1133 
   1134 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)
   1135 {
   1136 	//printf("solveMultiBodyGroup start\n");
   1137 	m_tmpMultiBodyConstraints = multiBodyConstraints;
   1138 	m_tmpNumMultiBodyConstraints = numMultiBodyConstraints;
   1139 
   1140 	btSequentialImpulseConstraintSolver::solveGroup(bodies,numBodies,manifold,numManifolds,constraints,numConstraints,info,debugDrawer,dispatcher);
   1141 
   1142 	m_tmpMultiBodyConstraints = 0;
   1143 	m_tmpNumMultiBodyConstraints = 0;
   1144 
   1145 
   1146 }
   1147