2
Bullet Continuous Collision Detection and Physics Library
3
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
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.
17
Refactored by Francisco Le?n
18
email: projectileman@yahoo.com
22
#include "btGeneric6DofConstraint.h"
23
#include "BulletDynamics/Dynamics/btRigidBody.h"
24
#include "LinearMath/btTransformUtil.h"
25
#include "LinearMath/btTransformUtil.h"
30
#define D6_USE_OBSOLETE_METHOD false
31
#define D6_USE_FRAME_OFFSET true
38
btGeneric6DofConstraint::btGeneric6DofConstraint(btRigidBody& rbA, btRigidBody& rbB, const btTransform& frameInA, const btTransform& frameInB, bool useLinearReferenceFrameA)
39
: btTypedConstraint(D6_CONSTRAINT_TYPE, rbA, rbB)
40
, m_frameInA(frameInA)
41
, m_frameInB(frameInB),
42
m_useLinearReferenceFrameA(useLinearReferenceFrameA),
43
m_useOffsetForConstraintFrame(D6_USE_FRAME_OFFSET),
45
m_useSolveConstraintObsolete(D6_USE_OBSOLETE_METHOD)
47
calculateTransforms();
52
btGeneric6DofConstraint::btGeneric6DofConstraint(btRigidBody& rbB, const btTransform& frameInB, bool useLinearReferenceFrameB)
53
: btTypedConstraint(D6_CONSTRAINT_TYPE, getFixedBody(), rbB),
55
m_useLinearReferenceFrameA(useLinearReferenceFrameB),
56
m_useOffsetForConstraintFrame(D6_USE_FRAME_OFFSET),
58
m_useSolveConstraintObsolete(false)
60
///not providing rigidbody A means implicitly using worldspace for body A
61
m_frameInA = rbB.getCenterOfMassTransform() * m_frameInB;
62
calculateTransforms();
68
#define GENERIC_D6_DISABLE_WARMSTARTING 1
72
btScalar btGetMatrixElem(const btMatrix3x3& mat, int index);
73
btScalar btGetMatrixElem(const btMatrix3x3& mat, int index)
82
///MatrixToEulerXYZ from http://www.geometrictools.com/LibFoundation/Mathematics/Wm4Matrix3.inl.html
83
bool matrixToEulerXYZ(const btMatrix3x3& mat,btVector3& xyz);
84
bool matrixToEulerXYZ(const btMatrix3x3& mat,btVector3& xyz)
86
// // rot = cy*cz -cy*sz sy
87
// // cz*sx*sy+cx*sz cx*cz-sx*sy*sz -cy*sx
88
// // -cx*cz*sy+sx*sz cz*sx+cx*sy*sz cx*cy
91
btScalar fi = btGetMatrixElem(mat,2);
92
if (fi < btScalar(1.0f))
94
if (fi > btScalar(-1.0f))
96
xyz[0] = btAtan2(-btGetMatrixElem(mat,5),btGetMatrixElem(mat,8));
97
xyz[1] = btAsin(btGetMatrixElem(mat,2));
98
xyz[2] = btAtan2(-btGetMatrixElem(mat,1),btGetMatrixElem(mat,0));
103
// WARNING. Not unique. XA - ZA = -atan2(r10,r11)
104
xyz[0] = -btAtan2(btGetMatrixElem(mat,3),btGetMatrixElem(mat,4));
105
xyz[1] = -SIMD_HALF_PI;
106
xyz[2] = btScalar(0.0);
112
// WARNING. Not unique. XAngle + ZAngle = atan2(r10,r11)
113
xyz[0] = btAtan2(btGetMatrixElem(mat,3),btGetMatrixElem(mat,4));
114
xyz[1] = SIMD_HALF_PI;
120
//////////////////////////// btRotationalLimitMotor ////////////////////////////////////
122
int btRotationalLimitMotor::testLimitValue(btScalar test_value)
124
if(m_loLimit>m_hiLimit)
126
m_currentLimit = 0;//Free from violation
129
if (test_value < m_loLimit)
131
m_currentLimit = 1;//low limit violation
132
m_currentLimitError = test_value - m_loLimit;
135
else if (test_value> m_hiLimit)
137
m_currentLimit = 2;//High limit violation
138
m_currentLimitError = test_value - m_hiLimit;
142
m_currentLimit = 0;//Free from violation
149
btScalar btRotationalLimitMotor::solveAngularLimits(
150
btScalar timeStep,btVector3& axis,btScalar jacDiagABInv,
151
btRigidBody * body0, btRigidBody * body1 )
153
if (needApplyTorques()==false) return 0.0f;
155
btScalar target_velocity = m_targetVelocity;
156
btScalar maxMotorForce = m_maxMotorForce;
158
//current error correction
159
if (m_currentLimit!=0)
161
target_velocity = -m_stopERP*m_currentLimitError/(timeStep);
162
maxMotorForce = m_maxLimitForce;
165
maxMotorForce *= timeStep;
167
// current velocity difference
170
body0->internalGetAngularVelocity(angVelA);
172
body1->internalGetAngularVelocity(angVelB);
175
vel_diff = angVelA-angVelB;
179
btScalar rel_vel = axis.dot(vel_diff);
181
// correction velocity
182
btScalar motor_relvel = m_limitSoftness*(target_velocity - m_damping*rel_vel);
185
if ( motor_relvel < SIMD_EPSILON && motor_relvel > -SIMD_EPSILON )
187
return 0.0f;//no need for applying force
191
// correction impulse
192
btScalar unclippedMotorImpulse = (1+m_bounce)*motor_relvel*jacDiagABInv;
194
// clip correction impulse
195
btScalar clippedMotorImpulse;
197
///@todo: should clip against accumulated impulse
198
if (unclippedMotorImpulse>0.0f)
200
clippedMotorImpulse = unclippedMotorImpulse > maxMotorForce? maxMotorForce: unclippedMotorImpulse;
204
clippedMotorImpulse = unclippedMotorImpulse < -maxMotorForce ? -maxMotorForce: unclippedMotorImpulse;
208
// sort with accumulated impulses
209
btScalar lo = btScalar(-BT_LARGE_FLOAT);
210
btScalar hi = btScalar(BT_LARGE_FLOAT);
212
btScalar oldaccumImpulse = m_accumulatedImpulse;
213
btScalar sum = oldaccumImpulse + clippedMotorImpulse;
214
m_accumulatedImpulse = sum > hi ? btScalar(0.) : sum < lo ? btScalar(0.) : sum;
216
clippedMotorImpulse = m_accumulatedImpulse - oldaccumImpulse;
218
btVector3 motorImp = clippedMotorImpulse * axis;
220
//body0->applyTorqueImpulse(motorImp);
221
//body1->applyTorqueImpulse(-motorImp);
223
body0->internalApplyImpulse(btVector3(0,0,0), body0->getInvInertiaTensorWorld()*axis,clippedMotorImpulse);
224
body1->internalApplyImpulse(btVector3(0,0,0), body1->getInvInertiaTensorWorld()*axis,-clippedMotorImpulse);
227
return clippedMotorImpulse;
232
//////////////////////////// End btRotationalLimitMotor ////////////////////////////////////
237
//////////////////////////// btTranslationalLimitMotor ////////////////////////////////////
240
int btTranslationalLimitMotor::testLimitValue(int limitIndex, btScalar test_value)
242
btScalar loLimit = m_lowerLimit[limitIndex];
243
btScalar hiLimit = m_upperLimit[limitIndex];
244
if(loLimit > hiLimit)
246
m_currentLimit[limitIndex] = 0;//Free from violation
247
m_currentLimitError[limitIndex] = btScalar(0.f);
251
if (test_value < loLimit)
253
m_currentLimit[limitIndex] = 2;//low limit violation
254
m_currentLimitError[limitIndex] = test_value - loLimit;
257
else if (test_value> hiLimit)
259
m_currentLimit[limitIndex] = 1;//High limit violation
260
m_currentLimitError[limitIndex] = test_value - hiLimit;
264
m_currentLimit[limitIndex] = 0;//Free from violation
265
m_currentLimitError[limitIndex] = btScalar(0.f);
271
btScalar btTranslationalLimitMotor::solveLinearAxis(
273
btScalar jacDiagABInv,
274
btRigidBody& body1,const btVector3 &pointInA,
275
btRigidBody& body2,const btVector3 &pointInB,
277
const btVector3 & axis_normal_on_a,
278
const btVector3 & anchorPos)
281
///find relative velocity
282
// btVector3 rel_pos1 = pointInA - body1.getCenterOfMassPosition();
283
// btVector3 rel_pos2 = pointInB - body2.getCenterOfMassPosition();
284
btVector3 rel_pos1 = anchorPos - body1.getCenterOfMassPosition();
285
btVector3 rel_pos2 = anchorPos - body2.getCenterOfMassPosition();
288
body1.internalGetVelocityInLocalPointObsolete(rel_pos1,vel1);
290
body2.internalGetVelocityInLocalPointObsolete(rel_pos2,vel2);
291
btVector3 vel = vel1 - vel2;
293
btScalar rel_vel = axis_normal_on_a.dot(vel);
297
/// apply displacement correction
299
//positional error (zeroth order error)
300
btScalar depth = -(pointInA - pointInB).dot(axis_normal_on_a);
301
btScalar lo = btScalar(-BT_LARGE_FLOAT);
302
btScalar hi = btScalar(BT_LARGE_FLOAT);
304
btScalar minLimit = m_lowerLimit[limit_index];
305
btScalar maxLimit = m_upperLimit[limit_index];
308
if (minLimit < maxLimit)
311
if (depth > maxLimit)
319
if (depth < minLimit)
332
btScalar normalImpulse= m_limitSoftness*(m_restitution*depth/timeStep - m_damping*rel_vel) * jacDiagABInv;
337
btScalar oldNormalImpulse = m_accumulatedImpulse[limit_index];
338
btScalar sum = oldNormalImpulse + normalImpulse;
339
m_accumulatedImpulse[limit_index] = sum > hi ? btScalar(0.) : sum < lo ? btScalar(0.) : sum;
340
normalImpulse = m_accumulatedImpulse[limit_index] - oldNormalImpulse;
342
btVector3 impulse_vector = axis_normal_on_a * normalImpulse;
343
//body1.applyImpulse( impulse_vector, rel_pos1);
344
//body2.applyImpulse(-impulse_vector, rel_pos2);
346
btVector3 ftorqueAxis1 = rel_pos1.cross(axis_normal_on_a);
347
btVector3 ftorqueAxis2 = rel_pos2.cross(axis_normal_on_a);
348
body1.internalApplyImpulse(axis_normal_on_a*body1.getInvMass(), body1.getInvInertiaTensorWorld()*ftorqueAxis1,normalImpulse);
349
body2.internalApplyImpulse(axis_normal_on_a*body2.getInvMass(), body2.getInvInertiaTensorWorld()*ftorqueAxis2,-normalImpulse);
354
return normalImpulse;
357
//////////////////////////// btTranslationalLimitMotor ////////////////////////////////////
359
void btGeneric6DofConstraint::calculateAngleInfo()
361
btMatrix3x3 relative_frame = m_calculatedTransformA.getBasis().inverse()*m_calculatedTransformB.getBasis();
362
matrixToEulerXYZ(relative_frame,m_calculatedAxisAngleDiff);
363
// in euler angle mode we do not actually constrain the angular velocity
364
// along the axes axis[0] and axis[2] (although we do use axis[1]) :
366
// to get constrain w2-w1 along ...not
367
// ------ --------------------- ------
368
// d(angle[0])/dt = 0 ax[1] x ax[2] ax[0]
369
// d(angle[1])/dt = 0 ax[1]
370
// d(angle[2])/dt = 0 ax[0] x ax[1] ax[2]
372
// constraining w2-w1 along an axis 'a' means that a'*(w2-w1)=0.
373
// to prove the result for angle[0], write the expression for angle[0] from
374
// GetInfo1 then take the derivative. to prove this for angle[2] it is
375
// easier to take the euler rate expression for d(angle[2])/dt with respect
376
// to the components of w and set that to 0.
377
btVector3 axis0 = m_calculatedTransformB.getBasis().getColumn(0);
378
btVector3 axis2 = m_calculatedTransformA.getBasis().getColumn(2);
380
m_calculatedAxis[1] = axis2.cross(axis0);
381
m_calculatedAxis[0] = m_calculatedAxis[1].cross(axis2);
382
m_calculatedAxis[2] = axis0.cross(m_calculatedAxis[1]);
384
m_calculatedAxis[0].normalize();
385
m_calculatedAxis[1].normalize();
386
m_calculatedAxis[2].normalize();
390
void btGeneric6DofConstraint::calculateTransforms()
392
calculateTransforms(m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform());
395
void btGeneric6DofConstraint::calculateTransforms(const btTransform& transA,const btTransform& transB)
397
m_calculatedTransformA = transA * m_frameInA;
398
m_calculatedTransformB = transB * m_frameInB;
399
calculateLinearInfo();
400
calculateAngleInfo();
401
if(m_useOffsetForConstraintFrame)
402
{ // get weight factors depending on masses
403
btScalar miA = getRigidBodyA().getInvMass();
404
btScalar miB = getRigidBodyB().getInvMass();
405
m_hasStaticBody = (miA < SIMD_EPSILON) || (miB < SIMD_EPSILON);
406
btScalar miS = miA + miB;
407
if(miS > btScalar(0.f))
413
m_factA = btScalar(0.5f);
415
m_factB = btScalar(1.0f) - m_factA;
421
void btGeneric6DofConstraint::buildLinearJacobian(
422
btJacobianEntry & jacLinear,const btVector3 & normalWorld,
423
const btVector3 & pivotAInW,const btVector3 & pivotBInW)
425
new (&jacLinear) btJacobianEntry(
426
m_rbA.getCenterOfMassTransform().getBasis().transpose(),
427
m_rbB.getCenterOfMassTransform().getBasis().transpose(),
428
pivotAInW - m_rbA.getCenterOfMassPosition(),
429
pivotBInW - m_rbB.getCenterOfMassPosition(),
431
m_rbA.getInvInertiaDiagLocal(),
433
m_rbB.getInvInertiaDiagLocal(),
439
void btGeneric6DofConstraint::buildAngularJacobian(
440
btJacobianEntry & jacAngular,const btVector3 & jointAxisW)
442
new (&jacAngular) btJacobianEntry(jointAxisW,
443
m_rbA.getCenterOfMassTransform().getBasis().transpose(),
444
m_rbB.getCenterOfMassTransform().getBasis().transpose(),
445
m_rbA.getInvInertiaDiagLocal(),
446
m_rbB.getInvInertiaDiagLocal());
452
bool btGeneric6DofConstraint::testAngularLimitMotor(int axis_index)
454
btScalar angle = m_calculatedAxisAngleDiff[axis_index];
455
angle = btAdjustAngleToLimits(angle, m_angularLimits[axis_index].m_loLimit, m_angularLimits[axis_index].m_hiLimit);
456
m_angularLimits[axis_index].m_currentPosition = angle;
458
m_angularLimits[axis_index].testLimitValue(angle);
459
return m_angularLimits[axis_index].needApplyTorques();
464
void btGeneric6DofConstraint::buildJacobian()
467
if (m_useSolveConstraintObsolete)
470
// Clear accumulated impulses for the next simulation step
471
m_linearLimits.m_accumulatedImpulse.setValue(btScalar(0.), btScalar(0.), btScalar(0.));
473
for(i = 0; i < 3; i++)
475
m_angularLimits[i].m_accumulatedImpulse = btScalar(0.);
477
//calculates transform
478
calculateTransforms(m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform());
480
// const btVector3& pivotAInW = m_calculatedTransformA.getOrigin();
481
// const btVector3& pivotBInW = m_calculatedTransformB.getOrigin();
483
btVector3 pivotAInW = m_AnchorPos;
484
btVector3 pivotBInW = m_AnchorPos;
487
// btVector3 rel_pos1 = pivotAInW - m_rbA.getCenterOfMassPosition();
488
// btVector3 rel_pos2 = pivotBInW - m_rbB.getCenterOfMassPosition();
490
btVector3 normalWorld;
494
if (m_linearLimits.isLimited(i))
496
if (m_useLinearReferenceFrameA)
497
normalWorld = m_calculatedTransformA.getBasis().getColumn(i);
499
normalWorld = m_calculatedTransformB.getBasis().getColumn(i);
502
m_jacLinear[i],normalWorld ,
503
pivotAInW,pivotBInW);
511
//calculates error angle
512
if (testAngularLimitMotor(i))
514
normalWorld = this->getAxis(i);
515
// Create angular atom
516
buildAngularJacobian(m_jacAng[i],normalWorld);
526
void btGeneric6DofConstraint::getInfo1 (btConstraintInfo1* info)
528
if (m_useSolveConstraintObsolete)
530
info->m_numConstraintRows = 0;
535
calculateTransforms(m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform());
536
info->m_numConstraintRows = 0;
540
for(i = 0; i < 3; i++)
542
if(m_linearLimits.needApplyForce(i))
544
info->m_numConstraintRows++;
548
//test angular limits
551
if(testAngularLimitMotor(i))
553
info->m_numConstraintRows++;
560
void btGeneric6DofConstraint::getInfo1NonVirtual (btConstraintInfo1* info)
562
if (m_useSolveConstraintObsolete)
564
info->m_numConstraintRows = 0;
569
info->m_numConstraintRows = 6;
575
void btGeneric6DofConstraint::getInfo2 (btConstraintInfo2* info)
577
btAssert(!m_useSolveConstraintObsolete);
579
const btTransform& transA = m_rbA.getCenterOfMassTransform();
580
const btTransform& transB = m_rbB.getCenterOfMassTransform();
581
const btVector3& linVelA = m_rbA.getLinearVelocity();
582
const btVector3& linVelB = m_rbB.getLinearVelocity();
583
const btVector3& angVelA = m_rbA.getAngularVelocity();
584
const btVector3& angVelB = m_rbB.getAngularVelocity();
586
if(m_useOffsetForConstraintFrame)
587
{ // for stability better to solve angular limits first
588
int row = setAngularLimits(info, 0,transA,transB,linVelA,linVelB,angVelA,angVelB);
589
setLinearLimits(info, row, transA,transB,linVelA,linVelB,angVelA,angVelB);
592
{ // leave old version for compatibility
593
int row = setLinearLimits(info, 0, transA,transB,linVelA,linVelB,angVelA,angVelB);
594
setAngularLimits(info, row,transA,transB,linVelA,linVelB,angVelA,angVelB);
600
void btGeneric6DofConstraint::getInfo2NonVirtual (btConstraintInfo2* info, const btTransform& transA,const btTransform& transB,const btVector3& linVelA,const btVector3& linVelB,const btVector3& angVelA,const btVector3& angVelB)
603
btAssert(!m_useSolveConstraintObsolete);
605
calculateTransforms(transA,transB);
610
testAngularLimitMotor(i);
613
if(m_useOffsetForConstraintFrame)
614
{ // for stability better to solve angular limits first
615
int row = setAngularLimits(info, 0,transA,transB,linVelA,linVelB,angVelA,angVelB);
616
setLinearLimits(info, row, transA,transB,linVelA,linVelB,angVelA,angVelB);
619
{ // leave old version for compatibility
620
int row = setLinearLimits(info, 0, transA,transB,linVelA,linVelB,angVelA,angVelB);
621
setAngularLimits(info, row,transA,transB,linVelA,linVelB,angVelA,angVelB);
627
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)
630
//solve linear limits
631
btRotationalLimitMotor limot;
632
for (int i=0;i<3 ;i++ )
634
if(m_linearLimits.needApplyForce(i))
635
{ // re-use rotational motor code
636
limot.m_bounce = btScalar(0.f);
637
limot.m_currentLimit = m_linearLimits.m_currentLimit[i];
638
limot.m_currentPosition = m_linearLimits.m_currentLinearDiff[i];
639
limot.m_currentLimitError = m_linearLimits.m_currentLimitError[i];
640
limot.m_damping = m_linearLimits.m_damping;
641
limot.m_enableMotor = m_linearLimits.m_enableMotor[i];
642
limot.m_hiLimit = m_linearLimits.m_upperLimit[i];
643
limot.m_limitSoftness = m_linearLimits.m_limitSoftness;
644
limot.m_loLimit = m_linearLimits.m_lowerLimit[i];
645
limot.m_maxLimitForce = btScalar(0.f);
646
limot.m_maxMotorForce = m_linearLimits.m_maxMotorForce[i];
647
limot.m_targetVelocity = m_linearLimits.m_targetVelocity[i];
648
btVector3 axis = m_calculatedTransformA.getBasis().getColumn(i);
649
int flags = m_flags >> (i * BT_6DOF_FLAGS_AXIS_SHIFT);
650
limot.m_normalCFM = (flags & BT_6DOF_FLAGS_CFM_NORM) ? m_linearLimits.m_normalCFM[i] : info->cfm[0];
651
limot.m_stopCFM = (flags & BT_6DOF_FLAGS_CFM_STOP) ? m_linearLimits.m_stopCFM[i] : info->cfm[0];
652
limot.m_stopERP = (flags & BT_6DOF_FLAGS_ERP_STOP) ? m_linearLimits.m_stopERP[i] : info->erp;
653
if(m_useOffsetForConstraintFrame)
655
int indx1 = (i + 1) % 3;
656
int indx2 = (i + 2) % 3;
657
int rotAllowed = 1; // rotations around orthos to current axis
658
if(m_angularLimits[indx1].m_currentLimit && m_angularLimits[indx2].m_currentLimit)
662
row += get_limit_motor_info2(&limot, transA,transB,linVelA,linVelB,angVelA,angVelB, info, row, axis, 0, rotAllowed);
666
row += get_limit_motor_info2(&limot, transA,transB,linVelA,linVelB,angVelA,angVelB, info, row, axis, 0);
675
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)
677
btGeneric6DofConstraint * d6constraint = this;
678
int row = row_offset;
679
//solve angular limits
680
for (int i=0;i<3 ;i++ )
682
if(d6constraint->getRotationalLimitMotor(i)->needApplyTorques())
684
btVector3 axis = d6constraint->getAxis(i);
685
int flags = m_flags >> ((i + 3) * BT_6DOF_FLAGS_AXIS_SHIFT);
686
if(!(flags & BT_6DOF_FLAGS_CFM_NORM))
688
m_angularLimits[i].m_normalCFM = info->cfm[0];
690
if(!(flags & BT_6DOF_FLAGS_CFM_STOP))
692
m_angularLimits[i].m_stopCFM = info->cfm[0];
694
if(!(flags & BT_6DOF_FLAGS_ERP_STOP))
696
m_angularLimits[i].m_stopERP = info->erp;
698
row += get_limit_motor_info2(d6constraint->getRotationalLimitMotor(i),
699
transA,transB,linVelA,linVelB,angVelA,angVelB, info,row,axis,1);
709
void btGeneric6DofConstraint::updateRHS(btScalar timeStep)
716
void btGeneric6DofConstraint::setFrames(const btTransform& frameA, const btTransform& frameB)
721
calculateTransforms();
726
btVector3 btGeneric6DofConstraint::getAxis(int axis_index) const
728
return m_calculatedAxis[axis_index];
732
btScalar btGeneric6DofConstraint::getRelativePivotPosition(int axisIndex) const
734
return m_calculatedLinearDiff[axisIndex];
738
btScalar btGeneric6DofConstraint::getAngle(int axisIndex) const
740
return m_calculatedAxisAngleDiff[axisIndex];
745
void btGeneric6DofConstraint::calcAnchorPos(void)
747
btScalar imA = m_rbA.getInvMass();
748
btScalar imB = m_rbB.getInvMass();
750
if(imB == btScalar(0.0))
752
weight = btScalar(1.0);
756
weight = imA / (imA + imB);
758
const btVector3& pA = m_calculatedTransformA.getOrigin();
759
const btVector3& pB = m_calculatedTransformB.getOrigin();
760
m_AnchorPos = pA * weight + pB * (btScalar(1.0) - weight);
766
void btGeneric6DofConstraint::calculateLinearInfo()
768
m_calculatedLinearDiff = m_calculatedTransformB.getOrigin() - m_calculatedTransformA.getOrigin();
769
m_calculatedLinearDiff = m_calculatedTransformA.getBasis().inverse() * m_calculatedLinearDiff;
770
for(int i = 0; i < 3; i++)
772
m_linearLimits.m_currentLinearDiff[i] = m_calculatedLinearDiff[i];
773
m_linearLimits.testLimitValue(i, m_calculatedLinearDiff[i]);
779
int btGeneric6DofConstraint::get_limit_motor_info2(
780
btRotationalLimitMotor * limot,
781
const btTransform& transA,const btTransform& transB,const btVector3& linVelA,const btVector3& linVelB,const btVector3& angVelA,const btVector3& angVelB,
782
btConstraintInfo2 *info, int row, btVector3& ax1, int rotational,int rotAllowed)
784
int srow = row * info->rowskip;
785
int powered = limot->m_enableMotor;
786
int limit = limot->m_currentLimit;
787
if (powered || limit)
788
{ // if the joint is powered, or has joint limits, add in the extra row
789
btScalar *J1 = rotational ? info->m_J1angularAxis : info->m_J1linearAxis;
790
btScalar *J2 = rotational ? info->m_J2angularAxis : 0;
796
J2[srow+0] = -ax1[0];
797
J2[srow+1] = -ax1[1];
798
J2[srow+2] = -ax1[2];
802
if (m_useOffsetForConstraintFrame)
804
btVector3 tmpA, tmpB, relA, relB;
805
// get vector from bodyB to frameB in WCS
806
relB = m_calculatedTransformB.getOrigin() - transB.getOrigin();
807
// get its projection to constraint axis
808
btVector3 projB = ax1 * relB.dot(ax1);
809
// get vector directed from bodyB to constraint axis (and orthogonal to it)
810
btVector3 orthoB = relB - projB;
812
relA = m_calculatedTransformA.getOrigin() - transA.getOrigin();
813
btVector3 projA = ax1 * relA.dot(ax1);
814
btVector3 orthoA = relA - projA;
815
// get desired offset between frames A and B along constraint axis
816
btScalar desiredOffs = limot->m_currentPosition - limot->m_currentLimitError;
817
// desired vector from projection of center of bodyA to projection of center of bodyB to constraint axis
818
btVector3 totalDist = projA + ax1 * desiredOffs - projB;
819
// get offset vectors relA and relB
820
relA = orthoA + totalDist * m_factA;
821
relB = orthoB - totalDist * m_factB;
822
tmpA = relA.cross(ax1);
823
tmpB = relB.cross(ax1);
824
if(m_hasStaticBody && (!rotAllowed))
830
for (i=0; i<3; i++) info->m_J1angularAxis[srow+i] = tmpA[i];
831
for (i=0; i<3; i++) info->m_J2angularAxis[srow+i] = -tmpB[i];
834
btVector3 ltd; // Linear Torque Decoupling vector
835
btVector3 c = m_calculatedTransformB.getOrigin() - transA.getOrigin();
837
info->m_J1angularAxis[srow+0] = ltd[0];
838
info->m_J1angularAxis[srow+1] = ltd[1];
839
info->m_J1angularAxis[srow+2] = ltd[2];
841
c = m_calculatedTransformB.getOrigin() - transB.getOrigin();
843
info->m_J2angularAxis[srow+0] = ltd[0];
844
info->m_J2angularAxis[srow+1] = ltd[1];
845
info->m_J2angularAxis[srow+2] = ltd[2];
848
// if we're limited low and high simultaneously, the joint motor is
850
if (limit && (limot->m_loLimit == limot->m_hiLimit)) powered = 0;
851
info->m_constraintError[srow] = btScalar(0.f);
854
info->cfm[srow] = limot->m_normalCFM;
857
btScalar tag_vel = rotational ? limot->m_targetVelocity : -limot->m_targetVelocity;
859
btScalar mot_fact = getMotorFactor( limot->m_currentPosition,
863
info->fps * limot->m_stopERP);
864
info->m_constraintError[srow] += mot_fact * limot->m_targetVelocity;
865
info->m_lowerLimit[srow] = -limot->m_maxMotorForce;
866
info->m_upperLimit[srow] = limot->m_maxMotorForce;
871
btScalar k = info->fps * limot->m_stopERP;
874
info->m_constraintError[srow] += k * limot->m_currentLimitError;
878
info->m_constraintError[srow] += -k * limot->m_currentLimitError;
880
info->cfm[srow] = limot->m_stopCFM;
881
if (limot->m_loLimit == limot->m_hiLimit)
882
{ // limited low and high simultaneously
883
info->m_lowerLimit[srow] = -SIMD_INFINITY;
884
info->m_upperLimit[srow] = SIMD_INFINITY;
890
info->m_lowerLimit[srow] = 0;
891
info->m_upperLimit[srow] = SIMD_INFINITY;
895
info->m_lowerLimit[srow] = -SIMD_INFINITY;
896
info->m_upperLimit[srow] = 0;
899
if (limot->m_bounce > 0)
901
// calculate joint velocity
905
vel = angVelA.dot(ax1);
906
//make sure that if no body -> angVelB == zero vec
908
vel -= angVelB.dot(ax1);
912
vel = linVelA.dot(ax1);
913
//make sure that if no body -> angVelB == zero vec
915
vel -= linVelB.dot(ax1);
917
// only apply bounce if the velocity is incoming, and if the
918
// resulting c[] exceeds what we already have.
923
btScalar newc = -limot->m_bounce* vel;
924
if (newc > info->m_constraintError[srow])
925
info->m_constraintError[srow] = newc;
932
btScalar newc = -limot->m_bounce * vel;
933
if (newc < info->m_constraintError[srow])
934
info->m_constraintError[srow] = newc;
950
///override the default global value of a parameter (such as ERP or CFM), optionally provide the axis (0..5).
951
///If no axis is provided, it uses the default axis for this constraint.
952
void btGeneric6DofConstraint::setParam(int num, btScalar value, int axis)
954
if((axis >= 0) && (axis < 3))
958
case BT_CONSTRAINT_STOP_ERP :
959
m_linearLimits.m_stopERP[axis] = value;
960
m_flags |= BT_6DOF_FLAGS_ERP_STOP << (axis * BT_6DOF_FLAGS_AXIS_SHIFT);
962
case BT_CONSTRAINT_STOP_CFM :
963
m_linearLimits.m_stopCFM[axis] = value;
964
m_flags |= BT_6DOF_FLAGS_CFM_STOP << (axis * BT_6DOF_FLAGS_AXIS_SHIFT);
966
case BT_CONSTRAINT_CFM :
967
m_linearLimits.m_normalCFM[axis] = value;
968
m_flags |= BT_6DOF_FLAGS_CFM_NORM << (axis * BT_6DOF_FLAGS_AXIS_SHIFT);
971
btAssertConstrParams(0);
974
else if((axis >=3) && (axis < 6))
978
case BT_CONSTRAINT_STOP_ERP :
979
m_angularLimits[axis - 3].m_stopERP = value;
980
m_flags |= BT_6DOF_FLAGS_ERP_STOP << (axis * BT_6DOF_FLAGS_AXIS_SHIFT);
982
case BT_CONSTRAINT_STOP_CFM :
983
m_angularLimits[axis - 3].m_stopCFM = value;
984
m_flags |= BT_6DOF_FLAGS_CFM_STOP << (axis * BT_6DOF_FLAGS_AXIS_SHIFT);
986
case BT_CONSTRAINT_CFM :
987
m_angularLimits[axis - 3].m_normalCFM = value;
988
m_flags |= BT_6DOF_FLAGS_CFM_NORM << (axis * BT_6DOF_FLAGS_AXIS_SHIFT);
991
btAssertConstrParams(0);
996
btAssertConstrParams(0);
1000
///return the local value of parameter
1001
btScalar btGeneric6DofConstraint::getParam(int num, int axis) const
1003
btScalar retVal = 0;
1004
if((axis >= 0) && (axis < 3))
1008
case BT_CONSTRAINT_STOP_ERP :
1009
btAssertConstrParams(m_flags & (BT_6DOF_FLAGS_ERP_STOP << (axis * BT_6DOF_FLAGS_AXIS_SHIFT)));
1010
retVal = m_linearLimits.m_stopERP[axis];
1012
case BT_CONSTRAINT_STOP_CFM :
1013
btAssertConstrParams(m_flags & (BT_6DOF_FLAGS_CFM_STOP << (axis * BT_6DOF_FLAGS_AXIS_SHIFT)));
1014
retVal = m_linearLimits.m_stopCFM[axis];
1016
case BT_CONSTRAINT_CFM :
1017
btAssertConstrParams(m_flags & (BT_6DOF_FLAGS_CFM_NORM << (axis * BT_6DOF_FLAGS_AXIS_SHIFT)));
1018
retVal = m_linearLimits.m_normalCFM[axis];
1021
btAssertConstrParams(0);
1024
else if((axis >=3) && (axis < 6))
1028
case BT_CONSTRAINT_STOP_ERP :
1029
btAssertConstrParams(m_flags & (BT_6DOF_FLAGS_ERP_STOP << (axis * BT_6DOF_FLAGS_AXIS_SHIFT)));
1030
retVal = m_angularLimits[axis - 3].m_stopERP;
1032
case BT_CONSTRAINT_STOP_CFM :
1033
btAssertConstrParams(m_flags & (BT_6DOF_FLAGS_CFM_STOP << (axis * BT_6DOF_FLAGS_AXIS_SHIFT)));
1034
retVal = m_angularLimits[axis - 3].m_stopCFM;
1036
case BT_CONSTRAINT_CFM :
1037
btAssertConstrParams(m_flags & (BT_6DOF_FLAGS_CFM_NORM << (axis * BT_6DOF_FLAGS_AXIS_SHIFT)));
1038
retVal = m_angularLimits[axis - 3].m_normalCFM;
1041
btAssertConstrParams(0);
1046
btAssertConstrParams(0);
1053
void btGeneric6DofConstraint::setAxis(const btVector3& axis1,const btVector3& axis2)
1055
btVector3 zAxis = axis1.normalized();
1056
btVector3 yAxis = axis2.normalized();
1057
btVector3 xAxis = yAxis.cross(zAxis); // we want right coordinate system
1059
btTransform frameInW;
1060
frameInW.setIdentity();
1061
frameInW.getBasis().setValue( xAxis[0], yAxis[0], zAxis[0],
1062
xAxis[1], yAxis[1], zAxis[1],
1063
xAxis[2], yAxis[2], zAxis[2]);
1065
// now get constraint frame in local coordinate systems
1066
m_frameInA = m_rbA.getCenterOfMassTransform().inverse() * frameInW;
1067
m_frameInB = m_rbB.getCenterOfMassTransform().inverse() * frameInW;
1069
calculateTransforms();
b'\\ No newline at end of file'