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 Added by Roman Ponomarev (rponom@gmail.com)
23 #include "btSliderConstraint.h"
24 #include "BulletDynamics/Dynamics/btRigidBody.h"
25 #include "LinearMath/btTransformUtil.h"
28 #define USE_OFFSET_FOR_CONSTANT_FRAME true
30 void btSliderConstraint::initParams()
32 m_lowerLinLimit = btScalar(1.0);
33 m_upperLinLimit = btScalar(-1.0);
34 m_lowerAngLimit = btScalar(0.);
35 m_upperAngLimit = btScalar(0.);
36 m_softnessDirLin = SLIDER_CONSTRAINT_DEF_SOFTNESS;
37 m_restitutionDirLin = SLIDER_CONSTRAINT_DEF_RESTITUTION;
38 m_dampingDirLin = btScalar(0.);
39 m_cfmDirLin = SLIDER_CONSTRAINT_DEF_CFM;
40 m_softnessDirAng = SLIDER_CONSTRAINT_DEF_SOFTNESS;
41 m_restitutionDirAng = SLIDER_CONSTRAINT_DEF_RESTITUTION;
42 m_dampingDirAng = btScalar(0.);
43 m_cfmDirAng = SLIDER_CONSTRAINT_DEF_CFM;
44 m_softnessOrthoLin = SLIDER_CONSTRAINT_DEF_SOFTNESS;
45 m_restitutionOrthoLin = SLIDER_CONSTRAINT_DEF_RESTITUTION;
46 m_dampingOrthoLin = SLIDER_CONSTRAINT_DEF_DAMPING;
47 m_cfmOrthoLin = SLIDER_CONSTRAINT_DEF_CFM;
48 m_softnessOrthoAng = SLIDER_CONSTRAINT_DEF_SOFTNESS;
49 m_restitutionOrthoAng = SLIDER_CONSTRAINT_DEF_RESTITUTION;
50 m_dampingOrthoAng = SLIDER_CONSTRAINT_DEF_DAMPING;
51 m_cfmOrthoAng = SLIDER_CONSTRAINT_DEF_CFM;
52 m_softnessLimLin = SLIDER_CONSTRAINT_DEF_SOFTNESS;
53 m_restitutionLimLin = SLIDER_CONSTRAINT_DEF_RESTITUTION;
54 m_dampingLimLin = SLIDER_CONSTRAINT_DEF_DAMPING;
55 m_cfmLimLin = SLIDER_CONSTRAINT_DEF_CFM;
56 m_softnessLimAng = SLIDER_CONSTRAINT_DEF_SOFTNESS;
57 m_restitutionLimAng = SLIDER_CONSTRAINT_DEF_RESTITUTION;
58 m_dampingLimAng = SLIDER_CONSTRAINT_DEF_DAMPING;
59 m_cfmLimAng = SLIDER_CONSTRAINT_DEF_CFM;
61 m_poweredLinMotor = false;
62 m_targetLinMotorVelocity = btScalar(0.);
63 m_maxLinMotorForce = btScalar(0.);
64 m_accumulatedLinMotorImpulse = btScalar(0.0);
66 m_poweredAngMotor = false;
67 m_targetAngMotorVelocity = btScalar(0.);
68 m_maxAngMotorForce = btScalar(0.);
69 m_accumulatedAngMotorImpulse = btScalar(0.0);
74 m_useOffsetForConstraintFrame = USE_OFFSET_FOR_CONSTANT_FRAME;
76 calculateTransforms(m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform());
83 btSliderConstraint::btSliderConstraint(btRigidBody& rbA, btRigidBody& rbB, const btTransform& frameInA, const btTransform& frameInB, bool useLinearReferenceFrameA)
84 : btTypedConstraint(SLIDER_CONSTRAINT_TYPE, rbA, rbB),
85 m_useSolveConstraintObsolete(false),
88 m_useLinearReferenceFrameA(useLinearReferenceFrameA)
95 btSliderConstraint::btSliderConstraint(btRigidBody& rbB, const btTransform& frameInB, bool useLinearReferenceFrameA)
96 : btTypedConstraint(SLIDER_CONSTRAINT_TYPE, getFixedBody(), rbB),
97 m_useSolveConstraintObsolete(false),
99 m_useLinearReferenceFrameA(useLinearReferenceFrameA)
101 ///not providing rigidbody A means implicitly using worldspace for body A
102 m_frameInA = rbB.getCenterOfMassTransform() * m_frameInB;
103 // m_frameInA.getOrigin() = m_rbA.getCenterOfMassTransform()(m_frameInA.getOrigin());
113 void btSliderConstraint::getInfo1(btConstraintInfo1* info)
115 if (m_useSolveConstraintObsolete)
117 info->m_numConstraintRows = 0;
122 info->m_numConstraintRows = 4; // Fixed 2 linear + 2 angular
125 calculateTransforms(m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform());
128 if(getSolveLinLimit() || getPoweredLinMotor())
130 info->m_numConstraintRows++; // limit 3rd linear as well
133 if(getSolveAngLimit() || getPoweredAngMotor())
135 info->m_numConstraintRows++; // limit 3rd angular as well
141 void btSliderConstraint::getInfo1NonVirtual(btConstraintInfo1* info)
144 info->m_numConstraintRows = 6; // Fixed 2 linear + 2 angular + 1 limit (even if not used)
148 void btSliderConstraint::getInfo2(btConstraintInfo2* info)
150 getInfo2NonVirtual(info,m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform(), m_rbA.getLinearVelocity(),m_rbB.getLinearVelocity(), m_rbA.getInvMass(),m_rbB.getInvMass());
159 void btSliderConstraint::calculateTransforms(const btTransform& transA,const btTransform& transB)
161 if(m_useLinearReferenceFrameA || (!m_useSolveConstraintObsolete))
163 m_calculatedTransformA = transA * m_frameInA;
164 m_calculatedTransformB = transB * m_frameInB;
168 m_calculatedTransformA = transB * m_frameInB;
169 m_calculatedTransformB = transA * m_frameInA;
171 m_realPivotAInW = m_calculatedTransformA.getOrigin();
172 m_realPivotBInW = m_calculatedTransformB.getOrigin();
173 m_sliderAxis = m_calculatedTransformA.getBasis().getColumn(0); // along X
174 if(m_useLinearReferenceFrameA || m_useSolveConstraintObsolete)
176 m_delta = m_realPivotBInW - m_realPivotAInW;
180 m_delta = m_realPivotAInW - m_realPivotBInW;
182 m_projPivotInW = m_realPivotAInW + m_sliderAxis.dot(m_delta) * m_sliderAxis;
183 btVector3 normalWorld;
186 for(i = 0; i < 3; i++)
188 normalWorld = m_calculatedTransformA.getBasis().getColumn(i);
189 m_depth[i] = m_delta.dot(normalWorld);
195 void btSliderConstraint::testLinLimits(void)
197 m_solveLinLim = false;
198 m_linPos = m_depth[0];
199 if(m_lowerLinLimit <= m_upperLinLimit)
201 if(m_depth[0] > m_upperLinLimit)
203 m_depth[0] -= m_upperLinLimit;
204 m_solveLinLim = true;
206 else if(m_depth[0] < m_lowerLinLimit)
208 m_depth[0] -= m_lowerLinLimit;
209 m_solveLinLim = true;
213 m_depth[0] = btScalar(0.);
218 m_depth[0] = btScalar(0.);
224 void btSliderConstraint::testAngLimits(void)
226 m_angDepth = btScalar(0.);
227 m_solveAngLim = false;
228 if(m_lowerAngLimit <= m_upperAngLimit)
230 const btVector3 axisA0 = m_calculatedTransformA.getBasis().getColumn(1);
231 const btVector3 axisA1 = m_calculatedTransformA.getBasis().getColumn(2);
232 const btVector3 axisB0 = m_calculatedTransformB.getBasis().getColumn(1);
233 // btScalar rot = btAtan2Fast(axisB0.dot(axisA1), axisB0.dot(axisA0));
234 btScalar rot = btAtan2(axisB0.dot(axisA1), axisB0.dot(axisA0));
235 rot = btAdjustAngleToLimits(rot, m_lowerAngLimit, m_upperAngLimit);
237 if(rot < m_lowerAngLimit)
239 m_angDepth = rot - m_lowerAngLimit;
240 m_solveAngLim = true;
242 else if(rot > m_upperAngLimit)
244 m_angDepth = rot - m_upperAngLimit;
245 m_solveAngLim = true;
250 btVector3 btSliderConstraint::getAncorInA(void)
253 ancorInA = m_realPivotAInW + (m_lowerLinLimit + m_upperLinLimit) * btScalar(0.5) * m_sliderAxis;
254 ancorInA = m_rbA.getCenterOfMassTransform().inverse() * ancorInA;
260 btVector3 btSliderConstraint::getAncorInB(void)
263 ancorInB = m_frameInB.getOrigin();
268 void btSliderConstraint::getInfo2NonVirtual(btConstraintInfo2* info, const btTransform& transA,const btTransform& transB, const btVector3& linVelA,const btVector3& linVelB, btScalar rbAinvMass,btScalar rbBinvMass )
270 const btTransform& trA = getCalculatedTransformA();
271 const btTransform& trB = getCalculatedTransformB();
273 btAssert(!m_useSolveConstraintObsolete);
274 int i, s = info->rowskip;
276 btScalar signFact = m_useLinearReferenceFrameA ? btScalar(1.0f) : btScalar(-1.0f);
278 // difference between frames in WCS
279 btVector3 ofs = trB.getOrigin() - trA.getOrigin();
280 // now get weight factors depending on masses
281 btScalar miA = rbAinvMass;
282 btScalar miB = rbBinvMass;
283 bool hasStaticBody = (miA < SIMD_EPSILON) || (miB < SIMD_EPSILON);
284 btScalar miS = miA + miB;
285 btScalar factA, factB;
286 if(miS > btScalar(0.f))
292 factA = btScalar(0.5f);
294 factB = btScalar(1.0f) - factA;
296 btVector3 ax1A = trA.getBasis().getColumn(0);
297 btVector3 ax1B = trB.getBasis().getColumn(0);
298 if(m_useOffsetForConstraintFrame)
300 // get the desired direction of slider axis
301 // as weighted sum of X-orthos of frameA and frameB in WCS
302 ax1 = ax1A * factA + ax1B * factB;
304 // construct two orthos to slider axis
305 btPlaneSpace1 (ax1, p, q);
308 { // old way - use frameA
309 ax1 = trA.getBasis().getColumn(0);
310 // get 2 orthos to slider axis (Y, Z)
311 p = trA.getBasis().getColumn(1);
312 q = trA.getBasis().getColumn(2);
314 // make rotations around these orthos equal
315 // the slider axis should be the only unconstrained
316 // rotational axis, the angular velocity of the two bodies perpendicular to
317 // the slider axis should be equal. thus the constraint equations are
320 // where p and q are unit vectors normal to the slider axis, and w1 and w2
321 // are the angular velocity vectors of the two bodies.
322 info->m_J1angularAxis[0] = p[0];
323 info->m_J1angularAxis[1] = p[1];
324 info->m_J1angularAxis[2] = p[2];
325 info->m_J1angularAxis[s+0] = q[0];
326 info->m_J1angularAxis[s+1] = q[1];
327 info->m_J1angularAxis[s+2] = q[2];
329 info->m_J2angularAxis[0] = -p[0];
330 info->m_J2angularAxis[1] = -p[1];
331 info->m_J2angularAxis[2] = -p[2];
332 info->m_J2angularAxis[s+0] = -q[0];
333 info->m_J2angularAxis[s+1] = -q[1];
334 info->m_J2angularAxis[s+2] = -q[2];
335 // compute the right hand side of the constraint equation. set relative
336 // body velocities along p and q to bring the slider back into alignment.
337 // if ax1A,ax1B are the unit length slider axes as computed from bodyA and
338 // bodyB, we need to rotate both bodies along the axis u = (ax1 x ax2).
339 // if "theta" is the angle between ax1 and ax2, we need an angular velocity
340 // along u to cover angle erp*theta in one step :
341 // |angular_velocity| = angle/time = erp*theta / stepsize
342 // = (erp*fps) * theta
343 // angular_velocity = |angular_velocity| * (ax1 x ax2) / |ax1 x ax2|
344 // = (erp*fps) * theta * (ax1 x ax2) / sin(theta)
345 // ...as ax1 and ax2 are unit length. if theta is smallish,
346 // theta ~= sin(theta), so
347 // angular_velocity = (erp*fps) * (ax1 x ax2)
348 // ax1 x ax2 is in the plane space of ax1, so we project the angular
349 // velocity to p and q to find the right hand side.
350 // btScalar k = info->fps * info->erp * getSoftnessOrthoAng();
351 btScalar currERP = (m_flags & BT_SLIDER_FLAGS_ERP_ORTANG) ? m_softnessOrthoAng : m_softnessOrthoAng * info->erp;
352 btScalar k = info->fps * currERP;
354 btVector3 u = ax1A.cross(ax1B);
355 info->m_constraintError[0] = k * u.dot(p);
356 info->m_constraintError[s] = k * u.dot(q);
357 if(m_flags & BT_SLIDER_FLAGS_CFM_ORTANG)
359 info->cfm[0] = m_cfmOrthoAng;
360 info->cfm[s] = m_cfmOrthoAng;
363 int nrow = 1; // last filled row
370 // we want: velA + wA x relA == velB + wB x relB ... but this would
371 // result in three equations, so we project along two orthos to the slider axis
373 btTransform bodyA_trans = transA;
374 btTransform bodyB_trans = transB;
379 btVector3 tmpA(0,0,0), tmpB(0,0,0), relA(0,0,0), relB(0,0,0), c(0,0,0);
380 if(m_useOffsetForConstraintFrame)
382 // get vector from bodyB to frameB in WCS
383 relB = trB.getOrigin() - bodyB_trans.getOrigin();
384 // get its projection to slider axis
385 btVector3 projB = ax1 * relB.dot(ax1);
386 // get vector directed from bodyB to slider axis (and orthogonal to it)
387 btVector3 orthoB = relB - projB;
389 relA = trA.getOrigin() - bodyA_trans.getOrigin();
390 btVector3 projA = ax1 * relA.dot(ax1);
391 btVector3 orthoA = relA - projA;
392 // get desired offset between frames A and B along slider axis
393 btScalar sliderOffs = m_linPos - m_depth[0];
394 // desired vector from projection of center of bodyA to projection of center of bodyB to slider axis
395 btVector3 totalDist = projA + ax1 * sliderOffs - projB;
396 // get offset vectors relA and relB
397 relA = orthoA + totalDist * factA;
398 relB = orthoB - totalDist * factB;
399 // now choose average ortho to slider axis
400 p = orthoB * factA + orthoA * factB;
401 btScalar len2 = p.length2();
402 if(len2 > SIMD_EPSILON)
408 p = trA.getBasis().getColumn(1);
410 // make one more ortho
413 tmpA = relA.cross(p);
414 tmpB = relB.cross(p);
415 for (i=0; i<3; i++) info->m_J1angularAxis[s2+i] = tmpA[i];
416 for (i=0; i<3; i++) info->m_J2angularAxis[s2+i] = -tmpB[i];
417 tmpA = relA.cross(q);
418 tmpB = relB.cross(q);
419 if(hasStaticBody && getSolveAngLimit())
420 { // to make constraint between static and dynamic objects more rigid
421 // remove wA (or wB) from equation if angular limit is hit
425 for (i=0; i<3; i++) info->m_J1angularAxis[s3+i] = tmpA[i];
426 for (i=0; i<3; i++) info->m_J2angularAxis[s3+i] = -tmpB[i];
427 for (i=0; i<3; i++) info->m_J1linearAxis[s2+i] = p[i];
428 for (i=0; i<3; i++) info->m_J1linearAxis[s3+i] = q[i];
431 { // old way - maybe incorrect if bodies are not on the slider axis
432 // see discussion "Bug in slider constraint" http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?f=9&t=4024&start=0
433 c = bodyB_trans.getOrigin() - bodyA_trans.getOrigin();
434 btVector3 tmp = c.cross(p);
435 for (i=0; i<3; i++) info->m_J1angularAxis[s2+i] = factA*tmp[i];
436 for (i=0; i<3; i++) info->m_J2angularAxis[s2+i] = factB*tmp[i];
438 for (i=0; i<3; i++) info->m_J1angularAxis[s3+i] = factA*tmp[i];
439 for (i=0; i<3; i++) info->m_J2angularAxis[s3+i] = factB*tmp[i];
441 for (i=0; i<3; i++) info->m_J1linearAxis[s2+i] = p[i];
442 for (i=0; i<3; i++) info->m_J1linearAxis[s3+i] = q[i];
444 // compute two elements of right hand side
446 // k = info->fps * info->erp * getSoftnessOrthoLin();
447 currERP = (m_flags & BT_SLIDER_FLAGS_ERP_ORTLIN) ? m_softnessOrthoLin : m_softnessOrthoLin * info->erp;
448 k = info->fps * currERP;
450 btScalar rhs = k * p.dot(ofs);
451 info->m_constraintError[s2] = rhs;
452 rhs = k * q.dot(ofs);
453 info->m_constraintError[s3] = rhs;
454 if(m_flags & BT_SLIDER_FLAGS_CFM_ORTLIN)
456 info->cfm[s2] = m_cfmOrthoLin;
457 info->cfm[s3] = m_cfmOrthoLin;
461 // check linear limits
462 limit_err = btScalar(0.0);
464 if(getSolveLinLimit())
466 limit_err = getLinDepth() * signFact;
467 limit = (limit_err > btScalar(0.0)) ? 2 : 1;
470 if(getPoweredLinMotor())
474 // if the slider has joint limits or motor, add in the extra row
475 if (limit || powered)
478 srow = nrow * info->rowskip;
479 info->m_J1linearAxis[srow+0] = ax1[0];
480 info->m_J1linearAxis[srow+1] = ax1[1];
481 info->m_J1linearAxis[srow+2] = ax1[2];
482 // linear torque decoupling step:
484 // we have to be careful that the linear constraint forces (+/- ax1) applied to the two bodies
485 // do not create a torque couple. in other words, the points that the
486 // constraint force is applied at must lie along the same ax1 axis.
487 // a torque couple will result in limited slider-jointed free
488 // bodies from gaining angular momentum.
489 if(m_useOffsetForConstraintFrame)
491 // this is needed only when bodyA and bodyB are both dynamic.
494 tmpA = relA.cross(ax1);
495 tmpB = relB.cross(ax1);
496 info->m_J1angularAxis[srow+0] = tmpA[0];
497 info->m_J1angularAxis[srow+1] = tmpA[1];
498 info->m_J1angularAxis[srow+2] = tmpA[2];
499 info->m_J2angularAxis[srow+0] = -tmpB[0];
500 info->m_J2angularAxis[srow+1] = -tmpB[1];
501 info->m_J2angularAxis[srow+2] = -tmpB[2];
505 { // The old way. May be incorrect if bodies are not on the slider axis
506 btVector3 ltd; // Linear Torque Decoupling vector (a torque)
508 info->m_J1angularAxis[srow+0] = factA*ltd[0];
509 info->m_J1angularAxis[srow+1] = factA*ltd[1];
510 info->m_J1angularAxis[srow+2] = factA*ltd[2];
511 info->m_J2angularAxis[srow+0] = factB*ltd[0];
512 info->m_J2angularAxis[srow+1] = factB*ltd[1];
513 info->m_J2angularAxis[srow+2] = factB*ltd[2];
516 btScalar lostop = getLowerLinLimit();
517 btScalar histop = getUpperLinLimit();
518 if(limit && (lostop == histop))
519 { // the joint motor is ineffective
522 info->m_constraintError[srow] = 0.;
523 info->m_lowerLimit[srow] = 0.;
524 info->m_upperLimit[srow] = 0.;
525 currERP = (m_flags & BT_SLIDER_FLAGS_ERP_LIMLIN) ? m_softnessLimLin : info->erp;
528 if(m_flags & BT_SLIDER_FLAGS_CFM_DIRLIN)
530 info->cfm[srow] = m_cfmDirLin;
532 btScalar tag_vel = getTargetLinMotorVelocity();
533 btScalar mot_fact = getMotorFactor(m_linPos, m_lowerLinLimit, m_upperLinLimit, tag_vel, info->fps * currERP);
534 info->m_constraintError[srow] -= signFact * mot_fact * getTargetLinMotorVelocity();
535 info->m_lowerLimit[srow] += -getMaxLinMotorForce() * info->fps;
536 info->m_upperLimit[srow] += getMaxLinMotorForce() * info->fps;
540 k = info->fps * currERP;
541 info->m_constraintError[srow] += k * limit_err;
542 if(m_flags & BT_SLIDER_FLAGS_CFM_LIMLIN)
544 info->cfm[srow] = m_cfmLimLin;
547 { // limited low and high simultaneously
548 info->m_lowerLimit[srow] = -SIMD_INFINITY;
549 info->m_upperLimit[srow] = SIMD_INFINITY;
553 info->m_lowerLimit[srow] = -SIMD_INFINITY;
554 info->m_upperLimit[srow] = 0;
558 info->m_lowerLimit[srow] = 0;
559 info->m_upperLimit[srow] = SIMD_INFINITY;
561 // bounce (we'll use slider parameter abs(1.0 - m_dampingLimLin) for that)
562 btScalar bounce = btFabs(btScalar(1.0) - getDampingLimLin());
563 if(bounce > btScalar(0.0))
565 btScalar vel = linVelA.dot(ax1);
566 vel -= linVelB.dot(ax1);
568 // only apply bounce if the velocity is incoming, and if the
569 // resulting c[] exceeds what we already have.
574 btScalar newc = -bounce * vel;
575 if (newc > info->m_constraintError[srow])
577 info->m_constraintError[srow] = newc;
582 { // high limit - all those computations are reversed
585 btScalar newc = -bounce * vel;
586 if(newc < info->m_constraintError[srow])
588 info->m_constraintError[srow] = newc;
593 info->m_constraintError[srow] *= getSoftnessLimLin();
596 // check angular limits
597 limit_err = btScalar(0.0);
599 if(getSolveAngLimit())
601 limit_err = getAngDepth();
602 limit = (limit_err > btScalar(0.0)) ? 1 : 2;
604 // if the slider has joint limits, add in the extra row
606 if(getPoweredAngMotor())
613 srow = nrow * info->rowskip;
614 info->m_J1angularAxis[srow+0] = ax1[0];
615 info->m_J1angularAxis[srow+1] = ax1[1];
616 info->m_J1angularAxis[srow+2] = ax1[2];
618 info->m_J2angularAxis[srow+0] = -ax1[0];
619 info->m_J2angularAxis[srow+1] = -ax1[1];
620 info->m_J2angularAxis[srow+2] = -ax1[2];
622 btScalar lostop = getLowerAngLimit();
623 btScalar histop = getUpperAngLimit();
624 if(limit && (lostop == histop))
625 { // the joint motor is ineffective
628 currERP = (m_flags & BT_SLIDER_FLAGS_ERP_LIMANG) ? m_softnessLimAng : info->erp;
631 if(m_flags & BT_SLIDER_FLAGS_CFM_DIRANG)
633 info->cfm[srow] = m_cfmDirAng;
635 btScalar mot_fact = getMotorFactor(m_angPos, m_lowerAngLimit, m_upperAngLimit, getTargetAngMotorVelocity(), info->fps * currERP);
636 info->m_constraintError[srow] = mot_fact * getTargetAngMotorVelocity();
637 info->m_lowerLimit[srow] = -getMaxAngMotorForce() * info->fps;
638 info->m_upperLimit[srow] = getMaxAngMotorForce() * info->fps;
642 k = info->fps * currERP;
643 info->m_constraintError[srow] += k * limit_err;
644 if(m_flags & BT_SLIDER_FLAGS_CFM_LIMANG)
646 info->cfm[srow] = m_cfmLimAng;
650 // limited low and high simultaneously
651 info->m_lowerLimit[srow] = -SIMD_INFINITY;
652 info->m_upperLimit[srow] = SIMD_INFINITY;
656 info->m_lowerLimit[srow] = 0;
657 info->m_upperLimit[srow] = SIMD_INFINITY;
661 info->m_lowerLimit[srow] = -SIMD_INFINITY;
662 info->m_upperLimit[srow] = 0;
664 // bounce (we'll use slider parameter abs(1.0 - m_dampingLimAng) for that)
665 btScalar bounce = btFabs(btScalar(1.0) - getDampingLimAng());
666 if(bounce > btScalar(0.0))
668 btScalar vel = m_rbA.getAngularVelocity().dot(ax1);
669 vel -= m_rbB.getAngularVelocity().dot(ax1);
670 // only apply bounce if the velocity is incoming, and if the
671 // resulting c[] exceeds what we already have.
676 btScalar newc = -bounce * vel;
677 if(newc > info->m_constraintError[srow])
679 info->m_constraintError[srow] = newc;
684 { // high limit - all those computations are reversed
687 btScalar newc = -bounce * vel;
688 if(newc < info->m_constraintError[srow])
690 info->m_constraintError[srow] = newc;
695 info->m_constraintError[srow] *= getSoftnessLimAng();
697 } // if angular limit or powered
701 ///override the default global value of a parameter (such as ERP or CFM), optionally provide the axis (0..5).
702 ///If no axis is provided, it uses the default axis for this constraint.
703 void btSliderConstraint::setParam(int num, btScalar value, int axis)
707 case BT_CONSTRAINT_STOP_ERP :
710 m_softnessLimLin = value;
711 m_flags |= BT_SLIDER_FLAGS_ERP_LIMLIN;
715 m_softnessOrthoLin = value;
716 m_flags |= BT_SLIDER_FLAGS_ERP_ORTLIN;
720 m_softnessLimAng = value;
721 m_flags |= BT_SLIDER_FLAGS_ERP_LIMANG;
725 m_softnessOrthoAng = value;
726 m_flags |= BT_SLIDER_FLAGS_ERP_ORTANG;
730 btAssertConstrParams(0);
733 case BT_CONSTRAINT_CFM :
737 m_flags |= BT_SLIDER_FLAGS_CFM_DIRLIN;
742 m_flags |= BT_SLIDER_FLAGS_CFM_DIRANG;
746 btAssertConstrParams(0);
749 case BT_CONSTRAINT_STOP_CFM :
753 m_flags |= BT_SLIDER_FLAGS_CFM_LIMLIN;
757 m_cfmOrthoLin = value;
758 m_flags |= BT_SLIDER_FLAGS_CFM_ORTLIN;
763 m_flags |= BT_SLIDER_FLAGS_CFM_LIMANG;
767 m_cfmOrthoAng = value;
768 m_flags |= BT_SLIDER_FLAGS_CFM_ORTANG;
772 btAssertConstrParams(0);
778 ///return the local value of parameter
779 btScalar btSliderConstraint::getParam(int num, int axis) const
781 btScalar retVal(SIMD_INFINITY);
784 case BT_CONSTRAINT_STOP_ERP :
787 btAssertConstrParams(m_flags & BT_SLIDER_FLAGS_ERP_LIMLIN);
788 retVal = m_softnessLimLin;
792 btAssertConstrParams(m_flags & BT_SLIDER_FLAGS_ERP_ORTLIN);
793 retVal = m_softnessOrthoLin;
797 btAssertConstrParams(m_flags & BT_SLIDER_FLAGS_ERP_LIMANG);
798 retVal = m_softnessLimAng;
802 btAssertConstrParams(m_flags & BT_SLIDER_FLAGS_ERP_ORTANG);
803 retVal = m_softnessOrthoAng;
807 btAssertConstrParams(0);
810 case BT_CONSTRAINT_CFM :
813 btAssertConstrParams(m_flags & BT_SLIDER_FLAGS_CFM_DIRLIN);
814 retVal = m_cfmDirLin;
818 btAssertConstrParams(m_flags & BT_SLIDER_FLAGS_CFM_DIRANG);
819 retVal = m_cfmDirAng;
823 btAssertConstrParams(0);
826 case BT_CONSTRAINT_STOP_CFM :
829 btAssertConstrParams(m_flags & BT_SLIDER_FLAGS_CFM_LIMLIN);
830 retVal = m_cfmLimLin;
834 btAssertConstrParams(m_flags & BT_SLIDER_FLAGS_CFM_ORTLIN);
835 retVal = m_cfmOrthoLin;
839 btAssertConstrParams(m_flags & BT_SLIDER_FLAGS_CFM_LIMANG);
840 retVal = m_cfmLimAng;
844 btAssertConstrParams(m_flags & BT_SLIDER_FLAGS_CFM_ORTANG);
845 retVal = m_cfmOrthoAng;
849 btAssertConstrParams(0);