2 Bullet Continuous Collision Detection and Physics Library
3 Copyright (c) 2003-2006 Erwin Coumans https://bulletphysics.org
5 This software is provided 'as-is', without any express or implied warranty.
6 In no event will the authors be held liable for any damages arising from the use of this software.
7 Permission is granted to anyone to use this software for any purpose,
8 including commercial applications, and to alter it and redistribute it freely,
9 subject to the following restrictions:
11 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
12 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13 3. This notice may not be removed or altered from any source distribution.
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"
28 #define D6_USE_OBSOLETE_METHOD false
29 #define D6_USE_FRAME_OFFSET true
31 btGeneric6DofConstraint::btGeneric6DofConstraint(btRigidBody& rbA, btRigidBody& rbB, const btTransform& frameInA, const btTransform& frameInB, bool useLinearReferenceFrameA)
32 : 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)
34 calculateTransforms();
37 btGeneric6DofConstraint::btGeneric6DofConstraint(btRigidBody& rbB, const btTransform& frameInB, bool useLinearReferenceFrameB)
38 : btTypedConstraint(D6_CONSTRAINT_TYPE, getFixedBody(), rbB),
40 m_useLinearReferenceFrameA(useLinearReferenceFrameB),
41 m_useOffsetForConstraintFrame(D6_USE_FRAME_OFFSET),
43 m_useSolveConstraintObsolete(false)
45 ///not providing rigidbody A means implicitly using worldspace for body A
46 m_frameInA = rbB.getCenterOfMassTransform() * m_frameInB;
47 calculateTransforms();
50 #define GENERIC_D6_DISABLE_WARMSTARTING 1
52 btScalar btGetMatrixElem(const btMatrix3x3& mat, int index);
53 btScalar btGetMatrixElem(const btMatrix3x3& mat, int index)
60 ///MatrixToEulerXYZ from http://www.geometrictools.com/LibFoundation/Mathematics/Wm4Matrix3.inl.html
61 bool matrixToEulerXYZ(const btMatrix3x3& mat, btVector3& xyz);
62 bool matrixToEulerXYZ(const btMatrix3x3& mat, btVector3& xyz)
64 // // rot = cy*cz -cy*sz sy
65 // // cz*sx*sy+cx*sz cx*cz-sx*sy*sz -cy*sx
66 // // -cx*cz*sy+sx*sz cz*sx+cx*sy*sz cx*cy
69 btScalar fi = btGetMatrixElem(mat, 2);
70 if (fi < btScalar(1.0f))
72 if (fi > btScalar(-1.0f))
74 xyz[0] = btAtan2(-btGetMatrixElem(mat, 5), btGetMatrixElem(mat, 8));
75 xyz[1] = btAsin(btGetMatrixElem(mat, 2));
76 xyz[2] = btAtan2(-btGetMatrixElem(mat, 1), btGetMatrixElem(mat, 0));
81 // WARNING. Not unique. XA - ZA = -atan2(r10,r11)
82 xyz[0] = -btAtan2(btGetMatrixElem(mat, 3), btGetMatrixElem(mat, 4));
83 xyz[1] = -SIMD_HALF_PI;
84 xyz[2] = btScalar(0.0);
90 // WARNING. Not unique. XAngle + ZAngle = atan2(r10,r11)
91 xyz[0] = btAtan2(btGetMatrixElem(mat, 3), btGetMatrixElem(mat, 4));
92 xyz[1] = SIMD_HALF_PI;
98 //////////////////////////// btRotationalLimitMotor ////////////////////////////////////
100 int btRotationalLimitMotor::testLimitValue(btScalar test_value)
102 if (m_loLimit > m_hiLimit)
104 m_currentLimit = 0; //Free from violation
107 if (test_value < m_loLimit)
109 m_currentLimit = 1; //low limit violation
110 m_currentLimitError = test_value - m_loLimit;
111 if (m_currentLimitError > SIMD_PI)
112 m_currentLimitError -= SIMD_2_PI;
113 else if (m_currentLimitError < -SIMD_PI)
114 m_currentLimitError += SIMD_2_PI;
117 else if (test_value > m_hiLimit)
119 m_currentLimit = 2; //High limit violation
120 m_currentLimitError = test_value - m_hiLimit;
121 if (m_currentLimitError > SIMD_PI)
122 m_currentLimitError -= SIMD_2_PI;
123 else if (m_currentLimitError < -SIMD_PI)
124 m_currentLimitError += SIMD_2_PI;
128 m_currentLimit = 0; //Free from violation
132 btScalar btRotationalLimitMotor::solveAngularLimits(
133 btScalar timeStep, btVector3& axis, btScalar jacDiagABInv,
134 btRigidBody* body0, btRigidBody* body1)
136 if (needApplyTorques() == false) return 0.0f;
138 btScalar target_velocity = m_targetVelocity;
139 btScalar maxMotorForce = m_maxMotorForce;
141 //current error correction
142 if (m_currentLimit != 0)
144 target_velocity = -m_stopERP * m_currentLimitError / (timeStep);
145 maxMotorForce = m_maxLimitForce;
148 maxMotorForce *= timeStep;
150 // current velocity difference
152 btVector3 angVelA = body0->getAngularVelocity();
153 btVector3 angVelB = body1->getAngularVelocity();
156 vel_diff = angVelA - angVelB;
158 btScalar rel_vel = axis.dot(vel_diff);
160 // correction velocity
161 btScalar motor_relvel = m_limitSoftness * (target_velocity - m_damping * rel_vel);
163 if (motor_relvel < SIMD_EPSILON && motor_relvel > -SIMD_EPSILON)
165 return 0.0f; //no need for applying force
168 // correction impulse
169 btScalar unclippedMotorImpulse = (1 + m_bounce) * motor_relvel * jacDiagABInv;
171 // clip correction impulse
172 btScalar clippedMotorImpulse;
174 ///@todo: should clip against accumulated impulse
175 if (unclippedMotorImpulse > 0.0f)
177 clippedMotorImpulse = unclippedMotorImpulse > maxMotorForce ? maxMotorForce : unclippedMotorImpulse;
181 clippedMotorImpulse = unclippedMotorImpulse < -maxMotorForce ? -maxMotorForce : unclippedMotorImpulse;
184 // sort with accumulated impulses
185 btScalar lo = btScalar(-BT_LARGE_FLOAT);
186 btScalar hi = btScalar(BT_LARGE_FLOAT);
188 btScalar oldaccumImpulse = m_accumulatedImpulse;
189 btScalar sum = oldaccumImpulse + clippedMotorImpulse;
190 m_accumulatedImpulse = sum > hi ? btScalar(0.) : sum < lo ? btScalar(0.) : sum;
192 clippedMotorImpulse = m_accumulatedImpulse - oldaccumImpulse;
194 btVector3 motorImp = clippedMotorImpulse * axis;
196 body0->applyTorqueImpulse(motorImp);
197 body1->applyTorqueImpulse(-motorImp);
199 return clippedMotorImpulse;
202 //////////////////////////// End btRotationalLimitMotor ////////////////////////////////////
204 //////////////////////////// btTranslationalLimitMotor ////////////////////////////////////
206 int btTranslationalLimitMotor::testLimitValue(int limitIndex, btScalar test_value)
208 btScalar loLimit = m_lowerLimit[limitIndex];
209 btScalar hiLimit = m_upperLimit[limitIndex];
210 if (loLimit > hiLimit)
212 m_currentLimit[limitIndex] = 0; //Free from violation
213 m_currentLimitError[limitIndex] = btScalar(0.f);
217 if (test_value < loLimit)
219 m_currentLimit[limitIndex] = 2; //low limit violation
220 m_currentLimitError[limitIndex] = test_value - loLimit;
223 else if (test_value > hiLimit)
225 m_currentLimit[limitIndex] = 1; //High limit violation
226 m_currentLimitError[limitIndex] = test_value - hiLimit;
230 m_currentLimit[limitIndex] = 0; //Free from violation
231 m_currentLimitError[limitIndex] = btScalar(0.f);
235 btScalar btTranslationalLimitMotor::solveLinearAxis(
237 btScalar jacDiagABInv,
238 btRigidBody& body1, const btVector3& pointInA,
239 btRigidBody& body2, const btVector3& pointInB,
241 const btVector3& axis_normal_on_a,
242 const btVector3& anchorPos)
244 ///find relative velocity
245 // btVector3 rel_pos1 = pointInA - body1.getCenterOfMassPosition();
246 // btVector3 rel_pos2 = pointInB - body2.getCenterOfMassPosition();
247 btVector3 rel_pos1 = anchorPos - body1.getCenterOfMassPosition();
248 btVector3 rel_pos2 = anchorPos - body2.getCenterOfMassPosition();
250 btVector3 vel1 = body1.getVelocityInLocalPoint(rel_pos1);
251 btVector3 vel2 = body2.getVelocityInLocalPoint(rel_pos2);
252 btVector3 vel = vel1 - vel2;
254 btScalar rel_vel = axis_normal_on_a.dot(vel);
256 /// apply displacement correction
258 //positional error (zeroth order error)
259 btScalar depth = -(pointInA - pointInB).dot(axis_normal_on_a);
260 btScalar lo = btScalar(-BT_LARGE_FLOAT);
261 btScalar hi = btScalar(BT_LARGE_FLOAT);
263 btScalar minLimit = m_lowerLimit[limit_index];
264 btScalar maxLimit = m_upperLimit[limit_index];
267 if (minLimit < maxLimit)
270 if (depth > maxLimit)
277 if (depth < minLimit)
290 btScalar normalImpulse = m_limitSoftness * (m_restitution * depth / timeStep - m_damping * rel_vel) * jacDiagABInv;
292 btScalar oldNormalImpulse = m_accumulatedImpulse[limit_index];
293 btScalar sum = oldNormalImpulse + normalImpulse;
294 m_accumulatedImpulse[limit_index] = sum > hi ? btScalar(0.) : sum < lo ? btScalar(0.) : sum;
295 normalImpulse = m_accumulatedImpulse[limit_index] - oldNormalImpulse;
297 btVector3 impulse_vector = axis_normal_on_a * normalImpulse;
298 body1.applyImpulse(impulse_vector, rel_pos1);
299 body2.applyImpulse(-impulse_vector, rel_pos2);
301 return normalImpulse;
304 //////////////////////////// btTranslationalLimitMotor ////////////////////////////////////
306 void btGeneric6DofConstraint::calculateAngleInfo()
308 btMatrix3x3 relative_frame = m_calculatedTransformA.getBasis().inverse() * m_calculatedTransformB.getBasis();
309 matrixToEulerXYZ(relative_frame, m_calculatedAxisAngleDiff);
310 // in euler angle mode we do not actually constrain the angular velocity
311 // along the axes axis[0] and axis[2] (although we do use axis[1]) :
313 // to get constrain w2-w1 along ...not
314 // ------ --------------------- ------
315 // d(angle[0])/dt = 0 ax[1] x ax[2] ax[0]
316 // d(angle[1])/dt = 0 ax[1]
317 // d(angle[2])/dt = 0 ax[0] x ax[1] ax[2]
319 // constraining w2-w1 along an axis 'a' means that a'*(w2-w1)=0.
320 // to prove the result for angle[0], write the expression for angle[0] from
321 // GetInfo1 then take the derivative. to prove this for angle[2] it is
322 // easier to take the euler rate expression for d(angle[2])/dt with respect
323 // to the components of w and set that to 0.
324 btVector3 axis0 = m_calculatedTransformB.getBasis().getColumn(0);
325 btVector3 axis2 = m_calculatedTransformA.getBasis().getColumn(2);
327 m_calculatedAxis[1] = axis2.cross(axis0);
328 m_calculatedAxis[0] = m_calculatedAxis[1].cross(axis2);
329 m_calculatedAxis[2] = axis0.cross(m_calculatedAxis[1]);
331 m_calculatedAxis[0].normalize();
332 m_calculatedAxis[1].normalize();
333 m_calculatedAxis[2].normalize();
336 void btGeneric6DofConstraint::calculateTransforms()
338 calculateTransforms(m_rbA.getCenterOfMassTransform(), m_rbB.getCenterOfMassTransform());
341 void btGeneric6DofConstraint::calculateTransforms(const btTransform& transA, const btTransform& transB)
343 m_calculatedTransformA = transA * m_frameInA;
344 m_calculatedTransformB = transB * m_frameInB;
345 calculateLinearInfo();
346 calculateAngleInfo();
347 if (m_useOffsetForConstraintFrame)
348 { // get weight factors depending on masses
349 btScalar miA = getRigidBodyA().getInvMass();
350 btScalar miB = getRigidBodyB().getInvMass();
351 m_hasStaticBody = (miA < SIMD_EPSILON) || (miB < SIMD_EPSILON);
352 btScalar miS = miA + miB;
353 if (miS > btScalar(0.f))
359 m_factA = btScalar(0.5f);
361 m_factB = btScalar(1.0f) - m_factA;
365 void btGeneric6DofConstraint::buildLinearJacobian(
366 btJacobianEntry& jacLinear, const btVector3& normalWorld,
367 const btVector3& pivotAInW, const btVector3& pivotBInW)
369 new (&jacLinear) btJacobianEntry(
370 m_rbA.getCenterOfMassTransform().getBasis().transpose(),
371 m_rbB.getCenterOfMassTransform().getBasis().transpose(),
372 pivotAInW - m_rbA.getCenterOfMassPosition(),
373 pivotBInW - m_rbB.getCenterOfMassPosition(),
375 m_rbA.getInvInertiaDiagLocal(),
377 m_rbB.getInvInertiaDiagLocal(),
381 void btGeneric6DofConstraint::buildAngularJacobian(
382 btJacobianEntry& jacAngular, const btVector3& jointAxisW)
384 new (&jacAngular) btJacobianEntry(jointAxisW,
385 m_rbA.getCenterOfMassTransform().getBasis().transpose(),
386 m_rbB.getCenterOfMassTransform().getBasis().transpose(),
387 m_rbA.getInvInertiaDiagLocal(),
388 m_rbB.getInvInertiaDiagLocal());
391 bool btGeneric6DofConstraint::testAngularLimitMotor(int axis_index)
393 btScalar angle = m_calculatedAxisAngleDiff[axis_index];
394 angle = btAdjustAngleToLimits(angle, m_angularLimits[axis_index].m_loLimit, m_angularLimits[axis_index].m_hiLimit);
395 m_angularLimits[axis_index].m_currentPosition = angle;
397 m_angularLimits[axis_index].testLimitValue(angle);
398 return m_angularLimits[axis_index].needApplyTorques();
401 void btGeneric6DofConstraint::buildJacobian()
404 if (m_useSolveConstraintObsolete)
406 // Clear accumulated impulses for the next simulation step
407 m_linearLimits.m_accumulatedImpulse.setValue(btScalar(0.), btScalar(0.), btScalar(0.));
409 for (i = 0; i < 3; i++)
411 m_angularLimits[i].m_accumulatedImpulse = btScalar(0.);
413 //calculates transform
414 calculateTransforms(m_rbA.getCenterOfMassTransform(), m_rbB.getCenterOfMassTransform());
416 // const btVector3& pivotAInW = m_calculatedTransformA.getOrigin();
417 // const btVector3& pivotBInW = m_calculatedTransformB.getOrigin();
419 btVector3 pivotAInW = m_AnchorPos;
420 btVector3 pivotBInW = m_AnchorPos;
423 // btVector3 rel_pos1 = pivotAInW - m_rbA.getCenterOfMassPosition();
424 // btVector3 rel_pos2 = pivotBInW - m_rbB.getCenterOfMassPosition();
426 btVector3 normalWorld;
428 for (i = 0; i < 3; i++)
430 if (m_linearLimits.isLimited(i))
432 if (m_useLinearReferenceFrameA)
433 normalWorld = m_calculatedTransformA.getBasis().getColumn(i);
435 normalWorld = m_calculatedTransformB.getBasis().getColumn(i);
438 m_jacLinear[i], normalWorld,
439 pivotAInW, pivotBInW);
444 for (i = 0; i < 3; i++)
446 //calculates error angle
447 if (testAngularLimitMotor(i))
449 normalWorld = this->getAxis(i);
450 // Create angular atom
451 buildAngularJacobian(m_jacAng[i], normalWorld);
458 void btGeneric6DofConstraint::getInfo1(btConstraintInfo1* info)
460 if (m_useSolveConstraintObsolete)
462 info->m_numConstraintRows = 0;
468 calculateTransforms(m_rbA.getCenterOfMassTransform(), m_rbB.getCenterOfMassTransform());
469 info->m_numConstraintRows = 0;
473 for (i = 0; i < 3; i++)
475 if (m_linearLimits.needApplyForce(i))
477 info->m_numConstraintRows++;
481 //test angular limits
482 for (i = 0; i < 3; i++)
484 if (testAngularLimitMotor(i))
486 info->m_numConstraintRows++;
493 void btGeneric6DofConstraint::getInfo1NonVirtual(btConstraintInfo1* info)
495 if (m_useSolveConstraintObsolete)
497 info->m_numConstraintRows = 0;
503 info->m_numConstraintRows = 6;
508 void btGeneric6DofConstraint::getInfo2(btConstraintInfo2* info)
510 btAssert(!m_useSolveConstraintObsolete);
512 const btTransform& transA = m_rbA.getCenterOfMassTransform();
513 const btTransform& transB = m_rbB.getCenterOfMassTransform();
514 const btVector3& linVelA = m_rbA.getLinearVelocity();
515 const btVector3& linVelB = m_rbB.getLinearVelocity();
516 const btVector3& angVelA = m_rbA.getAngularVelocity();
517 const btVector3& angVelB = m_rbB.getAngularVelocity();
519 if (m_useOffsetForConstraintFrame)
520 { // for stability better to solve angular limits first
521 int row = setAngularLimits(info, 0, transA, transB, linVelA, linVelB, angVelA, angVelB);
522 setLinearLimits(info, row, transA, transB, linVelA, linVelB, angVelA, angVelB);
525 { // leave old version for compatibility
526 int row = setLinearLimits(info, 0, transA, transB, linVelA, linVelB, angVelA, angVelB);
527 setAngularLimits(info, row, transA, transB, linVelA, linVelB, angVelA, angVelB);
531 void btGeneric6DofConstraint::getInfo2NonVirtual(btConstraintInfo2* info, const btTransform& transA, const btTransform& transB, const btVector3& linVelA, const btVector3& linVelB, const btVector3& angVelA, const btVector3& angVelB)
533 btAssert(!m_useSolveConstraintObsolete);
535 calculateTransforms(transA, transB);
538 for (i = 0; i < 3; i++)
540 testAngularLimitMotor(i);
543 if (m_useOffsetForConstraintFrame)
544 { // for stability better to solve angular limits first
545 int row = setAngularLimits(info, 0, transA, transB, linVelA, linVelB, angVelA, angVelB);
546 setLinearLimits(info, row, transA, transB, linVelA, linVelB, angVelA, angVelB);
549 { // leave old version for compatibility
550 int row = setLinearLimits(info, 0, transA, transB, linVelA, linVelB, angVelA, angVelB);
551 setAngularLimits(info, row, transA, transB, linVelA, linVelB, angVelA, angVelB);
555 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)
558 //solve linear limits
559 btRotationalLimitMotor limot;
560 for (int i = 0; i < 3; i++)
562 if (m_linearLimits.needApplyForce(i))
563 { // re-use rotational motor code
564 limot.m_bounce = btScalar(0.f);
565 limot.m_currentLimit = m_linearLimits.m_currentLimit[i];
566 limot.m_currentPosition = m_linearLimits.m_currentLinearDiff[i];
567 limot.m_currentLimitError = m_linearLimits.m_currentLimitError[i];
568 limot.m_damping = m_linearLimits.m_damping;
569 limot.m_enableMotor = m_linearLimits.m_enableMotor[i];
570 limot.m_hiLimit = m_linearLimits.m_upperLimit[i];
571 limot.m_limitSoftness = m_linearLimits.m_limitSoftness;
572 limot.m_loLimit = m_linearLimits.m_lowerLimit[i];
573 limot.m_maxLimitForce = btScalar(0.f);
574 limot.m_maxMotorForce = m_linearLimits.m_maxMotorForce[i];
575 limot.m_targetVelocity = m_linearLimits.m_targetVelocity[i];
576 btVector3 axis = m_calculatedTransformA.getBasis().getColumn(i);
577 int flags = m_flags >> (i * BT_6DOF_FLAGS_AXIS_SHIFT);
578 limot.m_normalCFM = (flags & BT_6DOF_FLAGS_CFM_NORM) ? m_linearLimits.m_normalCFM[i] : info->cfm[0];
579 limot.m_stopCFM = (flags & BT_6DOF_FLAGS_CFM_STOP) ? m_linearLimits.m_stopCFM[i] : info->cfm[0];
580 limot.m_stopERP = (flags & BT_6DOF_FLAGS_ERP_STOP) ? m_linearLimits.m_stopERP[i] : info->erp;
581 if (m_useOffsetForConstraintFrame)
583 int indx1 = (i + 1) % 3;
584 int indx2 = (i + 2) % 3;
585 int rotAllowed = 1; // rotations around orthos to current axis
586 if (m_angularLimits[indx1].m_currentLimit && m_angularLimits[indx2].m_currentLimit)
590 row += get_limit_motor_info2(&limot, transA, transB, linVelA, linVelB, angVelA, angVelB, info, row, axis, 0, rotAllowed);
594 row += get_limit_motor_info2(&limot, transA, transB, linVelA, linVelB, angVelA, angVelB, info, row, axis, 0);
601 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)
603 btGeneric6DofConstraint* d6constraint = this;
604 int row = row_offset;
605 //solve angular limits
606 for (int i = 0; i < 3; i++)
608 if (d6constraint->getRotationalLimitMotor(i)->needApplyTorques())
610 btVector3 axis = d6constraint->getAxis(i);
611 int flags = m_flags >> ((i + 3) * BT_6DOF_FLAGS_AXIS_SHIFT);
612 if (!(flags & BT_6DOF_FLAGS_CFM_NORM))
614 m_angularLimits[i].m_normalCFM = info->cfm[0];
616 if (!(flags & BT_6DOF_FLAGS_CFM_STOP))
618 m_angularLimits[i].m_stopCFM = info->cfm[0];
620 if (!(flags & BT_6DOF_FLAGS_ERP_STOP))
622 m_angularLimits[i].m_stopERP = info->erp;
624 row += get_limit_motor_info2(d6constraint->getRotationalLimitMotor(i),
625 transA, transB, linVelA, linVelB, angVelA, angVelB, info, row, axis, 1);
632 void btGeneric6DofConstraint::updateRHS(btScalar timeStep)
637 void btGeneric6DofConstraint::setFrames(const btTransform& frameA, const btTransform& frameB)
642 calculateTransforms();
645 btVector3 btGeneric6DofConstraint::getAxis(int axis_index) const
647 return m_calculatedAxis[axis_index];
650 btScalar btGeneric6DofConstraint::getRelativePivotPosition(int axisIndex) const
652 return m_calculatedLinearDiff[axisIndex];
655 btScalar btGeneric6DofConstraint::getAngle(int axisIndex) const
657 return m_calculatedAxisAngleDiff[axisIndex];
660 void btGeneric6DofConstraint::calcAnchorPos(void)
662 btScalar imA = m_rbA.getInvMass();
663 btScalar imB = m_rbB.getInvMass();
665 if (imB == btScalar(0.0))
667 weight = btScalar(1.0);
671 weight = imA / (imA + imB);
673 const btVector3& pA = m_calculatedTransformA.getOrigin();
674 const btVector3& pB = m_calculatedTransformB.getOrigin();
675 m_AnchorPos = pA * weight + pB * (btScalar(1.0) - weight);
679 void btGeneric6DofConstraint::calculateLinearInfo()
681 m_calculatedLinearDiff = m_calculatedTransformB.getOrigin() - m_calculatedTransformA.getOrigin();
682 m_calculatedLinearDiff = m_calculatedTransformA.getBasis().inverse() * m_calculatedLinearDiff;
683 for (int i = 0; i < 3; i++)
685 m_linearLimits.m_currentLinearDiff[i] = m_calculatedLinearDiff[i];
686 m_linearLimits.testLimitValue(i, m_calculatedLinearDiff[i]);
690 int btGeneric6DofConstraint::get_limit_motor_info2(
691 btRotationalLimitMotor* limot,
692 const btTransform& transA, const btTransform& transB, const btVector3& linVelA, const btVector3& linVelB, const btVector3& angVelA, const btVector3& angVelB,
693 btConstraintInfo2* info, int row, btVector3& ax1, int rotational, int rotAllowed)
695 int srow = row * info->rowskip;
696 bool powered = limot->m_enableMotor;
697 int limit = limot->m_currentLimit;
698 if (powered || limit)
699 { // if the joint is powered, or has joint limits, add in the extra row
700 btScalar* J1 = rotational ? info->m_J1angularAxis : info->m_J1linearAxis;
701 btScalar* J2 = rotational ? info->m_J2angularAxis : info->m_J2linearAxis;
702 J1[srow + 0] = ax1[0];
703 J1[srow + 1] = ax1[1];
704 J1[srow + 2] = ax1[2];
706 J2[srow + 0] = -ax1[0];
707 J2[srow + 1] = -ax1[1];
708 J2[srow + 2] = -ax1[2];
712 if (m_useOffsetForConstraintFrame)
714 btVector3 tmpA, tmpB, relA, relB;
715 // get vector from bodyB to frameB in WCS
716 relB = m_calculatedTransformB.getOrigin() - transB.getOrigin();
717 // get its projection to constraint axis
718 btVector3 projB = ax1 * relB.dot(ax1);
719 // get vector directed from bodyB to constraint axis (and orthogonal to it)
720 btVector3 orthoB = relB - projB;
722 relA = m_calculatedTransformA.getOrigin() - transA.getOrigin();
723 btVector3 projA = ax1 * relA.dot(ax1);
724 btVector3 orthoA = relA - projA;
725 // get desired offset between frames A and B along constraint axis
726 btScalar desiredOffs = limot->m_currentPosition - limot->m_currentLimitError;
727 // desired vector from projection of center of bodyA to projection of center of bodyB to constraint axis
728 btVector3 totalDist = projA + ax1 * desiredOffs - projB;
729 // get offset vectors relA and relB
730 relA = orthoA + totalDist * m_factA;
731 relB = orthoB - totalDist * m_factB;
732 tmpA = relA.cross(ax1);
733 tmpB = relB.cross(ax1);
734 if (m_hasStaticBody && (!rotAllowed))
740 for (i = 0; i < 3; i++) info->m_J1angularAxis[srow + i] = tmpA[i];
741 for (i = 0; i < 3; i++) info->m_J2angularAxis[srow + i] = -tmpB[i];
745 btVector3 ltd; // Linear Torque Decoupling vector
746 btVector3 c = m_calculatedTransformB.getOrigin() - transA.getOrigin();
748 info->m_J1angularAxis[srow + 0] = ltd[0];
749 info->m_J1angularAxis[srow + 1] = ltd[1];
750 info->m_J1angularAxis[srow + 2] = ltd[2];
752 c = m_calculatedTransformB.getOrigin() - transB.getOrigin();
754 info->m_J2angularAxis[srow + 0] = ltd[0];
755 info->m_J2angularAxis[srow + 1] = ltd[1];
756 info->m_J2angularAxis[srow + 2] = ltd[2];
759 // if we're limited low and high simultaneously, the joint motor is
761 if (limit && (limot->m_loLimit == limot->m_hiLimit)) powered = false;
762 info->m_constraintError[srow] = btScalar(0.f);
765 info->cfm[srow] = limot->m_normalCFM;
768 btScalar tag_vel = rotational ? limot->m_targetVelocity : -limot->m_targetVelocity;
770 btScalar mot_fact = getMotorFactor(limot->m_currentPosition,
774 info->fps * limot->m_stopERP);
775 info->m_constraintError[srow] += mot_fact * limot->m_targetVelocity;
776 info->m_lowerLimit[srow] = -limot->m_maxMotorForce / info->fps;
777 info->m_upperLimit[srow] = limot->m_maxMotorForce / info->fps;
782 btScalar k = info->fps * limot->m_stopERP;
785 info->m_constraintError[srow] += k * limot->m_currentLimitError;
789 info->m_constraintError[srow] += -k * limot->m_currentLimitError;
791 info->cfm[srow] = limot->m_stopCFM;
792 if (limot->m_loLimit == limot->m_hiLimit)
793 { // limited low and high simultaneously
794 info->m_lowerLimit[srow] = -SIMD_INFINITY;
795 info->m_upperLimit[srow] = SIMD_INFINITY;
801 info->m_lowerLimit[srow] = 0;
802 info->m_upperLimit[srow] = SIMD_INFINITY;
806 info->m_lowerLimit[srow] = -SIMD_INFINITY;
807 info->m_upperLimit[srow] = 0;
810 if (limot->m_bounce > 0)
812 // calculate joint velocity
816 vel = angVelA.dot(ax1);
817 //make sure that if no body -> angVelB == zero vec
819 vel -= angVelB.dot(ax1);
823 vel = linVelA.dot(ax1);
824 //make sure that if no body -> angVelB == zero vec
826 vel -= linVelB.dot(ax1);
828 // only apply bounce if the velocity is incoming, and if the
829 // resulting c[] exceeds what we already have.
834 btScalar newc = -limot->m_bounce * vel;
835 if (newc > info->m_constraintError[srow])
836 info->m_constraintError[srow] = newc;
843 btScalar newc = -limot->m_bounce * vel;
844 if (newc < info->m_constraintError[srow])
845 info->m_constraintError[srow] = newc;
857 ///override the default global value of a parameter (such as ERP or CFM), optionally provide the axis (0..5).
858 ///If no axis is provided, it uses the default axis for this constraint.
859 void btGeneric6DofConstraint::setParam(int num, btScalar value, int axis)
861 if ((axis >= 0) && (axis < 3))
865 case BT_CONSTRAINT_STOP_ERP:
866 m_linearLimits.m_stopERP[axis] = value;
867 m_flags |= BT_6DOF_FLAGS_ERP_STOP << (axis * BT_6DOF_FLAGS_AXIS_SHIFT);
869 case BT_CONSTRAINT_STOP_CFM:
870 m_linearLimits.m_stopCFM[axis] = value;
871 m_flags |= BT_6DOF_FLAGS_CFM_STOP << (axis * BT_6DOF_FLAGS_AXIS_SHIFT);
873 case BT_CONSTRAINT_CFM:
874 m_linearLimits.m_normalCFM[axis] = value;
875 m_flags |= BT_6DOF_FLAGS_CFM_NORM << (axis * BT_6DOF_FLAGS_AXIS_SHIFT);
878 btAssertConstrParams(0);
881 else if ((axis >= 3) && (axis < 6))
885 case BT_CONSTRAINT_STOP_ERP:
886 m_angularLimits[axis - 3].m_stopERP = value;
887 m_flags |= BT_6DOF_FLAGS_ERP_STOP << (axis * BT_6DOF_FLAGS_AXIS_SHIFT);
889 case BT_CONSTRAINT_STOP_CFM:
890 m_angularLimits[axis - 3].m_stopCFM = value;
891 m_flags |= BT_6DOF_FLAGS_CFM_STOP << (axis * BT_6DOF_FLAGS_AXIS_SHIFT);
893 case BT_CONSTRAINT_CFM:
894 m_angularLimits[axis - 3].m_normalCFM = value;
895 m_flags |= BT_6DOF_FLAGS_CFM_NORM << (axis * BT_6DOF_FLAGS_AXIS_SHIFT);
898 btAssertConstrParams(0);
903 btAssertConstrParams(0);
907 ///return the local value of parameter
908 btScalar btGeneric6DofConstraint::getParam(int num, int axis) const
911 if ((axis >= 0) && (axis < 3))
915 case BT_CONSTRAINT_STOP_ERP:
916 btAssertConstrParams(m_flags & (BT_6DOF_FLAGS_ERP_STOP << (axis * BT_6DOF_FLAGS_AXIS_SHIFT)));
917 retVal = m_linearLimits.m_stopERP[axis];
919 case BT_CONSTRAINT_STOP_CFM:
920 btAssertConstrParams(m_flags & (BT_6DOF_FLAGS_CFM_STOP << (axis * BT_6DOF_FLAGS_AXIS_SHIFT)));
921 retVal = m_linearLimits.m_stopCFM[axis];
923 case BT_CONSTRAINT_CFM:
924 btAssertConstrParams(m_flags & (BT_6DOF_FLAGS_CFM_NORM << (axis * BT_6DOF_FLAGS_AXIS_SHIFT)));
925 retVal = m_linearLimits.m_normalCFM[axis];
928 btAssertConstrParams(0);
931 else if ((axis >= 3) && (axis < 6))
935 case BT_CONSTRAINT_STOP_ERP:
936 btAssertConstrParams(m_flags & (BT_6DOF_FLAGS_ERP_STOP << (axis * BT_6DOF_FLAGS_AXIS_SHIFT)));
937 retVal = m_angularLimits[axis - 3].m_stopERP;
939 case BT_CONSTRAINT_STOP_CFM:
940 btAssertConstrParams(m_flags & (BT_6DOF_FLAGS_CFM_STOP << (axis * BT_6DOF_FLAGS_AXIS_SHIFT)));
941 retVal = m_angularLimits[axis - 3].m_stopCFM;
943 case BT_CONSTRAINT_CFM:
944 btAssertConstrParams(m_flags & (BT_6DOF_FLAGS_CFM_NORM << (axis * BT_6DOF_FLAGS_AXIS_SHIFT)));
945 retVal = m_angularLimits[axis - 3].m_normalCFM;
948 btAssertConstrParams(0);
953 btAssertConstrParams(0);
958 void btGeneric6DofConstraint::setAxis(const btVector3& axis1, const btVector3& axis2)
960 btVector3 zAxis = axis1.normalized();
961 btVector3 yAxis = axis2.normalized();
962 btVector3 xAxis = yAxis.cross(zAxis); // we want right coordinate system
964 btTransform frameInW;
965 frameInW.setIdentity();
966 frameInW.getBasis().setValue(xAxis[0], yAxis[0], zAxis[0],
967 xAxis[1], yAxis[1], zAxis[1],
968 xAxis[2], yAxis[2], zAxis[2]);
970 // now get constraint frame in local coordinate systems
971 m_frameInA = m_rbA.getCenterOfMassTransform().inverse() * frameInW;
972 m_frameInB = m_rbB.getCenterOfMassTransform().inverse() * frameInW;
974 calculateTransforms();