1/* 2Bullet Continuous Collision Detection and Physics Library 3Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 4 5This software is provided 'as-is', without any express or implied warranty. 6In no event will the authors be held liable for any damages arising from the use of this software. 7Permission is granted to anyone to use this software for any purpose, 8including commercial applications, and to alter it and redistribute it freely, 9subject to the following restrictions: 10 111. 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. 122. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 133. This notice may not be removed or altered from any source distribution. 14*/ 15 16/* 17Added by Roman Ponomarev (rponom@gmail.com) 18April 04, 2008 19*/ 20 21 22 23#include "btSliderConstraint.h" 24#include "BulletDynamics/Dynamics/btRigidBody.h" 25#include "LinearMath/btTransformUtil.h" 26#include <new> 27 28#define USE_OFFSET_FOR_CONSTANT_FRAME true 29 30void btSliderConstraint::initParams() 31{ 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; 60 61 m_poweredLinMotor = false; 62 m_targetLinMotorVelocity = btScalar(0.); 63 m_maxLinMotorForce = btScalar(0.); 64 m_accumulatedLinMotorImpulse = btScalar(0.0); 65 66 m_poweredAngMotor = false; 67 m_targetAngMotorVelocity = btScalar(0.); 68 m_maxAngMotorForce = btScalar(0.); 69 m_accumulatedAngMotorImpulse = btScalar(0.0); 70 71 m_flags = 0; 72 m_flags = 0; 73 74 m_useOffsetForConstraintFrame = USE_OFFSET_FOR_CONSTANT_FRAME; 75 76 calculateTransforms(m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform()); 77} 78 79 80 81 82 83btSliderConstraint::btSliderConstraint(btRigidBody& rbA, btRigidBody& rbB, const btTransform& frameInA, const btTransform& frameInB, bool useLinearReferenceFrameA) 84 : btTypedConstraint(SLIDER_CONSTRAINT_TYPE, rbA, rbB), 85 m_useSolveConstraintObsolete(false), 86 m_frameInA(frameInA), 87 m_frameInB(frameInB), 88 m_useLinearReferenceFrameA(useLinearReferenceFrameA) 89{ 90 initParams(); 91} 92 93 94 95btSliderConstraint::btSliderConstraint(btRigidBody& rbB, const btTransform& frameInB, bool useLinearReferenceFrameA) 96 : btTypedConstraint(SLIDER_CONSTRAINT_TYPE, getFixedBody(), rbB), 97 m_useSolveConstraintObsolete(false), 98 m_frameInB(frameInB), 99 m_useLinearReferenceFrameA(useLinearReferenceFrameA) 100{ 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()); 104 105 initParams(); 106} 107 108 109 110 111 112 113void btSliderConstraint::getInfo1(btConstraintInfo1* info) 114{ 115 if (m_useSolveConstraintObsolete) 116 { 117 info->m_numConstraintRows = 0; 118 info->nub = 0; 119 } 120 else 121 { 122 info->m_numConstraintRows = 4; // Fixed 2 linear + 2 angular 123 info->nub = 2; 124 //prepare constraint 125 calculateTransforms(m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform()); 126 testAngLimits(); 127 testLinLimits(); 128 if(getSolveLinLimit() || getPoweredLinMotor()) 129 { 130 info->m_numConstraintRows++; // limit 3rd linear as well 131 info->nub--; 132 } 133 if(getSolveAngLimit() || getPoweredAngMotor()) 134 { 135 info->m_numConstraintRows++; // limit 3rd angular as well 136 info->nub--; 137 } 138 } 139} 140 141void btSliderConstraint::getInfo1NonVirtual(btConstraintInfo1* info) 142{ 143 144 info->m_numConstraintRows = 6; // Fixed 2 linear + 2 angular + 1 limit (even if not used) 145 info->nub = 0; 146} 147 148void btSliderConstraint::getInfo2(btConstraintInfo2* info) 149{ 150 getInfo2NonVirtual(info,m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform(), m_rbA.getLinearVelocity(),m_rbB.getLinearVelocity(), m_rbA.getInvMass(),m_rbB.getInvMass()); 151} 152 153 154 155 156 157 158 159void btSliderConstraint::calculateTransforms(const btTransform& transA,const btTransform& transB) 160{ 161 if(m_useLinearReferenceFrameA || (!m_useSolveConstraintObsolete)) 162 { 163 m_calculatedTransformA = transA * m_frameInA; 164 m_calculatedTransformB = transB * m_frameInB; 165 } 166 else 167 { 168 m_calculatedTransformA = transB * m_frameInB; 169 m_calculatedTransformB = transA * m_frameInA; 170 } 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) 175 { 176 m_delta = m_realPivotBInW - m_realPivotAInW; 177 } 178 else 179 { 180 m_delta = m_realPivotAInW - m_realPivotBInW; 181 } 182 m_projPivotInW = m_realPivotAInW + m_sliderAxis.dot(m_delta) * m_sliderAxis; 183 btVector3 normalWorld; 184 int i; 185 //linear part 186 for(i = 0; i < 3; i++) 187 { 188 normalWorld = m_calculatedTransformA.getBasis().getColumn(i); 189 m_depth[i] = m_delta.dot(normalWorld); 190 } 191} 192 193 194 195void btSliderConstraint::testLinLimits(void) 196{ 197 m_solveLinLim = false; 198 m_linPos = m_depth[0]; 199 if(m_lowerLinLimit <= m_upperLinLimit) 200 { 201 if(m_depth[0] > m_upperLinLimit) 202 { 203 m_depth[0] -= m_upperLinLimit; 204 m_solveLinLim = true; 205 } 206 else if(m_depth[0] < m_lowerLinLimit) 207 { 208 m_depth[0] -= m_lowerLinLimit; 209 m_solveLinLim = true; 210 } 211 else 212 { 213 m_depth[0] = btScalar(0.); 214 } 215 } 216 else 217 { 218 m_depth[0] = btScalar(0.); 219 } 220} 221 222 223 224void btSliderConstraint::testAngLimits(void) 225{ 226 m_angDepth = btScalar(0.); 227 m_solveAngLim = false; 228 if(m_lowerAngLimit <= m_upperAngLimit) 229 { 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); 236 m_angPos = rot; 237 if(rot < m_lowerAngLimit) 238 { 239 m_angDepth = rot - m_lowerAngLimit; 240 m_solveAngLim = true; 241 } 242 else if(rot > m_upperAngLimit) 243 { 244 m_angDepth = rot - m_upperAngLimit; 245 m_solveAngLim = true; 246 } 247 } 248} 249 250btVector3 btSliderConstraint::getAncorInA(void) 251{ 252 btVector3 ancorInA; 253 ancorInA = m_realPivotAInW + (m_lowerLinLimit + m_upperLinLimit) * btScalar(0.5) * m_sliderAxis; 254 ancorInA = m_rbA.getCenterOfMassTransform().inverse() * ancorInA; 255 return ancorInA; 256} 257 258 259 260btVector3 btSliderConstraint::getAncorInB(void) 261{ 262 btVector3 ancorInB; 263 ancorInB = m_frameInB.getOrigin(); 264 return ancorInB; 265} 266 267 268void btSliderConstraint::getInfo2NonVirtual(btConstraintInfo2* info, const btTransform& transA,const btTransform& transB, const btVector3& linVelA,const btVector3& linVelB, btScalar rbAinvMass,btScalar rbBinvMass ) 269{ 270 const btTransform& trA = getCalculatedTransformA(); 271 const btTransform& trB = getCalculatedTransformB(); 272 273 btAssert(!m_useSolveConstraintObsolete); 274 int i, s = info->rowskip; 275 276 btScalar signFact = m_useLinearReferenceFrameA ? btScalar(1.0f) : btScalar(-1.0f); 277 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)) 287 { 288 factA = miB / miS; 289 } 290 else 291 { 292 factA = btScalar(0.5f); 293 } 294 factB = btScalar(1.0f) - factA; 295 btVector3 ax1, p, q; 296 btVector3 ax1A = trA.getBasis().getColumn(0); 297 btVector3 ax1B = trB.getBasis().getColumn(0); 298 if(m_useOffsetForConstraintFrame) 299 { 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; 303 ax1.normalize(); 304 // construct two orthos to slider axis 305 btPlaneSpace1 (ax1, p, q); 306 } 307 else 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); 313 } 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 318 // p*w1 - p*w2 = 0 319 // q*w1 - q*w2 = 0 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]; 328 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; 353 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) 358 { 359 info->cfm[0] = m_cfmOrthoAng; 360 info->cfm[s] = m_cfmOrthoAng; 361 } 362 363 int nrow = 1; // last filled row 364 int srow; 365 btScalar limit_err; 366 int limit; 367 int powered; 368 369 // next two rows. 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 372 373 btTransform bodyA_trans = transA; 374 btTransform bodyB_trans = transB; 375 nrow++; 376 int s2 = nrow * s; 377 nrow++; 378 int s3 = nrow * s; 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) 381 { 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; 388 // same for bodyA 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) 403 { 404 p /= btSqrt(len2); 405 } 406 else 407 { 408 p = trA.getBasis().getColumn(1); 409 } 410 // make one more ortho 411 q = ax1.cross(p); 412 // fill two rows 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 422 tmpB *= factB; 423 tmpA *= factA; 424 } 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]; 429 for (i=0; i<3; i++) info->m_J2linearAxis[s2+i] = -p[i]; 430 for (i=0; i<3; i++) info->m_J2linearAxis[s3+i] = -q[i]; 431 } 432 else 433 { // old way - maybe incorrect if bodies are not on the slider axis 434 // see discussion "Bug in slider constraint" http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?f=9&t=4024&start=0 435 c = bodyB_trans.getOrigin() - bodyA_trans.getOrigin(); 436 btVector3 tmp = c.cross(p); 437 for (i=0; i<3; i++) info->m_J1angularAxis[s2+i] = factA*tmp[i]; 438 for (i=0; i<3; i++) info->m_J2angularAxis[s2+i] = factB*tmp[i]; 439 tmp = c.cross(q); 440 for (i=0; i<3; i++) info->m_J1angularAxis[s3+i] = factA*tmp[i]; 441 for (i=0; i<3; i++) info->m_J2angularAxis[s3+i] = factB*tmp[i]; 442 443 for (i=0; i<3; i++) info->m_J1linearAxis[s2+i] = p[i]; 444 for (i=0; i<3; i++) info->m_J1linearAxis[s3+i] = q[i]; 445 for (i=0; i<3; i++) info->m_J2linearAxis[s2+i] = -p[i]; 446 for (i=0; i<3; i++) info->m_J2linearAxis[s3+i] = -q[i]; 447 } 448 // compute two elements of right hand side 449 450 // k = info->fps * info->erp * getSoftnessOrthoLin(); 451 currERP = (m_flags & BT_SLIDER_FLAGS_ERP_ORTLIN) ? m_softnessOrthoLin : m_softnessOrthoLin * info->erp; 452 k = info->fps * currERP; 453 454 btScalar rhs = k * p.dot(ofs); 455 info->m_constraintError[s2] = rhs; 456 rhs = k * q.dot(ofs); 457 info->m_constraintError[s3] = rhs; 458 if(m_flags & BT_SLIDER_FLAGS_CFM_ORTLIN) 459 { 460 info->cfm[s2] = m_cfmOrthoLin; 461 info->cfm[s3] = m_cfmOrthoLin; 462 } 463 464 465 // check linear limits 466 limit_err = btScalar(0.0); 467 limit = 0; 468 if(getSolveLinLimit()) 469 { 470 limit_err = getLinDepth() * signFact; 471 limit = (limit_err > btScalar(0.0)) ? 2 : 1; 472 } 473 powered = 0; 474 if(getPoweredLinMotor()) 475 { 476 powered = 1; 477 } 478 // if the slider has joint limits or motor, add in the extra row 479 if (limit || powered) 480 { 481 nrow++; 482 srow = nrow * info->rowskip; 483 info->m_J1linearAxis[srow+0] = ax1[0]; 484 info->m_J1linearAxis[srow+1] = ax1[1]; 485 info->m_J1linearAxis[srow+2] = ax1[2]; 486 info->m_J2linearAxis[srow+0] = -ax1[0]; 487 info->m_J2linearAxis[srow+1] = -ax1[1]; 488 info->m_J2linearAxis[srow+2] = -ax1[2]; 489 // linear torque decoupling step: 490 // 491 // we have to be careful that the linear constraint forces (+/- ax1) applied to the two bodies 492 // do not create a torque couple. in other words, the points that the 493 // constraint force is applied at must lie along the same ax1 axis. 494 // a torque couple will result in limited slider-jointed free 495 // bodies from gaining angular momentum. 496 if(m_useOffsetForConstraintFrame) 497 { 498 // this is needed only when bodyA and bodyB are both dynamic. 499 if(!hasStaticBody) 500 { 501 tmpA = relA.cross(ax1); 502 tmpB = relB.cross(ax1); 503 info->m_J1angularAxis[srow+0] = tmpA[0]; 504 info->m_J1angularAxis[srow+1] = tmpA[1]; 505 info->m_J1angularAxis[srow+2] = tmpA[2]; 506 info->m_J2angularAxis[srow+0] = -tmpB[0]; 507 info->m_J2angularAxis[srow+1] = -tmpB[1]; 508 info->m_J2angularAxis[srow+2] = -tmpB[2]; 509 } 510 } 511 else 512 { // The old way. May be incorrect if bodies are not on the slider axis 513 btVector3 ltd; // Linear Torque Decoupling vector (a torque) 514 ltd = c.cross(ax1); 515 info->m_J1angularAxis[srow+0] = factA*ltd[0]; 516 info->m_J1angularAxis[srow+1] = factA*ltd[1]; 517 info->m_J1angularAxis[srow+2] = factA*ltd[2]; 518 info->m_J2angularAxis[srow+0] = factB*ltd[0]; 519 info->m_J2angularAxis[srow+1] = factB*ltd[1]; 520 info->m_J2angularAxis[srow+2] = factB*ltd[2]; 521 } 522 // right-hand part 523 btScalar lostop = getLowerLinLimit(); 524 btScalar histop = getUpperLinLimit(); 525 if(limit && (lostop == histop)) 526 { // the joint motor is ineffective 527 powered = 0; 528 } 529 info->m_constraintError[srow] = 0.; 530 info->m_lowerLimit[srow] = 0.; 531 info->m_upperLimit[srow] = 0.; 532 currERP = (m_flags & BT_SLIDER_FLAGS_ERP_LIMLIN) ? m_softnessLimLin : info->erp; 533 if(powered) 534 { 535 if(m_flags & BT_SLIDER_FLAGS_CFM_DIRLIN) 536 { 537 info->cfm[srow] = m_cfmDirLin; 538 } 539 btScalar tag_vel = getTargetLinMotorVelocity(); 540 btScalar mot_fact = getMotorFactor(m_linPos, m_lowerLinLimit, m_upperLinLimit, tag_vel, info->fps * currERP); 541 info->m_constraintError[srow] -= signFact * mot_fact * getTargetLinMotorVelocity(); 542 info->m_lowerLimit[srow] += -getMaxLinMotorForce() / info->fps; 543 info->m_upperLimit[srow] += getMaxLinMotorForce() / info->fps; 544 } 545 if(limit) 546 { 547 k = info->fps * currERP; 548 info->m_constraintError[srow] += k * limit_err; 549 if(m_flags & BT_SLIDER_FLAGS_CFM_LIMLIN) 550 { 551 info->cfm[srow] = m_cfmLimLin; 552 } 553 if(lostop == histop) 554 { // limited low and high simultaneously 555 info->m_lowerLimit[srow] = -SIMD_INFINITY; 556 info->m_upperLimit[srow] = SIMD_INFINITY; 557 } 558 else if(limit == 1) 559 { // low limit 560 info->m_lowerLimit[srow] = -SIMD_INFINITY; 561 info->m_upperLimit[srow] = 0; 562 } 563 else 564 { // high limit 565 info->m_lowerLimit[srow] = 0; 566 info->m_upperLimit[srow] = SIMD_INFINITY; 567 } 568 // bounce (we'll use slider parameter abs(1.0 - m_dampingLimLin) for that) 569 btScalar bounce = btFabs(btScalar(1.0) - getDampingLimLin()); 570 if(bounce > btScalar(0.0)) 571 { 572 btScalar vel = linVelA.dot(ax1); 573 vel -= linVelB.dot(ax1); 574 vel *= signFact; 575 // only apply bounce if the velocity is incoming, and if the 576 // resulting c[] exceeds what we already have. 577 if(limit == 1) 578 { // low limit 579 if(vel < 0) 580 { 581 btScalar newc = -bounce * vel; 582 if (newc > info->m_constraintError[srow]) 583 { 584 info->m_constraintError[srow] = newc; 585 } 586 } 587 } 588 else 589 { // high limit - all those computations are reversed 590 if(vel > 0) 591 { 592 btScalar newc = -bounce * vel; 593 if(newc < info->m_constraintError[srow]) 594 { 595 info->m_constraintError[srow] = newc; 596 } 597 } 598 } 599 } 600 info->m_constraintError[srow] *= getSoftnessLimLin(); 601 } // if(limit) 602 } // if linear limit 603 // check angular limits 604 limit_err = btScalar(0.0); 605 limit = 0; 606 if(getSolveAngLimit()) 607 { 608 limit_err = getAngDepth(); 609 limit = (limit_err > btScalar(0.0)) ? 1 : 2; 610 } 611 // if the slider has joint limits, add in the extra row 612 powered = 0; 613 if(getPoweredAngMotor()) 614 { 615 powered = 1; 616 } 617 if(limit || powered) 618 { 619 nrow++; 620 srow = nrow * info->rowskip; 621 info->m_J1angularAxis[srow+0] = ax1[0]; 622 info->m_J1angularAxis[srow+1] = ax1[1]; 623 info->m_J1angularAxis[srow+2] = ax1[2]; 624 625 info->m_J2angularAxis[srow+0] = -ax1[0]; 626 info->m_J2angularAxis[srow+1] = -ax1[1]; 627 info->m_J2angularAxis[srow+2] = -ax1[2]; 628 629 btScalar lostop = getLowerAngLimit(); 630 btScalar histop = getUpperAngLimit(); 631 if(limit && (lostop == histop)) 632 { // the joint motor is ineffective 633 powered = 0; 634 } 635 currERP = (m_flags & BT_SLIDER_FLAGS_ERP_LIMANG) ? m_softnessLimAng : info->erp; 636 if(powered) 637 { 638 if(m_flags & BT_SLIDER_FLAGS_CFM_DIRANG) 639 { 640 info->cfm[srow] = m_cfmDirAng; 641 } 642 btScalar mot_fact = getMotorFactor(m_angPos, m_lowerAngLimit, m_upperAngLimit, getTargetAngMotorVelocity(), info->fps * currERP); 643 info->m_constraintError[srow] = mot_fact * getTargetAngMotorVelocity(); 644 info->m_lowerLimit[srow] = -getMaxAngMotorForce() / info->fps; 645 info->m_upperLimit[srow] = getMaxAngMotorForce() / info->fps; 646 } 647 if(limit) 648 { 649 k = info->fps * currERP; 650 info->m_constraintError[srow] += k * limit_err; 651 if(m_flags & BT_SLIDER_FLAGS_CFM_LIMANG) 652 { 653 info->cfm[srow] = m_cfmLimAng; 654 } 655 if(lostop == histop) 656 { 657 // limited low and high simultaneously 658 info->m_lowerLimit[srow] = -SIMD_INFINITY; 659 info->m_upperLimit[srow] = SIMD_INFINITY; 660 } 661 else if(limit == 1) 662 { // low limit 663 info->m_lowerLimit[srow] = 0; 664 info->m_upperLimit[srow] = SIMD_INFINITY; 665 } 666 else 667 { // high limit 668 info->m_lowerLimit[srow] = -SIMD_INFINITY; 669 info->m_upperLimit[srow] = 0; 670 } 671 // bounce (we'll use slider parameter abs(1.0 - m_dampingLimAng) for that) 672 btScalar bounce = btFabs(btScalar(1.0) - getDampingLimAng()); 673 if(bounce > btScalar(0.0)) 674 { 675 btScalar vel = m_rbA.getAngularVelocity().dot(ax1); 676 vel -= m_rbB.getAngularVelocity().dot(ax1); 677 // only apply bounce if the velocity is incoming, and if the 678 // resulting c[] exceeds what we already have. 679 if(limit == 1) 680 { // low limit 681 if(vel < 0) 682 { 683 btScalar newc = -bounce * vel; 684 if(newc > info->m_constraintError[srow]) 685 { 686 info->m_constraintError[srow] = newc; 687 } 688 } 689 } 690 else 691 { // high limit - all those computations are reversed 692 if(vel > 0) 693 { 694 btScalar newc = -bounce * vel; 695 if(newc < info->m_constraintError[srow]) 696 { 697 info->m_constraintError[srow] = newc; 698 } 699 } 700 } 701 } 702 info->m_constraintError[srow] *= getSoftnessLimAng(); 703 } // if(limit) 704 } // if angular limit or powered 705} 706 707 708///override the default global value of a parameter (such as ERP or CFM), optionally provide the axis (0..5). 709///If no axis is provided, it uses the default axis for this constraint. 710void btSliderConstraint::setParam(int num, btScalar value, int axis) 711{ 712 switch(num) 713 { 714 case BT_CONSTRAINT_STOP_ERP : 715 if(axis < 1) 716 { 717 m_softnessLimLin = value; 718 m_flags |= BT_SLIDER_FLAGS_ERP_LIMLIN; 719 } 720 else if(axis < 3) 721 { 722 m_softnessOrthoLin = value; 723 m_flags |= BT_SLIDER_FLAGS_ERP_ORTLIN; 724 } 725 else if(axis == 3) 726 { 727 m_softnessLimAng = value; 728 m_flags |= BT_SLIDER_FLAGS_ERP_LIMANG; 729 } 730 else if(axis < 6) 731 { 732 m_softnessOrthoAng = value; 733 m_flags |= BT_SLIDER_FLAGS_ERP_ORTANG; 734 } 735 else 736 { 737 btAssertConstrParams(0); 738 } 739 break; 740 case BT_CONSTRAINT_CFM : 741 if(axis < 1) 742 { 743 m_cfmDirLin = value; 744 m_flags |= BT_SLIDER_FLAGS_CFM_DIRLIN; 745 } 746 else if(axis == 3) 747 { 748 m_cfmDirAng = value; 749 m_flags |= BT_SLIDER_FLAGS_CFM_DIRANG; 750 } 751 else 752 { 753 btAssertConstrParams(0); 754 } 755 break; 756 case BT_CONSTRAINT_STOP_CFM : 757 if(axis < 1) 758 { 759 m_cfmLimLin = value; 760 m_flags |= BT_SLIDER_FLAGS_CFM_LIMLIN; 761 } 762 else if(axis < 3) 763 { 764 m_cfmOrthoLin = value; 765 m_flags |= BT_SLIDER_FLAGS_CFM_ORTLIN; 766 } 767 else if(axis == 3) 768 { 769 m_cfmLimAng = value; 770 m_flags |= BT_SLIDER_FLAGS_CFM_LIMANG; 771 } 772 else if(axis < 6) 773 { 774 m_cfmOrthoAng = value; 775 m_flags |= BT_SLIDER_FLAGS_CFM_ORTANG; 776 } 777 else 778 { 779 btAssertConstrParams(0); 780 } 781 break; 782 } 783} 784 785///return the local value of parameter 786btScalar btSliderConstraint::getParam(int num, int axis) const 787{ 788 btScalar retVal(SIMD_INFINITY); 789 switch(num) 790 { 791 case BT_CONSTRAINT_STOP_ERP : 792 if(axis < 1) 793 { 794 btAssertConstrParams(m_flags & BT_SLIDER_FLAGS_ERP_LIMLIN); 795 retVal = m_softnessLimLin; 796 } 797 else if(axis < 3) 798 { 799 btAssertConstrParams(m_flags & BT_SLIDER_FLAGS_ERP_ORTLIN); 800 retVal = m_softnessOrthoLin; 801 } 802 else if(axis == 3) 803 { 804 btAssertConstrParams(m_flags & BT_SLIDER_FLAGS_ERP_LIMANG); 805 retVal = m_softnessLimAng; 806 } 807 else if(axis < 6) 808 { 809 btAssertConstrParams(m_flags & BT_SLIDER_FLAGS_ERP_ORTANG); 810 retVal = m_softnessOrthoAng; 811 } 812 else 813 { 814 btAssertConstrParams(0); 815 } 816 break; 817 case BT_CONSTRAINT_CFM : 818 if(axis < 1) 819 { 820 btAssertConstrParams(m_flags & BT_SLIDER_FLAGS_CFM_DIRLIN); 821 retVal = m_cfmDirLin; 822 } 823 else if(axis == 3) 824 { 825 btAssertConstrParams(m_flags & BT_SLIDER_FLAGS_CFM_DIRANG); 826 retVal = m_cfmDirAng; 827 } 828 else 829 { 830 btAssertConstrParams(0); 831 } 832 break; 833 case BT_CONSTRAINT_STOP_CFM : 834 if(axis < 1) 835 { 836 btAssertConstrParams(m_flags & BT_SLIDER_FLAGS_CFM_LIMLIN); 837 retVal = m_cfmLimLin; 838 } 839 else if(axis < 3) 840 { 841 btAssertConstrParams(m_flags & BT_SLIDER_FLAGS_CFM_ORTLIN); 842 retVal = m_cfmOrthoLin; 843 } 844 else if(axis == 3) 845 { 846 btAssertConstrParams(m_flags & BT_SLIDER_FLAGS_CFM_LIMANG); 847 retVal = m_cfmLimAng; 848 } 849 else if(axis < 6) 850 { 851 btAssertConstrParams(m_flags & BT_SLIDER_FLAGS_CFM_ORTANG); 852 retVal = m_cfmOrthoAng; 853 } 854 else 855 { 856 btAssertConstrParams(0); 857 } 858 break; 859 } 860 return retVal; 861} 862 863 864 865