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 Added by Roman Ponomarev (rponom@gmail.com)
21 #include "btSliderConstraint.h"
22 #include "BulletDynamics/Dynamics/btRigidBody.h"
23 #include "LinearMath/btTransformUtil.h"
26 #define USE_OFFSET_FOR_CONSTANT_FRAME true
28 void btSliderConstraint::initParams()
30 m_lowerLinLimit = btScalar(1.0);
31 m_upperLinLimit = btScalar(-1.0);
32 m_lowerAngLimit = btScalar(0.);
33 m_upperAngLimit = btScalar(0.);
34 m_softnessDirLin = SLIDER_CONSTRAINT_DEF_SOFTNESS;
35 m_restitutionDirLin = SLIDER_CONSTRAINT_DEF_RESTITUTION;
36 m_dampingDirLin = btScalar(0.);
37 m_cfmDirLin = SLIDER_CONSTRAINT_DEF_CFM;
38 m_softnessDirAng = SLIDER_CONSTRAINT_DEF_SOFTNESS;
39 m_restitutionDirAng = SLIDER_CONSTRAINT_DEF_RESTITUTION;
40 m_dampingDirAng = btScalar(0.);
41 m_cfmDirAng = SLIDER_CONSTRAINT_DEF_CFM;
42 m_softnessOrthoLin = SLIDER_CONSTRAINT_DEF_SOFTNESS;
43 m_restitutionOrthoLin = SLIDER_CONSTRAINT_DEF_RESTITUTION;
44 m_dampingOrthoLin = SLIDER_CONSTRAINT_DEF_DAMPING;
45 m_cfmOrthoLin = SLIDER_CONSTRAINT_DEF_CFM;
46 m_softnessOrthoAng = SLIDER_CONSTRAINT_DEF_SOFTNESS;
47 m_restitutionOrthoAng = SLIDER_CONSTRAINT_DEF_RESTITUTION;
48 m_dampingOrthoAng = SLIDER_CONSTRAINT_DEF_DAMPING;
49 m_cfmOrthoAng = SLIDER_CONSTRAINT_DEF_CFM;
50 m_softnessLimLin = SLIDER_CONSTRAINT_DEF_SOFTNESS;
51 m_restitutionLimLin = SLIDER_CONSTRAINT_DEF_RESTITUTION;
52 m_dampingLimLin = SLIDER_CONSTRAINT_DEF_DAMPING;
53 m_cfmLimLin = SLIDER_CONSTRAINT_DEF_CFM;
54 m_softnessLimAng = SLIDER_CONSTRAINT_DEF_SOFTNESS;
55 m_restitutionLimAng = SLIDER_CONSTRAINT_DEF_RESTITUTION;
56 m_dampingLimAng = SLIDER_CONSTRAINT_DEF_DAMPING;
57 m_cfmLimAng = SLIDER_CONSTRAINT_DEF_CFM;
59 m_poweredLinMotor = false;
60 m_targetLinMotorVelocity = btScalar(0.);
61 m_maxLinMotorForce = btScalar(0.);
62 m_accumulatedLinMotorImpulse = btScalar(0.0);
64 m_poweredAngMotor = false;
65 m_targetAngMotorVelocity = btScalar(0.);
66 m_maxAngMotorForce = btScalar(0.);
67 m_accumulatedAngMotorImpulse = btScalar(0.0);
72 m_useOffsetForConstraintFrame = USE_OFFSET_FOR_CONSTANT_FRAME;
74 calculateTransforms(m_rbA.getCenterOfMassTransform(), m_rbB.getCenterOfMassTransform());
77 btSliderConstraint::btSliderConstraint(btRigidBody& rbA, btRigidBody& rbB, const btTransform& frameInA, const btTransform& frameInB, bool useLinearReferenceFrameA)
78 : btTypedConstraint(SLIDER_CONSTRAINT_TYPE, rbA, rbB),
79 m_useSolveConstraintObsolete(false),
82 m_useLinearReferenceFrameA(useLinearReferenceFrameA)
87 btSliderConstraint::btSliderConstraint(btRigidBody& rbB, const btTransform& frameInB, bool useLinearReferenceFrameA)
88 : btTypedConstraint(SLIDER_CONSTRAINT_TYPE, getFixedBody(), rbB),
89 m_useSolveConstraintObsolete(false),
91 m_useLinearReferenceFrameA(useLinearReferenceFrameA)
93 ///not providing rigidbody A means implicitly using worldspace for body A
94 m_frameInA = rbB.getCenterOfMassTransform() * m_frameInB;
95 // m_frameInA.getOrigin() = m_rbA.getCenterOfMassTransform()(m_frameInA.getOrigin());
100 void btSliderConstraint::getInfo1(btConstraintInfo1* info)
102 if (m_useSolveConstraintObsolete)
104 info->m_numConstraintRows = 0;
109 info->m_numConstraintRows = 4; // Fixed 2 linear + 2 angular
112 calculateTransforms(m_rbA.getCenterOfMassTransform(), m_rbB.getCenterOfMassTransform());
115 if (getSolveLinLimit() || getPoweredLinMotor())
117 info->m_numConstraintRows++; // limit 3rd linear as well
120 if (getSolveAngLimit() || getPoweredAngMotor())
122 info->m_numConstraintRows++; // limit 3rd angular as well
128 void btSliderConstraint::getInfo1NonVirtual(btConstraintInfo1* info)
130 info->m_numConstraintRows = 6; // Fixed 2 linear + 2 angular + 1 limit (even if not used)
134 void btSliderConstraint::getInfo2(btConstraintInfo2* info)
136 getInfo2NonVirtual(info, m_rbA.getCenterOfMassTransform(), m_rbB.getCenterOfMassTransform(), m_rbA.getLinearVelocity(), m_rbB.getLinearVelocity(), m_rbA.getInvMass(), m_rbB.getInvMass());
139 void btSliderConstraint::calculateTransforms(const btTransform& transA, const btTransform& transB)
141 if (m_useLinearReferenceFrameA || (!m_useSolveConstraintObsolete))
143 m_calculatedTransformA = transA * m_frameInA;
144 m_calculatedTransformB = transB * m_frameInB;
148 m_calculatedTransformA = transB * m_frameInB;
149 m_calculatedTransformB = transA * m_frameInA;
151 m_realPivotAInW = m_calculatedTransformA.getOrigin();
152 m_realPivotBInW = m_calculatedTransformB.getOrigin();
153 m_sliderAxis = m_calculatedTransformA.getBasis().getColumn(0); // along X
154 if (m_useLinearReferenceFrameA || m_useSolveConstraintObsolete)
156 m_delta = m_realPivotBInW - m_realPivotAInW;
160 m_delta = m_realPivotAInW - m_realPivotBInW;
162 m_projPivotInW = m_realPivotAInW + m_sliderAxis.dot(m_delta) * m_sliderAxis;
163 btVector3 normalWorld;
166 for (i = 0; i < 3; i++)
168 normalWorld = m_calculatedTransformA.getBasis().getColumn(i);
169 m_depth[i] = m_delta.dot(normalWorld);
173 void btSliderConstraint::testLinLimits(void)
175 m_solveLinLim = false;
176 m_linPos = m_depth[0];
177 if (m_lowerLinLimit <= m_upperLinLimit)
179 if (m_depth[0] > m_upperLinLimit)
181 m_depth[0] -= m_upperLinLimit;
182 m_solveLinLim = true;
184 else if (m_depth[0] < m_lowerLinLimit)
186 m_depth[0] -= m_lowerLinLimit;
187 m_solveLinLim = true;
191 m_depth[0] = btScalar(0.);
196 m_depth[0] = btScalar(0.);
200 void btSliderConstraint::testAngLimits(void)
202 m_angDepth = btScalar(0.);
203 m_solveAngLim = false;
204 if (m_lowerAngLimit <= m_upperAngLimit)
206 const btVector3 axisA0 = m_calculatedTransformA.getBasis().getColumn(1);
207 const btVector3 axisA1 = m_calculatedTransformA.getBasis().getColumn(2);
208 const btVector3 axisB0 = m_calculatedTransformB.getBasis().getColumn(1);
209 // btScalar rot = btAtan2Fast(axisB0.dot(axisA1), axisB0.dot(axisA0));
210 btScalar rot = btAtan2(axisB0.dot(axisA1), axisB0.dot(axisA0));
211 rot = btAdjustAngleToLimits(rot, m_lowerAngLimit, m_upperAngLimit);
213 if (rot < m_lowerAngLimit)
215 m_angDepth = rot - m_lowerAngLimit;
216 m_solveAngLim = true;
218 else if (rot > m_upperAngLimit)
220 m_angDepth = rot - m_upperAngLimit;
221 m_solveAngLim = true;
226 btVector3 btSliderConstraint::getAncorInA(void)
229 ancorInA = m_realPivotAInW + (m_lowerLinLimit + m_upperLinLimit) * btScalar(0.5) * m_sliderAxis;
230 ancorInA = m_rbA.getCenterOfMassTransform().inverse() * ancorInA;
234 btVector3 btSliderConstraint::getAncorInB(void)
237 ancorInB = m_frameInB.getOrigin();
241 void btSliderConstraint::getInfo2NonVirtual(btConstraintInfo2* info, const btTransform& transA, const btTransform& transB, const btVector3& linVelA, const btVector3& linVelB, btScalar rbAinvMass, btScalar rbBinvMass)
243 const btTransform& trA = getCalculatedTransformA();
244 const btTransform& trB = getCalculatedTransformB();
246 btAssert(!m_useSolveConstraintObsolete);
247 int i, s = info->rowskip;
249 btScalar signFact = m_useLinearReferenceFrameA ? btScalar(1.0f) : btScalar(-1.0f);
251 // difference between frames in WCS
252 btVector3 ofs = trB.getOrigin() - trA.getOrigin();
253 // now get weight factors depending on masses
254 btScalar miA = rbAinvMass;
255 btScalar miB = rbBinvMass;
256 bool hasStaticBody = (miA < SIMD_EPSILON) || (miB < SIMD_EPSILON);
257 btScalar miS = miA + miB;
258 btScalar factA, factB;
259 if (miS > btScalar(0.f))
265 factA = btScalar(0.5f);
267 factB = btScalar(1.0f) - factA;
269 btVector3 ax1A = trA.getBasis().getColumn(0);
270 btVector3 ax1B = trB.getBasis().getColumn(0);
271 if (m_useOffsetForConstraintFrame)
273 // get the desired direction of slider axis
274 // as weighted sum of X-orthos of frameA and frameB in WCS
275 ax1 = ax1A * factA + ax1B * factB;
277 // construct two orthos to slider axis
278 btPlaneSpace1(ax1, p, q);
281 { // old way - use frameA
282 ax1 = trA.getBasis().getColumn(0);
283 // get 2 orthos to slider axis (Y, Z)
284 p = trA.getBasis().getColumn(1);
285 q = trA.getBasis().getColumn(2);
287 // make rotations around these orthos equal
288 // the slider axis should be the only unconstrained
289 // rotational axis, the angular velocity of the two bodies perpendicular to
290 // the slider axis should be equal. thus the constraint equations are
293 // where p and q are unit vectors normal to the slider axis, and w1 and w2
294 // are the angular velocity vectors of the two bodies.
295 info->m_J1angularAxis[0] = p[0];
296 info->m_J1angularAxis[1] = p[1];
297 info->m_J1angularAxis[2] = p[2];
298 info->m_J1angularAxis[s + 0] = q[0];
299 info->m_J1angularAxis[s + 1] = q[1];
300 info->m_J1angularAxis[s + 2] = q[2];
302 info->m_J2angularAxis[0] = -p[0];
303 info->m_J2angularAxis[1] = -p[1];
304 info->m_J2angularAxis[2] = -p[2];
305 info->m_J2angularAxis[s + 0] = -q[0];
306 info->m_J2angularAxis[s + 1] = -q[1];
307 info->m_J2angularAxis[s + 2] = -q[2];
308 // compute the right hand side of the constraint equation. set relative
309 // body velocities along p and q to bring the slider back into alignment.
310 // if ax1A,ax1B are the unit length slider axes as computed from bodyA and
311 // bodyB, we need to rotate both bodies along the axis u = (ax1 x ax2).
312 // if "theta" is the angle between ax1 and ax2, we need an angular velocity
313 // along u to cover angle erp*theta in one step :
314 // |angular_velocity| = angle/time = erp*theta / stepsize
315 // = (erp*fps) * theta
316 // angular_velocity = |angular_velocity| * (ax1 x ax2) / |ax1 x ax2|
317 // = (erp*fps) * theta * (ax1 x ax2) / sin(theta)
318 // ...as ax1 and ax2 are unit length. if theta is smallish,
319 // theta ~= sin(theta), so
320 // angular_velocity = (erp*fps) * (ax1 x ax2)
321 // ax1 x ax2 is in the plane space of ax1, so we project the angular
322 // velocity to p and q to find the right hand side.
323 // btScalar k = info->fps * info->erp * getSoftnessOrthoAng();
324 btScalar currERP = (m_flags & BT_SLIDER_FLAGS_ERP_ORTANG) ? m_softnessOrthoAng : m_softnessOrthoAng * info->erp;
325 btScalar k = info->fps * currERP;
327 btVector3 u = ax1A.cross(ax1B);
328 info->m_constraintError[0] = k * u.dot(p);
329 info->m_constraintError[s] = k * u.dot(q);
330 if (m_flags & BT_SLIDER_FLAGS_CFM_ORTANG)
332 info->cfm[0] = m_cfmOrthoAng;
333 info->cfm[s] = m_cfmOrthoAng;
336 int nrow = 1; // last filled row
342 // we want: velA + wA x relA == velB + wB x relB ... but this would
343 // result in three equations, so we project along two orthos to the slider axis
345 btTransform bodyA_trans = transA;
346 btTransform bodyB_trans = transB;
351 btVector3 tmpA(0, 0, 0), tmpB(0, 0, 0), relA(0, 0, 0), relB(0, 0, 0), c(0, 0, 0);
352 if (m_useOffsetForConstraintFrame)
354 // get vector from bodyB to frameB in WCS
355 relB = trB.getOrigin() - bodyB_trans.getOrigin();
356 // get its projection to slider axis
357 btVector3 projB = ax1 * relB.dot(ax1);
358 // get vector directed from bodyB to slider axis (and orthogonal to it)
359 btVector3 orthoB = relB - projB;
361 relA = trA.getOrigin() - bodyA_trans.getOrigin();
362 btVector3 projA = ax1 * relA.dot(ax1);
363 btVector3 orthoA = relA - projA;
364 // get desired offset between frames A and B along slider axis
365 btScalar sliderOffs = m_linPos - m_depth[0];
366 // desired vector from projection of center of bodyA to projection of center of bodyB to slider axis
367 btVector3 totalDist = projA + ax1 * sliderOffs - projB;
368 // get offset vectors relA and relB
369 relA = orthoA + totalDist * factA;
370 relB = orthoB - totalDist * factB;
371 // now choose average ortho to slider axis
372 p = orthoB * factA + orthoA * factB;
373 btScalar len2 = p.length2();
374 if (len2 > SIMD_EPSILON)
380 p = trA.getBasis().getColumn(1);
382 // make one more ortho
385 tmpA = relA.cross(p);
386 tmpB = relB.cross(p);
387 for (i = 0; i < 3; i++) info->m_J1angularAxis[s2 + i] = tmpA[i];
388 for (i = 0; i < 3; i++) info->m_J2angularAxis[s2 + i] = -tmpB[i];
389 tmpA = relA.cross(q);
390 tmpB = relB.cross(q);
391 if (hasStaticBody && getSolveAngLimit())
392 { // to make constraint between static and dynamic objects more rigid
393 // remove wA (or wB) from equation if angular limit is hit
397 for (i = 0; i < 3; i++) info->m_J1angularAxis[s3 + i] = tmpA[i];
398 for (i = 0; i < 3; i++) info->m_J2angularAxis[s3 + i] = -tmpB[i];
399 for (i = 0; i < 3; i++) info->m_J1linearAxis[s2 + i] = p[i];
400 for (i = 0; i < 3; i++) info->m_J1linearAxis[s3 + i] = q[i];
401 for (i = 0; i < 3; i++) info->m_J2linearAxis[s2 + i] = -p[i];
402 for (i = 0; i < 3; i++) info->m_J2linearAxis[s3 + i] = -q[i];
405 { // old way - maybe incorrect if bodies are not on the slider axis
406 // see discussion "Bug in slider constraint" http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?f=9&t=4024&start=0
407 c = bodyB_trans.getOrigin() - bodyA_trans.getOrigin();
408 btVector3 tmp = c.cross(p);
409 for (i = 0; i < 3; i++) info->m_J1angularAxis[s2 + i] = factA * tmp[i];
410 for (i = 0; i < 3; i++) info->m_J2angularAxis[s2 + i] = factB * tmp[i];
412 for (i = 0; i < 3; i++) info->m_J1angularAxis[s3 + i] = factA * tmp[i];
413 for (i = 0; i < 3; i++) info->m_J2angularAxis[s3 + i] = factB * tmp[i];
415 for (i = 0; i < 3; i++) info->m_J1linearAxis[s2 + i] = p[i];
416 for (i = 0; i < 3; i++) info->m_J1linearAxis[s3 + i] = q[i];
417 for (i = 0; i < 3; i++) info->m_J2linearAxis[s2 + i] = -p[i];
418 for (i = 0; i < 3; i++) info->m_J2linearAxis[s3 + i] = -q[i];
420 // compute two elements of right hand side
422 // k = info->fps * info->erp * getSoftnessOrthoLin();
423 currERP = (m_flags & BT_SLIDER_FLAGS_ERP_ORTLIN) ? m_softnessOrthoLin : m_softnessOrthoLin * info->erp;
424 k = info->fps * currERP;
426 btScalar rhs = k * p.dot(ofs);
427 info->m_constraintError[s2] = rhs;
428 rhs = k * q.dot(ofs);
429 info->m_constraintError[s3] = rhs;
430 if (m_flags & BT_SLIDER_FLAGS_CFM_ORTLIN)
432 info->cfm[s2] = m_cfmOrthoLin;
433 info->cfm[s3] = m_cfmOrthoLin;
436 // check linear limits
437 limit_err = btScalar(0.0);
439 if (getSolveLinLimit())
441 limit_err = getLinDepth() * signFact;
442 limit = (limit_err > btScalar(0.0)) ? 2 : 1;
444 bool powered = getPoweredLinMotor();
445 // if the slider has joint limits or motor, add in the extra row
446 if (limit || powered)
449 srow = nrow * info->rowskip;
450 info->m_J1linearAxis[srow + 0] = ax1[0];
451 info->m_J1linearAxis[srow + 1] = ax1[1];
452 info->m_J1linearAxis[srow + 2] = ax1[2];
453 info->m_J2linearAxis[srow + 0] = -ax1[0];
454 info->m_J2linearAxis[srow + 1] = -ax1[1];
455 info->m_J2linearAxis[srow + 2] = -ax1[2];
456 // linear torque decoupling step:
458 // we have to be careful that the linear constraint forces (+/- ax1) applied to the two bodies
459 // do not create a torque couple. in other words, the points that the
460 // constraint force is applied at must lie along the same ax1 axis.
461 // a torque couple will result in limited slider-jointed free
462 // bodies from gaining angular momentum.
463 if (m_useOffsetForConstraintFrame)
465 // this is needed only when bodyA and bodyB are both dynamic.
468 tmpA = relA.cross(ax1);
469 tmpB = relB.cross(ax1);
470 info->m_J1angularAxis[srow + 0] = tmpA[0];
471 info->m_J1angularAxis[srow + 1] = tmpA[1];
472 info->m_J1angularAxis[srow + 2] = tmpA[2];
473 info->m_J2angularAxis[srow + 0] = -tmpB[0];
474 info->m_J2angularAxis[srow + 1] = -tmpB[1];
475 info->m_J2angularAxis[srow + 2] = -tmpB[2];
479 { // The old way. May be incorrect if bodies are not on the slider axis
480 btVector3 ltd; // Linear Torque Decoupling vector (a torque)
482 info->m_J1angularAxis[srow + 0] = factA * ltd[0];
483 info->m_J1angularAxis[srow + 1] = factA * ltd[1];
484 info->m_J1angularAxis[srow + 2] = factA * ltd[2];
485 info->m_J2angularAxis[srow + 0] = factB * ltd[0];
486 info->m_J2angularAxis[srow + 1] = factB * ltd[1];
487 info->m_J2angularAxis[srow + 2] = factB * ltd[2];
490 btScalar lostop = getLowerLinLimit();
491 btScalar histop = getUpperLinLimit();
492 if (limit && (lostop == histop))
493 { // the joint motor is ineffective
496 info->m_constraintError[srow] = 0.;
497 info->m_lowerLimit[srow] = 0.;
498 info->m_upperLimit[srow] = 0.;
499 currERP = (m_flags & BT_SLIDER_FLAGS_ERP_LIMLIN) ? m_softnessLimLin : info->erp;
502 if (m_flags & BT_SLIDER_FLAGS_CFM_DIRLIN)
504 info->cfm[srow] = m_cfmDirLin;
506 btScalar tag_vel = getTargetLinMotorVelocity();
507 btScalar mot_fact = getMotorFactor(m_linPos, m_lowerLinLimit, m_upperLinLimit, tag_vel, info->fps * currERP);
508 info->m_constraintError[srow] -= signFact * mot_fact * getTargetLinMotorVelocity();
509 info->m_lowerLimit[srow] += -getMaxLinMotorForce() / info->fps;
510 info->m_upperLimit[srow] += getMaxLinMotorForce() / info->fps;
514 k = info->fps * currERP;
515 info->m_constraintError[srow] += k * limit_err;
516 if (m_flags & BT_SLIDER_FLAGS_CFM_LIMLIN)
518 info->cfm[srow] = m_cfmLimLin;
520 if (lostop == histop)
521 { // limited low and high simultaneously
522 info->m_lowerLimit[srow] = -SIMD_INFINITY;
523 info->m_upperLimit[srow] = SIMD_INFINITY;
527 info->m_lowerLimit[srow] = -SIMD_INFINITY;
528 info->m_upperLimit[srow] = 0;
532 info->m_lowerLimit[srow] = 0;
533 info->m_upperLimit[srow] = SIMD_INFINITY;
535 // bounce (we'll use slider parameter abs(1.0 - m_dampingLimLin) for that)
536 btScalar bounce = btFabs(btScalar(1.0) - getDampingLimLin());
537 if (bounce > btScalar(0.0))
539 btScalar vel = linVelA.dot(ax1);
540 vel -= linVelB.dot(ax1);
542 // only apply bounce if the velocity is incoming, and if the
543 // resulting c[] exceeds what we already have.
548 btScalar newc = -bounce * vel;
549 if (newc > info->m_constraintError[srow])
551 info->m_constraintError[srow] = newc;
556 { // high limit - all those computations are reversed
559 btScalar newc = -bounce * vel;
560 if (newc < info->m_constraintError[srow])
562 info->m_constraintError[srow] = newc;
567 info->m_constraintError[srow] *= getSoftnessLimLin();
570 // check angular limits
571 limit_err = btScalar(0.0);
573 if (getSolveAngLimit())
575 limit_err = getAngDepth();
576 limit = (limit_err > btScalar(0.0)) ? 1 : 2;
578 // if the slider has joint limits, add in the extra row
579 powered = getPoweredAngMotor();
580 if (limit || powered)
583 srow = nrow * info->rowskip;
584 info->m_J1angularAxis[srow + 0] = ax1[0];
585 info->m_J1angularAxis[srow + 1] = ax1[1];
586 info->m_J1angularAxis[srow + 2] = ax1[2];
588 info->m_J2angularAxis[srow + 0] = -ax1[0];
589 info->m_J2angularAxis[srow + 1] = -ax1[1];
590 info->m_J2angularAxis[srow + 2] = -ax1[2];
592 btScalar lostop = getLowerAngLimit();
593 btScalar histop = getUpperAngLimit();
594 if (limit && (lostop == histop))
595 { // the joint motor is ineffective
598 currERP = (m_flags & BT_SLIDER_FLAGS_ERP_LIMANG) ? m_softnessLimAng : info->erp;
601 if (m_flags & BT_SLIDER_FLAGS_CFM_DIRANG)
603 info->cfm[srow] = m_cfmDirAng;
605 btScalar mot_fact = getMotorFactor(m_angPos, m_lowerAngLimit, m_upperAngLimit, getTargetAngMotorVelocity(), info->fps * currERP);
606 info->m_constraintError[srow] = mot_fact * getTargetAngMotorVelocity();
607 info->m_lowerLimit[srow] = -getMaxAngMotorForce() / info->fps;
608 info->m_upperLimit[srow] = getMaxAngMotorForce() / info->fps;
612 k = info->fps * currERP;
613 info->m_constraintError[srow] += k * limit_err;
614 if (m_flags & BT_SLIDER_FLAGS_CFM_LIMANG)
616 info->cfm[srow] = m_cfmLimAng;
618 if (lostop == histop)
620 // limited low and high simultaneously
621 info->m_lowerLimit[srow] = -SIMD_INFINITY;
622 info->m_upperLimit[srow] = SIMD_INFINITY;
626 info->m_lowerLimit[srow] = 0;
627 info->m_upperLimit[srow] = SIMD_INFINITY;
631 info->m_lowerLimit[srow] = -SIMD_INFINITY;
632 info->m_upperLimit[srow] = 0;
634 // bounce (we'll use slider parameter abs(1.0 - m_dampingLimAng) for that)
635 btScalar bounce = btFabs(btScalar(1.0) - getDampingLimAng());
636 if (bounce > btScalar(0.0))
638 btScalar vel = m_rbA.getAngularVelocity().dot(ax1);
639 vel -= m_rbB.getAngularVelocity().dot(ax1);
640 // only apply bounce if the velocity is incoming, and if the
641 // resulting c[] exceeds what we already have.
646 btScalar newc = -bounce * vel;
647 if (newc > info->m_constraintError[srow])
649 info->m_constraintError[srow] = newc;
654 { // high limit - all those computations are reversed
657 btScalar newc = -bounce * vel;
658 if (newc < info->m_constraintError[srow])
660 info->m_constraintError[srow] = newc;
665 info->m_constraintError[srow] *= getSoftnessLimAng();
667 } // if angular limit or powered
670 ///override the default global value of a parameter (such as ERP or CFM), optionally provide the axis (0..5).
671 ///If no axis is provided, it uses the default axis for this constraint.
672 void btSliderConstraint::setParam(int num, btScalar value, int axis)
676 case BT_CONSTRAINT_STOP_ERP:
679 m_softnessLimLin = value;
680 m_flags |= BT_SLIDER_FLAGS_ERP_LIMLIN;
684 m_softnessOrthoLin = value;
685 m_flags |= BT_SLIDER_FLAGS_ERP_ORTLIN;
689 m_softnessLimAng = value;
690 m_flags |= BT_SLIDER_FLAGS_ERP_LIMANG;
694 m_softnessOrthoAng = value;
695 m_flags |= BT_SLIDER_FLAGS_ERP_ORTANG;
699 btAssertConstrParams(0);
702 case BT_CONSTRAINT_CFM:
706 m_flags |= BT_SLIDER_FLAGS_CFM_DIRLIN;
711 m_flags |= BT_SLIDER_FLAGS_CFM_DIRANG;
715 btAssertConstrParams(0);
718 case BT_CONSTRAINT_STOP_CFM:
722 m_flags |= BT_SLIDER_FLAGS_CFM_LIMLIN;
726 m_cfmOrthoLin = value;
727 m_flags |= BT_SLIDER_FLAGS_CFM_ORTLIN;
732 m_flags |= BT_SLIDER_FLAGS_CFM_LIMANG;
736 m_cfmOrthoAng = value;
737 m_flags |= BT_SLIDER_FLAGS_CFM_ORTANG;
741 btAssertConstrParams(0);
747 ///return the local value of parameter
748 btScalar btSliderConstraint::getParam(int num, int axis) const
750 btScalar retVal(SIMD_INFINITY);
753 case BT_CONSTRAINT_STOP_ERP:
756 btAssertConstrParams(m_flags & BT_SLIDER_FLAGS_ERP_LIMLIN);
757 retVal = m_softnessLimLin;
761 btAssertConstrParams(m_flags & BT_SLIDER_FLAGS_ERP_ORTLIN);
762 retVal = m_softnessOrthoLin;
766 btAssertConstrParams(m_flags & BT_SLIDER_FLAGS_ERP_LIMANG);
767 retVal = m_softnessLimAng;
771 btAssertConstrParams(m_flags & BT_SLIDER_FLAGS_ERP_ORTANG);
772 retVal = m_softnessOrthoAng;
776 btAssertConstrParams(0);
779 case BT_CONSTRAINT_CFM:
782 btAssertConstrParams(m_flags & BT_SLIDER_FLAGS_CFM_DIRLIN);
783 retVal = m_cfmDirLin;
787 btAssertConstrParams(m_flags & BT_SLIDER_FLAGS_CFM_DIRANG);
788 retVal = m_cfmDirAng;
792 btAssertConstrParams(0);
795 case BT_CONSTRAINT_STOP_CFM:
798 btAssertConstrParams(m_flags & BT_SLIDER_FLAGS_CFM_LIMLIN);
799 retVal = m_cfmLimLin;
803 btAssertConstrParams(m_flags & BT_SLIDER_FLAGS_CFM_ORTLIN);
804 retVal = m_cfmOrthoLin;
808 btAssertConstrParams(m_flags & BT_SLIDER_FLAGS_CFM_LIMANG);
809 retVal = m_cfmLimAng;
813 btAssertConstrParams(m_flags & BT_SLIDER_FLAGS_CFM_ORTANG);
814 retVal = m_cfmOrthoAng;
818 btAssertConstrParams(0);