1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063 |
- /*
- Bullet Continuous Collision Detection and Physics Library
- Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
- This software is provided 'as-is', without any express or implied warranty.
- In no event will the authors be held liable for any damages arising from the use of this software.
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it freely,
- subject to the following restrictions:
- 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
- 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
- 3. This notice may not be removed or altered from any source distribution.
- */
- /*
- 2007-09-09
- Refactored by Francisco Le?n
- email: projectileman@yahoo.com
- http://gimpact.sf.net
- */
- #include "btGeneric6DofConstraint.h"
- #include "bullet/BulletDynamics/Dynamics/btRigidBody.h"
- #include "bullet/LinearMath/btTransformUtil.h"
- #include "bullet/LinearMath/btTransformUtil.h"
- #include <new>
- #define D6_USE_OBSOLETE_METHOD false
- #define D6_USE_FRAME_OFFSET true
- btGeneric6DofConstraint::btGeneric6DofConstraint(btRigidBody& rbA, btRigidBody& rbB, const btTransform& frameInA, const btTransform& frameInB, bool useLinearReferenceFrameA)
- : btTypedConstraint(D6_CONSTRAINT_TYPE, rbA, rbB)
- , m_frameInA(frameInA)
- , m_frameInB(frameInB),
- m_useLinearReferenceFrameA(useLinearReferenceFrameA),
- m_useOffsetForConstraintFrame(D6_USE_FRAME_OFFSET),
- m_flags(0),
- m_useSolveConstraintObsolete(D6_USE_OBSOLETE_METHOD)
- {
- calculateTransforms();
- }
- btGeneric6DofConstraint::btGeneric6DofConstraint(btRigidBody& rbB, const btTransform& frameInB, bool useLinearReferenceFrameB)
- : btTypedConstraint(D6_CONSTRAINT_TYPE, getFixedBody(), rbB),
- m_frameInB(frameInB),
- m_useLinearReferenceFrameA(useLinearReferenceFrameB),
- m_useOffsetForConstraintFrame(D6_USE_FRAME_OFFSET),
- m_flags(0),
- m_useSolveConstraintObsolete(false)
- {
- ///not providing rigidbody A means implicitly using worldspace for body A
- m_frameInA = rbB.getCenterOfMassTransform() * m_frameInB;
- calculateTransforms();
- }
- #define GENERIC_D6_DISABLE_WARMSTARTING 1
- btScalar btGetMatrixElem(const btMatrix3x3& mat, int index);
- btScalar btGetMatrixElem(const btMatrix3x3& mat, int index)
- {
- int i = index%3;
- int j = index/3;
- return mat[i][j];
- }
- ///MatrixToEulerXYZ from http://www.geometrictools.com/LibFoundation/Mathematics/Wm4Matrix3.inl.html
- bool matrixToEulerXYZ(const btMatrix3x3& mat,btVector3& xyz);
- bool matrixToEulerXYZ(const btMatrix3x3& mat,btVector3& xyz)
- {
- // // rot = cy*cz -cy*sz sy
- // // cz*sx*sy+cx*sz cx*cz-sx*sy*sz -cy*sx
- // // -cx*cz*sy+sx*sz cz*sx+cx*sy*sz cx*cy
- //
- btScalar fi = btGetMatrixElem(mat,2);
- if (fi < btScalar(1.0f))
- {
- if (fi > btScalar(-1.0f))
- {
- xyz[0] = btAtan2(-btGetMatrixElem(mat,5),btGetMatrixElem(mat,8));
- xyz[1] = btAsin(btGetMatrixElem(mat,2));
- xyz[2] = btAtan2(-btGetMatrixElem(mat,1),btGetMatrixElem(mat,0));
- return true;
- }
- else
- {
- // WARNING. Not unique. XA - ZA = -atan2(r10,r11)
- xyz[0] = -btAtan2(btGetMatrixElem(mat,3),btGetMatrixElem(mat,4));
- xyz[1] = -SIMD_HALF_PI;
- xyz[2] = btScalar(0.0);
- return false;
- }
- }
- else
- {
- // WARNING. Not unique. XAngle + ZAngle = atan2(r10,r11)
- xyz[0] = btAtan2(btGetMatrixElem(mat,3),btGetMatrixElem(mat,4));
- xyz[1] = SIMD_HALF_PI;
- xyz[2] = 0.0;
- }
- return false;
- }
- //////////////////////////// btRotationalLimitMotor ////////////////////////////////////
- int btRotationalLimitMotor::testLimitValue(btScalar test_value)
- {
- if(m_loLimit>m_hiLimit)
- {
- m_currentLimit = 0;//Free from violation
- return 0;
- }
- if (test_value < m_loLimit)
- {
- m_currentLimit = 1;//low limit violation
- m_currentLimitError = test_value - m_loLimit;
- if(m_currentLimitError>SIMD_PI)
- m_currentLimitError-=SIMD_2_PI;
- else if(m_currentLimitError<-SIMD_PI)
- m_currentLimitError+=SIMD_2_PI;
- return 1;
- }
- else if (test_value> m_hiLimit)
- {
- m_currentLimit = 2;//High limit violation
- m_currentLimitError = test_value - m_hiLimit;
- if(m_currentLimitError>SIMD_PI)
- m_currentLimitError-=SIMD_2_PI;
- else if(m_currentLimitError<-SIMD_PI)
- m_currentLimitError+=SIMD_2_PI;
- return 2;
- };
- m_currentLimit = 0;//Free from violation
- return 0;
- }
- btScalar btRotationalLimitMotor::solveAngularLimits(
- btScalar timeStep,btVector3& axis,btScalar jacDiagABInv,
- btRigidBody * body0, btRigidBody * body1 )
- {
- if (needApplyTorques()==false) return 0.0f;
- btScalar target_velocity = m_targetVelocity;
- btScalar maxMotorForce = m_maxMotorForce;
- //current error correction
- if (m_currentLimit!=0)
- {
- target_velocity = -m_stopERP*m_currentLimitError/(timeStep);
- maxMotorForce = m_maxLimitForce;
- }
- maxMotorForce *= timeStep;
- // current velocity difference
- btVector3 angVelA = body0->getAngularVelocity();
- btVector3 angVelB = body1->getAngularVelocity();
- btVector3 vel_diff;
- vel_diff = angVelA-angVelB;
- btScalar rel_vel = axis.dot(vel_diff);
- // correction velocity
- btScalar motor_relvel = m_limitSoftness*(target_velocity - m_damping*rel_vel);
- if ( motor_relvel < SIMD_EPSILON && motor_relvel > -SIMD_EPSILON )
- {
- return 0.0f;//no need for applying force
- }
- // correction impulse
- btScalar unclippedMotorImpulse = (1+m_bounce)*motor_relvel*jacDiagABInv;
- // clip correction impulse
- btScalar clippedMotorImpulse;
- ///@todo: should clip against accumulated impulse
- if (unclippedMotorImpulse>0.0f)
- {
- clippedMotorImpulse = unclippedMotorImpulse > maxMotorForce? maxMotorForce: unclippedMotorImpulse;
- }
- else
- {
- clippedMotorImpulse = unclippedMotorImpulse < -maxMotorForce ? -maxMotorForce: unclippedMotorImpulse;
- }
- // sort with accumulated impulses
- btScalar lo = btScalar(-BT_LARGE_FLOAT);
- btScalar hi = btScalar(BT_LARGE_FLOAT);
- btScalar oldaccumImpulse = m_accumulatedImpulse;
- btScalar sum = oldaccumImpulse + clippedMotorImpulse;
- m_accumulatedImpulse = sum > hi ? btScalar(0.) : sum < lo ? btScalar(0.) : sum;
- clippedMotorImpulse = m_accumulatedImpulse - oldaccumImpulse;
- btVector3 motorImp = clippedMotorImpulse * axis;
- body0->applyTorqueImpulse(motorImp);
- body1->applyTorqueImpulse(-motorImp);
- return clippedMotorImpulse;
- }
- //////////////////////////// End btRotationalLimitMotor ////////////////////////////////////
- //////////////////////////// btTranslationalLimitMotor ////////////////////////////////////
- int btTranslationalLimitMotor::testLimitValue(int limitIndex, btScalar test_value)
- {
- btScalar loLimit = m_lowerLimit[limitIndex];
- btScalar hiLimit = m_upperLimit[limitIndex];
- if(loLimit > hiLimit)
- {
- m_currentLimit[limitIndex] = 0;//Free from violation
- m_currentLimitError[limitIndex] = btScalar(0.f);
- return 0;
- }
- if (test_value < loLimit)
- {
- m_currentLimit[limitIndex] = 2;//low limit violation
- m_currentLimitError[limitIndex] = test_value - loLimit;
- return 2;
- }
- else if (test_value> hiLimit)
- {
- m_currentLimit[limitIndex] = 1;//High limit violation
- m_currentLimitError[limitIndex] = test_value - hiLimit;
- return 1;
- };
- m_currentLimit[limitIndex] = 0;//Free from violation
- m_currentLimitError[limitIndex] = btScalar(0.f);
- return 0;
- }
- btScalar btTranslationalLimitMotor::solveLinearAxis(
- btScalar timeStep,
- btScalar jacDiagABInv,
- btRigidBody& body1,const btVector3 &pointInA,
- btRigidBody& body2,const btVector3 &pointInB,
- int limit_index,
- const btVector3 & axis_normal_on_a,
- const btVector3 & anchorPos)
- {
- ///find relative velocity
- // btVector3 rel_pos1 = pointInA - body1.getCenterOfMassPosition();
- // btVector3 rel_pos2 = pointInB - body2.getCenterOfMassPosition();
- btVector3 rel_pos1 = anchorPos - body1.getCenterOfMassPosition();
- btVector3 rel_pos2 = anchorPos - body2.getCenterOfMassPosition();
- btVector3 vel1 = body1.getVelocityInLocalPoint(rel_pos1);
- btVector3 vel2 = body2.getVelocityInLocalPoint(rel_pos2);
- btVector3 vel = vel1 - vel2;
- btScalar rel_vel = axis_normal_on_a.dot(vel);
- /// apply displacement correction
- //positional error (zeroth order error)
- btScalar depth = -(pointInA - pointInB).dot(axis_normal_on_a);
- btScalar lo = btScalar(-BT_LARGE_FLOAT);
- btScalar hi = btScalar(BT_LARGE_FLOAT);
- btScalar minLimit = m_lowerLimit[limit_index];
- btScalar maxLimit = m_upperLimit[limit_index];
- //handle the limits
- if (minLimit < maxLimit)
- {
- {
- if (depth > maxLimit)
- {
- depth -= maxLimit;
- lo = btScalar(0.);
- }
- else
- {
- if (depth < minLimit)
- {
- depth -= minLimit;
- hi = btScalar(0.);
- }
- else
- {
- return 0.0f;
- }
- }
- }
- }
- btScalar normalImpulse= m_limitSoftness*(m_restitution*depth/timeStep - m_damping*rel_vel) * jacDiagABInv;
- btScalar oldNormalImpulse = m_accumulatedImpulse[limit_index];
- btScalar sum = oldNormalImpulse + normalImpulse;
- m_accumulatedImpulse[limit_index] = sum > hi ? btScalar(0.) : sum < lo ? btScalar(0.) : sum;
- normalImpulse = m_accumulatedImpulse[limit_index] - oldNormalImpulse;
- btVector3 impulse_vector = axis_normal_on_a * normalImpulse;
- body1.applyImpulse( impulse_vector, rel_pos1);
- body2.applyImpulse(-impulse_vector, rel_pos2);
-
- return normalImpulse;
- }
- //////////////////////////// btTranslationalLimitMotor ////////////////////////////////////
- void btGeneric6DofConstraint::calculateAngleInfo()
- {
- btMatrix3x3 relative_frame = m_calculatedTransformA.getBasis().inverse()*m_calculatedTransformB.getBasis();
- matrixToEulerXYZ(relative_frame,m_calculatedAxisAngleDiff);
- // in euler angle mode we do not actually constrain the angular velocity
- // along the axes axis[0] and axis[2] (although we do use axis[1]) :
- //
- // to get constrain w2-w1 along ...not
- // ------ --------------------- ------
- // d(angle[0])/dt = 0 ax[1] x ax[2] ax[0]
- // d(angle[1])/dt = 0 ax[1]
- // d(angle[2])/dt = 0 ax[0] x ax[1] ax[2]
- //
- // constraining w2-w1 along an axis 'a' means that a'*(w2-w1)=0.
- // to prove the result for angle[0], write the expression for angle[0] from
- // GetInfo1 then take the derivative. to prove this for angle[2] it is
- // easier to take the euler rate expression for d(angle[2])/dt with respect
- // to the components of w and set that to 0.
- btVector3 axis0 = m_calculatedTransformB.getBasis().getColumn(0);
- btVector3 axis2 = m_calculatedTransformA.getBasis().getColumn(2);
- m_calculatedAxis[1] = axis2.cross(axis0);
- m_calculatedAxis[0] = m_calculatedAxis[1].cross(axis2);
- m_calculatedAxis[2] = axis0.cross(m_calculatedAxis[1]);
- m_calculatedAxis[0].normalize();
- m_calculatedAxis[1].normalize();
- m_calculatedAxis[2].normalize();
- }
- void btGeneric6DofConstraint::calculateTransforms()
- {
- calculateTransforms(m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform());
- }
- void btGeneric6DofConstraint::calculateTransforms(const btTransform& transA,const btTransform& transB)
- {
- m_calculatedTransformA = transA * m_frameInA;
- m_calculatedTransformB = transB * m_frameInB;
- calculateLinearInfo();
- calculateAngleInfo();
- if(m_useOffsetForConstraintFrame)
- { // get weight factors depending on masses
- btScalar miA = getRigidBodyA().getInvMass();
- btScalar miB = getRigidBodyB().getInvMass();
- m_hasStaticBody = (miA < SIMD_EPSILON) || (miB < SIMD_EPSILON);
- btScalar miS = miA + miB;
- if(miS > btScalar(0.f))
- {
- m_factA = miB / miS;
- }
- else
- {
- m_factA = btScalar(0.5f);
- }
- m_factB = btScalar(1.0f) - m_factA;
- }
- }
- void btGeneric6DofConstraint::buildLinearJacobian(
- btJacobianEntry & jacLinear,const btVector3 & normalWorld,
- const btVector3 & pivotAInW,const btVector3 & pivotBInW)
- {
- new (&jacLinear) btJacobianEntry(
- m_rbA.getCenterOfMassTransform().getBasis().transpose(),
- m_rbB.getCenterOfMassTransform().getBasis().transpose(),
- pivotAInW - m_rbA.getCenterOfMassPosition(),
- pivotBInW - m_rbB.getCenterOfMassPosition(),
- normalWorld,
- m_rbA.getInvInertiaDiagLocal(),
- m_rbA.getInvMass(),
- m_rbB.getInvInertiaDiagLocal(),
- m_rbB.getInvMass());
- }
- void btGeneric6DofConstraint::buildAngularJacobian(
- btJacobianEntry & jacAngular,const btVector3 & jointAxisW)
- {
- new (&jacAngular) btJacobianEntry(jointAxisW,
- m_rbA.getCenterOfMassTransform().getBasis().transpose(),
- m_rbB.getCenterOfMassTransform().getBasis().transpose(),
- m_rbA.getInvInertiaDiagLocal(),
- m_rbB.getInvInertiaDiagLocal());
- }
- bool btGeneric6DofConstraint::testAngularLimitMotor(int axis_index)
- {
- btScalar angle = m_calculatedAxisAngleDiff[axis_index];
- angle = btAdjustAngleToLimits(angle, m_angularLimits[axis_index].m_loLimit, m_angularLimits[axis_index].m_hiLimit);
- m_angularLimits[axis_index].m_currentPosition = angle;
- //test limits
- m_angularLimits[axis_index].testLimitValue(angle);
- return m_angularLimits[axis_index].needApplyTorques();
- }
- void btGeneric6DofConstraint::buildJacobian()
- {
- #ifndef __SPU__
- if (m_useSolveConstraintObsolete)
- {
- // Clear accumulated impulses for the next simulation step
- m_linearLimits.m_accumulatedImpulse.setValue(btScalar(0.), btScalar(0.), btScalar(0.));
- int i;
- for(i = 0; i < 3; i++)
- {
- m_angularLimits[i].m_accumulatedImpulse = btScalar(0.);
- }
- //calculates transform
- calculateTransforms(m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform());
- // const btVector3& pivotAInW = m_calculatedTransformA.getOrigin();
- // const btVector3& pivotBInW = m_calculatedTransformB.getOrigin();
- calcAnchorPos();
- btVector3 pivotAInW = m_AnchorPos;
- btVector3 pivotBInW = m_AnchorPos;
- // not used here
- // btVector3 rel_pos1 = pivotAInW - m_rbA.getCenterOfMassPosition();
- // btVector3 rel_pos2 = pivotBInW - m_rbB.getCenterOfMassPosition();
- btVector3 normalWorld;
- //linear part
- for (i=0;i<3;i++)
- {
- if (m_linearLimits.isLimited(i))
- {
- if (m_useLinearReferenceFrameA)
- normalWorld = m_calculatedTransformA.getBasis().getColumn(i);
- else
- normalWorld = m_calculatedTransformB.getBasis().getColumn(i);
- buildLinearJacobian(
- m_jacLinear[i],normalWorld ,
- pivotAInW,pivotBInW);
- }
- }
- // angular part
- for (i=0;i<3;i++)
- {
- //calculates error angle
- if (testAngularLimitMotor(i))
- {
- normalWorld = this->getAxis(i);
- // Create angular atom
- buildAngularJacobian(m_jacAng[i],normalWorld);
- }
- }
- }
- #endif //__SPU__
- }
- void btGeneric6DofConstraint::getInfo1 (btConstraintInfo1* info)
- {
- if (m_useSolveConstraintObsolete)
- {
- info->m_numConstraintRows = 0;
- info->nub = 0;
- } else
- {
- //prepare constraint
- calculateTransforms(m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform());
- info->m_numConstraintRows = 0;
- info->nub = 6;
- int i;
- //test linear limits
- for(i = 0; i < 3; i++)
- {
- if(m_linearLimits.needApplyForce(i))
- {
- info->m_numConstraintRows++;
- info->nub--;
- }
- }
- //test angular limits
- for (i=0;i<3 ;i++ )
- {
- if(testAngularLimitMotor(i))
- {
- info->m_numConstraintRows++;
- info->nub--;
- }
- }
- }
- }
- void btGeneric6DofConstraint::getInfo1NonVirtual (btConstraintInfo1* info)
- {
- if (m_useSolveConstraintObsolete)
- {
- info->m_numConstraintRows = 0;
- info->nub = 0;
- } else
- {
- //pre-allocate all 6
- info->m_numConstraintRows = 6;
- info->nub = 0;
- }
- }
- void btGeneric6DofConstraint::getInfo2 (btConstraintInfo2* info)
- {
- btAssert(!m_useSolveConstraintObsolete);
- const btTransform& transA = m_rbA.getCenterOfMassTransform();
- const btTransform& transB = m_rbB.getCenterOfMassTransform();
- const btVector3& linVelA = m_rbA.getLinearVelocity();
- const btVector3& linVelB = m_rbB.getLinearVelocity();
- const btVector3& angVelA = m_rbA.getAngularVelocity();
- const btVector3& angVelB = m_rbB.getAngularVelocity();
- if(m_useOffsetForConstraintFrame)
- { // for stability better to solve angular limits first
- int row = setAngularLimits(info, 0,transA,transB,linVelA,linVelB,angVelA,angVelB);
- setLinearLimits(info, row, transA,transB,linVelA,linVelB,angVelA,angVelB);
- }
- else
- { // leave old version for compatibility
- int row = setLinearLimits(info, 0, transA,transB,linVelA,linVelB,angVelA,angVelB);
- setAngularLimits(info, row,transA,transB,linVelA,linVelB,angVelA,angVelB);
- }
- }
- void btGeneric6DofConstraint::getInfo2NonVirtual (btConstraintInfo2* info, const btTransform& transA,const btTransform& transB,const btVector3& linVelA,const btVector3& linVelB,const btVector3& angVelA,const btVector3& angVelB)
- {
-
- btAssert(!m_useSolveConstraintObsolete);
- //prepare constraint
- calculateTransforms(transA,transB);
- int i;
- for (i=0;i<3 ;i++ )
- {
- testAngularLimitMotor(i);
- }
- if(m_useOffsetForConstraintFrame)
- { // for stability better to solve angular limits first
- int row = setAngularLimits(info, 0,transA,transB,linVelA,linVelB,angVelA,angVelB);
- setLinearLimits(info, row, transA,transB,linVelA,linVelB,angVelA,angVelB);
- }
- else
- { // leave old version for compatibility
- int row = setLinearLimits(info, 0, transA,transB,linVelA,linVelB,angVelA,angVelB);
- setAngularLimits(info, row,transA,transB,linVelA,linVelB,angVelA,angVelB);
- }
- }
- int btGeneric6DofConstraint::setLinearLimits(btConstraintInfo2* info, int row, const btTransform& transA,const btTransform& transB,const btVector3& linVelA,const btVector3& linVelB,const btVector3& angVelA,const btVector3& angVelB)
- {
- // int row = 0;
- //solve linear limits
- btRotationalLimitMotor limot;
- for (int i=0;i<3 ;i++ )
- {
- if(m_linearLimits.needApplyForce(i))
- { // re-use rotational motor code
- limot.m_bounce = btScalar(0.f);
- limot.m_currentLimit = m_linearLimits.m_currentLimit[i];
- limot.m_currentPosition = m_linearLimits.m_currentLinearDiff[i];
- limot.m_currentLimitError = m_linearLimits.m_currentLimitError[i];
- limot.m_damping = m_linearLimits.m_damping;
- limot.m_enableMotor = m_linearLimits.m_enableMotor[i];
- limot.m_hiLimit = m_linearLimits.m_upperLimit[i];
- limot.m_limitSoftness = m_linearLimits.m_limitSoftness;
- limot.m_loLimit = m_linearLimits.m_lowerLimit[i];
- limot.m_maxLimitForce = btScalar(0.f);
- limot.m_maxMotorForce = m_linearLimits.m_maxMotorForce[i];
- limot.m_targetVelocity = m_linearLimits.m_targetVelocity[i];
- btVector3 axis = m_calculatedTransformA.getBasis().getColumn(i);
- int flags = m_flags >> (i * BT_6DOF_FLAGS_AXIS_SHIFT);
- limot.m_normalCFM = (flags & BT_6DOF_FLAGS_CFM_NORM) ? m_linearLimits.m_normalCFM[i] : info->cfm[0];
- limot.m_stopCFM = (flags & BT_6DOF_FLAGS_CFM_STOP) ? m_linearLimits.m_stopCFM[i] : info->cfm[0];
- limot.m_stopERP = (flags & BT_6DOF_FLAGS_ERP_STOP) ? m_linearLimits.m_stopERP[i] : info->erp;
- if(m_useOffsetForConstraintFrame)
- {
- int indx1 = (i + 1) % 3;
- int indx2 = (i + 2) % 3;
- int rotAllowed = 1; // rotations around orthos to current axis
- if(m_angularLimits[indx1].m_currentLimit && m_angularLimits[indx2].m_currentLimit)
- {
- rotAllowed = 0;
- }
- row += get_limit_motor_info2(&limot, transA,transB,linVelA,linVelB,angVelA,angVelB, info, row, axis, 0, rotAllowed);
- }
- else
- {
- row += get_limit_motor_info2(&limot, transA,transB,linVelA,linVelB,angVelA,angVelB, info, row, axis, 0);
- }
- }
- }
- return row;
- }
- int btGeneric6DofConstraint::setAngularLimits(btConstraintInfo2 *info, int row_offset, const btTransform& transA,const btTransform& transB,const btVector3& linVelA,const btVector3& linVelB,const btVector3& angVelA,const btVector3& angVelB)
- {
- btGeneric6DofConstraint * d6constraint = this;
- int row = row_offset;
- //solve angular limits
- for (int i=0;i<3 ;i++ )
- {
- if(d6constraint->getRotationalLimitMotor(i)->needApplyTorques())
- {
- btVector3 axis = d6constraint->getAxis(i);
- int flags = m_flags >> ((i + 3) * BT_6DOF_FLAGS_AXIS_SHIFT);
- if(!(flags & BT_6DOF_FLAGS_CFM_NORM))
- {
- m_angularLimits[i].m_normalCFM = info->cfm[0];
- }
- if(!(flags & BT_6DOF_FLAGS_CFM_STOP))
- {
- m_angularLimits[i].m_stopCFM = info->cfm[0];
- }
- if(!(flags & BT_6DOF_FLAGS_ERP_STOP))
- {
- m_angularLimits[i].m_stopERP = info->erp;
- }
- row += get_limit_motor_info2(d6constraint->getRotationalLimitMotor(i),
- transA,transB,linVelA,linVelB,angVelA,angVelB, info,row,axis,1);
- }
- }
- return row;
- }
- void btGeneric6DofConstraint::updateRHS(btScalar timeStep)
- {
- (void)timeStep;
- }
- void btGeneric6DofConstraint::setFrames(const btTransform& frameA, const btTransform& frameB)
- {
- m_frameInA = frameA;
- m_frameInB = frameB;
- buildJacobian();
- calculateTransforms();
- }
- btVector3 btGeneric6DofConstraint::getAxis(int axis_index) const
- {
- return m_calculatedAxis[axis_index];
- }
- btScalar btGeneric6DofConstraint::getRelativePivotPosition(int axisIndex) const
- {
- return m_calculatedLinearDiff[axisIndex];
- }
- btScalar btGeneric6DofConstraint::getAngle(int axisIndex) const
- {
- return m_calculatedAxisAngleDiff[axisIndex];
- }
- void btGeneric6DofConstraint::calcAnchorPos(void)
- {
- btScalar imA = m_rbA.getInvMass();
- btScalar imB = m_rbB.getInvMass();
- btScalar weight;
- if(imB == btScalar(0.0))
- {
- weight = btScalar(1.0);
- }
- else
- {
- weight = imA / (imA + imB);
- }
- const btVector3& pA = m_calculatedTransformA.getOrigin();
- const btVector3& pB = m_calculatedTransformB.getOrigin();
- m_AnchorPos = pA * weight + pB * (btScalar(1.0) - weight);
- return;
- }
- void btGeneric6DofConstraint::calculateLinearInfo()
- {
- m_calculatedLinearDiff = m_calculatedTransformB.getOrigin() - m_calculatedTransformA.getOrigin();
- m_calculatedLinearDiff = m_calculatedTransformA.getBasis().inverse() * m_calculatedLinearDiff;
- for(int i = 0; i < 3; i++)
- {
- m_linearLimits.m_currentLinearDiff[i] = m_calculatedLinearDiff[i];
- m_linearLimits.testLimitValue(i, m_calculatedLinearDiff[i]);
- }
- }
- int btGeneric6DofConstraint::get_limit_motor_info2(
- btRotationalLimitMotor * limot,
- const btTransform& transA,const btTransform& transB,const btVector3& linVelA,const btVector3& linVelB,const btVector3& angVelA,const btVector3& angVelB,
- btConstraintInfo2 *info, int row, btVector3& ax1, int rotational,int rotAllowed)
- {
- int srow = row * info->rowskip;
- int powered = limot->m_enableMotor;
- int limit = limot->m_currentLimit;
- if (powered || limit)
- { // if the joint is powered, or has joint limits, add in the extra row
- btScalar *J1 = rotational ? info->m_J1angularAxis : info->m_J1linearAxis;
- btScalar *J2 = rotational ? info->m_J2angularAxis : info->m_J2linearAxis;
- J1[srow+0] = ax1[0];
- J1[srow+1] = ax1[1];
- J1[srow+2] = ax1[2];
- J2[srow+0] = -ax1[0];
- J2[srow+1] = -ax1[1];
- J2[srow+2] = -ax1[2];
- if((!rotational))
- {
- if (m_useOffsetForConstraintFrame)
- {
- btVector3 tmpA, tmpB, relA, relB;
- // get vector from bodyB to frameB in WCS
- relB = m_calculatedTransformB.getOrigin() - transB.getOrigin();
- // get its projection to constraint axis
- btVector3 projB = ax1 * relB.dot(ax1);
- // get vector directed from bodyB to constraint axis (and orthogonal to it)
- btVector3 orthoB = relB - projB;
- // same for bodyA
- relA = m_calculatedTransformA.getOrigin() - transA.getOrigin();
- btVector3 projA = ax1 * relA.dot(ax1);
- btVector3 orthoA = relA - projA;
- // get desired offset between frames A and B along constraint axis
- btScalar desiredOffs = limot->m_currentPosition - limot->m_currentLimitError;
- // desired vector from projection of center of bodyA to projection of center of bodyB to constraint axis
- btVector3 totalDist = projA + ax1 * desiredOffs - projB;
- // get offset vectors relA and relB
- relA = orthoA + totalDist * m_factA;
- relB = orthoB - totalDist * m_factB;
- tmpA = relA.cross(ax1);
- tmpB = relB.cross(ax1);
- if(m_hasStaticBody && (!rotAllowed))
- {
- tmpA *= m_factA;
- tmpB *= m_factB;
- }
- int i;
- for (i=0; i<3; i++) info->m_J1angularAxis[srow+i] = tmpA[i];
- for (i=0; i<3; i++) info->m_J2angularAxis[srow+i] = -tmpB[i];
- } else
- {
- btVector3 ltd; // Linear Torque Decoupling vector
- btVector3 c = m_calculatedTransformB.getOrigin() - transA.getOrigin();
- ltd = c.cross(ax1);
- info->m_J1angularAxis[srow+0] = ltd[0];
- info->m_J1angularAxis[srow+1] = ltd[1];
- info->m_J1angularAxis[srow+2] = ltd[2];
- c = m_calculatedTransformB.getOrigin() - transB.getOrigin();
- ltd = -c.cross(ax1);
- info->m_J2angularAxis[srow+0] = ltd[0];
- info->m_J2angularAxis[srow+1] = ltd[1];
- info->m_J2angularAxis[srow+2] = ltd[2];
- }
- }
- // if we're limited low and high simultaneously, the joint motor is
- // ineffective
- if (limit && (limot->m_loLimit == limot->m_hiLimit)) powered = 0;
- info->m_constraintError[srow] = btScalar(0.f);
- if (powered)
- {
- info->cfm[srow] = limot->m_normalCFM;
- if(!limit)
- {
- btScalar tag_vel = rotational ? limot->m_targetVelocity : -limot->m_targetVelocity;
- btScalar mot_fact = getMotorFactor( limot->m_currentPosition,
- limot->m_loLimit,
- limot->m_hiLimit,
- tag_vel,
- info->fps * limot->m_stopERP);
- info->m_constraintError[srow] += mot_fact * limot->m_targetVelocity;
- info->m_lowerLimit[srow] = -limot->m_maxMotorForce;
- info->m_upperLimit[srow] = limot->m_maxMotorForce;
- }
- }
- if(limit)
- {
- btScalar k = info->fps * limot->m_stopERP;
- if(!rotational)
- {
- info->m_constraintError[srow] += k * limot->m_currentLimitError;
- }
- else
- {
- info->m_constraintError[srow] += -k * limot->m_currentLimitError;
- }
- info->cfm[srow] = limot->m_stopCFM;
- if (limot->m_loLimit == limot->m_hiLimit)
- { // limited low and high simultaneously
- info->m_lowerLimit[srow] = -SIMD_INFINITY;
- info->m_upperLimit[srow] = SIMD_INFINITY;
- }
- else
- {
- if (limit == 1)
- {
- info->m_lowerLimit[srow] = 0;
- info->m_upperLimit[srow] = SIMD_INFINITY;
- }
- else
- {
- info->m_lowerLimit[srow] = -SIMD_INFINITY;
- info->m_upperLimit[srow] = 0;
- }
- // deal with bounce
- if (limot->m_bounce > 0)
- {
- // calculate joint velocity
- btScalar vel;
- if (rotational)
- {
- vel = angVelA.dot(ax1);
- //make sure that if no body -> angVelB == zero vec
- // if (body1)
- vel -= angVelB.dot(ax1);
- }
- else
- {
- vel = linVelA.dot(ax1);
- //make sure that if no body -> angVelB == zero vec
- // if (body1)
- vel -= linVelB.dot(ax1);
- }
- // only apply bounce if the velocity is incoming, and if the
- // resulting c[] exceeds what we already have.
- if (limit == 1)
- {
- if (vel < 0)
- {
- btScalar newc = -limot->m_bounce* vel;
- if (newc > info->m_constraintError[srow])
- info->m_constraintError[srow] = newc;
- }
- }
- else
- {
- if (vel > 0)
- {
- btScalar newc = -limot->m_bounce * vel;
- if (newc < info->m_constraintError[srow])
- info->m_constraintError[srow] = newc;
- }
- }
- }
- }
- }
- return 1;
- }
- else return 0;
- }
- ///override the default global value of a parameter (such as ERP or CFM), optionally provide the axis (0..5).
- ///If no axis is provided, it uses the default axis for this constraint.
- void btGeneric6DofConstraint::setParam(int num, btScalar value, int axis)
- {
- if((axis >= 0) && (axis < 3))
- {
- switch(num)
- {
- case BT_CONSTRAINT_STOP_ERP :
- m_linearLimits.m_stopERP[axis] = value;
- m_flags |= BT_6DOF_FLAGS_ERP_STOP << (axis * BT_6DOF_FLAGS_AXIS_SHIFT);
- break;
- case BT_CONSTRAINT_STOP_CFM :
- m_linearLimits.m_stopCFM[axis] = value;
- m_flags |= BT_6DOF_FLAGS_CFM_STOP << (axis * BT_6DOF_FLAGS_AXIS_SHIFT);
- break;
- case BT_CONSTRAINT_CFM :
- m_linearLimits.m_normalCFM[axis] = value;
- m_flags |= BT_6DOF_FLAGS_CFM_NORM << (axis * BT_6DOF_FLAGS_AXIS_SHIFT);
- break;
- default :
- btAssertConstrParams(0);
- }
- }
- else if((axis >=3) && (axis < 6))
- {
- switch(num)
- {
- case BT_CONSTRAINT_STOP_ERP :
- m_angularLimits[axis - 3].m_stopERP = value;
- m_flags |= BT_6DOF_FLAGS_ERP_STOP << (axis * BT_6DOF_FLAGS_AXIS_SHIFT);
- break;
- case BT_CONSTRAINT_STOP_CFM :
- m_angularLimits[axis - 3].m_stopCFM = value;
- m_flags |= BT_6DOF_FLAGS_CFM_STOP << (axis * BT_6DOF_FLAGS_AXIS_SHIFT);
- break;
- case BT_CONSTRAINT_CFM :
- m_angularLimits[axis - 3].m_normalCFM = value;
- m_flags |= BT_6DOF_FLAGS_CFM_NORM << (axis * BT_6DOF_FLAGS_AXIS_SHIFT);
- break;
- default :
- btAssertConstrParams(0);
- }
- }
- else
- {
- btAssertConstrParams(0);
- }
- }
- ///return the local value of parameter
- btScalar btGeneric6DofConstraint::getParam(int num, int axis) const
- {
- btScalar retVal = 0;
- if((axis >= 0) && (axis < 3))
- {
- switch(num)
- {
- case BT_CONSTRAINT_STOP_ERP :
- btAssertConstrParams(m_flags & (BT_6DOF_FLAGS_ERP_STOP << (axis * BT_6DOF_FLAGS_AXIS_SHIFT)));
- retVal = m_linearLimits.m_stopERP[axis];
- break;
- case BT_CONSTRAINT_STOP_CFM :
- btAssertConstrParams(m_flags & (BT_6DOF_FLAGS_CFM_STOP << (axis * BT_6DOF_FLAGS_AXIS_SHIFT)));
- retVal = m_linearLimits.m_stopCFM[axis];
- break;
- case BT_CONSTRAINT_CFM :
- btAssertConstrParams(m_flags & (BT_6DOF_FLAGS_CFM_NORM << (axis * BT_6DOF_FLAGS_AXIS_SHIFT)));
- retVal = m_linearLimits.m_normalCFM[axis];
- break;
- default :
- btAssertConstrParams(0);
- }
- }
- else if((axis >=3) && (axis < 6))
- {
- switch(num)
- {
- case BT_CONSTRAINT_STOP_ERP :
- btAssertConstrParams(m_flags & (BT_6DOF_FLAGS_ERP_STOP << (axis * BT_6DOF_FLAGS_AXIS_SHIFT)));
- retVal = m_angularLimits[axis - 3].m_stopERP;
- break;
- case BT_CONSTRAINT_STOP_CFM :
- btAssertConstrParams(m_flags & (BT_6DOF_FLAGS_CFM_STOP << (axis * BT_6DOF_FLAGS_AXIS_SHIFT)));
- retVal = m_angularLimits[axis - 3].m_stopCFM;
- break;
- case BT_CONSTRAINT_CFM :
- btAssertConstrParams(m_flags & (BT_6DOF_FLAGS_CFM_NORM << (axis * BT_6DOF_FLAGS_AXIS_SHIFT)));
- retVal = m_angularLimits[axis - 3].m_normalCFM;
- break;
- default :
- btAssertConstrParams(0);
- }
- }
- else
- {
- btAssertConstrParams(0);
- }
- return retVal;
- }
-
- void btGeneric6DofConstraint::setAxis(const btVector3& axis1,const btVector3& axis2)
- {
- btVector3 zAxis = axis1.normalized();
- btVector3 yAxis = axis2.normalized();
- btVector3 xAxis = yAxis.cross(zAxis); // we want right coordinate system
-
- btTransform frameInW;
- frameInW.setIdentity();
- frameInW.getBasis().setValue( xAxis[0], yAxis[0], zAxis[0],
- xAxis[1], yAxis[1], zAxis[1],
- xAxis[2], yAxis[2], zAxis[2]);
-
- // now get constraint frame in local coordinate systems
- m_frameInA = m_rbA.getCenterOfMassTransform().inverse() * frameInW;
- m_frameInB = m_rbB.getCenterOfMassTransform().inverse() * frameInW;
-
- calculateTransforms();
- }
|