1 /* 2 Bullet Continuous Collision Detection and Physics Library 3 Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 4 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: 10 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. 14 */ 15 16 17 #include "btHingeConstraint.h" 18 #include "BulletDynamics/Dynamics/btRigidBody.h" 19 #include "LinearMath/btTransformUtil.h" 20 #include "LinearMath/btMinMax.h" 21 #include <new> 22 #include "btSolverBody.h" 23 24 25 26 //#define HINGE_USE_OBSOLETE_SOLVER false 27 #define HINGE_USE_OBSOLETE_SOLVER false 28 29 #define HINGE_USE_FRAME_OFFSET true 30 31 #ifndef __SPU__ 32 33 34 35 36 37 btHingeConstraint::btHingeConstraint(btRigidBody& rbA,btRigidBody& rbB, const btVector3& pivotInA,const btVector3& pivotInB, 38 const btVector3& axisInA,const btVector3& axisInB, bool useReferenceFrameA) 39 :btTypedConstraint(HINGE_CONSTRAINT_TYPE, rbA,rbB), 40 #ifdef _BT_USE_CENTER_LIMIT_ 41 m_limit(), 42 #endif 43 m_angularOnly(false), 44 m_enableAngularMotor(false), 45 m_useSolveConstraintObsolete(HINGE_USE_OBSOLETE_SOLVER), 46 m_useOffsetForConstraintFrame(HINGE_USE_FRAME_OFFSET), 47 m_useReferenceFrameA(useReferenceFrameA), 48 m_flags(0), 49 m_normalCFM(0), 50 m_normalERP(0), 51 m_stopCFM(0), 52 m_stopERP(0) 53 { 54 m_rbAFrame.getOrigin() = pivotInA; 55 56 // since no frame is given, assume this to be zero angle and just pick rb transform axis 57 btVector3 rbAxisA1 = rbA.getCenterOfMassTransform().getBasis().getColumn(0); 58 59 btVector3 rbAxisA2; 60 btScalar projection = axisInA.dot(rbAxisA1); 61 if (projection >= 1.0f - SIMD_EPSILON) { 62 rbAxisA1 = -rbA.getCenterOfMassTransform().getBasis().getColumn(2); 63 rbAxisA2 = rbA.getCenterOfMassTransform().getBasis().getColumn(1); 64 } else if (projection <= -1.0f + SIMD_EPSILON) { 65 rbAxisA1 = rbA.getCenterOfMassTransform().getBasis().getColumn(2); 66 rbAxisA2 = rbA.getCenterOfMassTransform().getBasis().getColumn(1); 67 } else { 68 rbAxisA2 = axisInA.cross(rbAxisA1); 69 rbAxisA1 = rbAxisA2.cross(axisInA); 70 } 71 72 m_rbAFrame.getBasis().setValue( rbAxisA1.getX(),rbAxisA2.getX(),axisInA.getX(), 73 rbAxisA1.getY(),rbAxisA2.getY(),axisInA.getY(), 74 rbAxisA1.getZ(),rbAxisA2.getZ(),axisInA.getZ() ); 75 76 btQuaternion rotationArc = shortestArcQuat(axisInA,axisInB); 77 btVector3 rbAxisB1 = quatRotate(rotationArc,rbAxisA1); 78 btVector3 rbAxisB2 = axisInB.cross(rbAxisB1); 79 80 m_rbBFrame.getOrigin() = pivotInB; 81 m_rbBFrame.getBasis().setValue( rbAxisB1.getX(),rbAxisB2.getX(),axisInB.getX(), 82 rbAxisB1.getY(),rbAxisB2.getY(),axisInB.getY(), 83 rbAxisB1.getZ(),rbAxisB2.getZ(),axisInB.getZ() ); 84 85 #ifndef _BT_USE_CENTER_LIMIT_ 86 //start with free 87 m_lowerLimit = btScalar(1.0f); 88 m_upperLimit = btScalar(-1.0f); 89 m_biasFactor = 0.3f; 90 m_relaxationFactor = 1.0f; 91 m_limitSoftness = 0.9f; 92 m_solveLimit = false; 93 #endif 94 m_referenceSign = m_useReferenceFrameA ? btScalar(-1.f) : btScalar(1.f); 95 } 96 97 98 99 btHingeConstraint::btHingeConstraint(btRigidBody& rbA,const btVector3& pivotInA,const btVector3& axisInA, bool useReferenceFrameA) 100 :btTypedConstraint(HINGE_CONSTRAINT_TYPE, rbA), 101 #ifdef _BT_USE_CENTER_LIMIT_ 102 m_limit(), 103 #endif 104 m_angularOnly(false), m_enableAngularMotor(false), 105 m_useSolveConstraintObsolete(HINGE_USE_OBSOLETE_SOLVER), 106 m_useOffsetForConstraintFrame(HINGE_USE_FRAME_OFFSET), 107 m_useReferenceFrameA(useReferenceFrameA), 108 m_flags(0), 109 m_normalCFM(0), 110 m_normalERP(0), 111 m_stopCFM(0), 112 m_stopERP(0) 113 { 114 115 // since no frame is given, assume this to be zero angle and just pick rb transform axis 116 // fixed axis in worldspace 117 btVector3 rbAxisA1, rbAxisA2; 118 btPlaneSpace1(axisInA, rbAxisA1, rbAxisA2); 119 120 m_rbAFrame.getOrigin() = pivotInA; 121 m_rbAFrame.getBasis().setValue( rbAxisA1.getX(),rbAxisA2.getX(),axisInA.getX(), 122 rbAxisA1.getY(),rbAxisA2.getY(),axisInA.getY(), 123 rbAxisA1.getZ(),rbAxisA2.getZ(),axisInA.getZ() ); 124 125 btVector3 axisInB = rbA.getCenterOfMassTransform().getBasis() * axisInA; 126 127 btQuaternion rotationArc = shortestArcQuat(axisInA,axisInB); 128 btVector3 rbAxisB1 = quatRotate(rotationArc,rbAxisA1); 129 btVector3 rbAxisB2 = axisInB.cross(rbAxisB1); 130 131 132 m_rbBFrame.getOrigin() = rbA.getCenterOfMassTransform()(pivotInA); 133 m_rbBFrame.getBasis().setValue( rbAxisB1.getX(),rbAxisB2.getX(),axisInB.getX(), 134 rbAxisB1.getY(),rbAxisB2.getY(),axisInB.getY(), 135 rbAxisB1.getZ(),rbAxisB2.getZ(),axisInB.getZ() ); 136 137 #ifndef _BT_USE_CENTER_LIMIT_ 138 //start with free 139 m_lowerLimit = btScalar(1.0f); 140 m_upperLimit = btScalar(-1.0f); 141 m_biasFactor = 0.3f; 142 m_relaxationFactor = 1.0f; 143 m_limitSoftness = 0.9f; 144 m_solveLimit = false; 145 #endif 146 m_referenceSign = m_useReferenceFrameA ? btScalar(-1.f) : btScalar(1.f); 147 } 148 149 150 151 btHingeConstraint::btHingeConstraint(btRigidBody& rbA,btRigidBody& rbB, 152 const btTransform& rbAFrame, const btTransform& rbBFrame, bool useReferenceFrameA) 153 :btTypedConstraint(HINGE_CONSTRAINT_TYPE, rbA,rbB),m_rbAFrame(rbAFrame),m_rbBFrame(rbBFrame), 154 #ifdef _BT_USE_CENTER_LIMIT_ 155 m_limit(), 156 #endif 157 m_angularOnly(false), 158 m_enableAngularMotor(false), 159 m_useSolveConstraintObsolete(HINGE_USE_OBSOLETE_SOLVER), 160 m_useOffsetForConstraintFrame(HINGE_USE_FRAME_OFFSET), 161 m_useReferenceFrameA(useReferenceFrameA), 162 m_flags(0), 163 m_normalCFM(0), 164 m_normalERP(0), 165 m_stopCFM(0), 166 m_stopERP(0) 167 { 168 #ifndef _BT_USE_CENTER_LIMIT_ 169 //start with free 170 m_lowerLimit = btScalar(1.0f); 171 m_upperLimit = btScalar(-1.0f); 172 m_biasFactor = 0.3f; 173 m_relaxationFactor = 1.0f; 174 m_limitSoftness = 0.9f; 175 m_solveLimit = false; 176 #endif 177 m_referenceSign = m_useReferenceFrameA ? btScalar(-1.f) : btScalar(1.f); 178 } 179 180 181 182 btHingeConstraint::btHingeConstraint(btRigidBody& rbA, const btTransform& rbAFrame, bool useReferenceFrameA) 183 :btTypedConstraint(HINGE_CONSTRAINT_TYPE, rbA),m_rbAFrame(rbAFrame),m_rbBFrame(rbAFrame), 184 #ifdef _BT_USE_CENTER_LIMIT_ 185 m_limit(), 186 #endif 187 m_angularOnly(false), 188 m_enableAngularMotor(false), 189 m_useSolveConstraintObsolete(HINGE_USE_OBSOLETE_SOLVER), 190 m_useOffsetForConstraintFrame(HINGE_USE_FRAME_OFFSET), 191 m_useReferenceFrameA(useReferenceFrameA), 192 m_flags(0), 193 m_normalCFM(0), 194 m_normalERP(0), 195 m_stopCFM(0), 196 m_stopERP(0) 197 { 198 ///not providing rigidbody B means implicitly using worldspace for body B 199 200 m_rbBFrame.getOrigin() = m_rbA.getCenterOfMassTransform()(m_rbAFrame.getOrigin()); 201 #ifndef _BT_USE_CENTER_LIMIT_ 202 //start with free 203 m_lowerLimit = btScalar(1.0f); 204 m_upperLimit = btScalar(-1.0f); 205 m_biasFactor = 0.3f; 206 m_relaxationFactor = 1.0f; 207 m_limitSoftness = 0.9f; 208 m_solveLimit = false; 209 #endif 210 m_referenceSign = m_useReferenceFrameA ? btScalar(-1.f) : btScalar(1.f); 211 } 212 213 214 215 void btHingeConstraint::buildJacobian() 216 { 217 if (m_useSolveConstraintObsolete) 218 { 219 m_appliedImpulse = btScalar(0.); 220 m_accMotorImpulse = btScalar(0.); 221 222 if (!m_angularOnly) 223 { 224 btVector3 pivotAInW = m_rbA.getCenterOfMassTransform()*m_rbAFrame.getOrigin(); 225 btVector3 pivotBInW = m_rbB.getCenterOfMassTransform()*m_rbBFrame.getOrigin(); 226 btVector3 relPos = pivotBInW - pivotAInW; 227 228 btVector3 normal[3]; 229 if (relPos.length2() > SIMD_EPSILON) 230 { 231 normal[0] = relPos.normalized(); 232 } 233 else 234 { 235 normal[0].setValue(btScalar(1.0),0,0); 236 } 237 238 btPlaneSpace1(normal[0], normal[1], normal[2]); 239 240 for (int i=0;i<3;i++) 241 { 242 new (&m_jac[i]) btJacobianEntry( 243 m_rbA.getCenterOfMassTransform().getBasis().transpose(), 244 m_rbB.getCenterOfMassTransform().getBasis().transpose(), 245 pivotAInW - m_rbA.getCenterOfMassPosition(), 246 pivotBInW - m_rbB.getCenterOfMassPosition(), 247 normal[i], 248 m_rbA.getInvInertiaDiagLocal(), 249 m_rbA.getInvMass(), 250 m_rbB.getInvInertiaDiagLocal(), 251 m_rbB.getInvMass()); 252 } 253 } 254 255 //calculate two perpendicular jointAxis, orthogonal to hingeAxis 256 //these two jointAxis require equal angular velocities for both bodies 257 258 //this is unused for now, it's a todo 259 btVector3 jointAxis0local; 260 btVector3 jointAxis1local; 261 262 btPlaneSpace1(m_rbAFrame.getBasis().getColumn(2),jointAxis0local,jointAxis1local); 263 264 btVector3 jointAxis0 = getRigidBodyA().getCenterOfMassTransform().getBasis() * jointAxis0local; 265 btVector3 jointAxis1 = getRigidBodyA().getCenterOfMassTransform().getBasis() * jointAxis1local; 266 btVector3 hingeAxisWorld = getRigidBodyA().getCenterOfMassTransform().getBasis() * m_rbAFrame.getBasis().getColumn(2); 267 268 new (&m_jacAng[0]) btJacobianEntry(jointAxis0, 269 m_rbA.getCenterOfMassTransform().getBasis().transpose(), 270 m_rbB.getCenterOfMassTransform().getBasis().transpose(), 271 m_rbA.getInvInertiaDiagLocal(), 272 m_rbB.getInvInertiaDiagLocal()); 273 274 new (&m_jacAng[1]) btJacobianEntry(jointAxis1, 275 m_rbA.getCenterOfMassTransform().getBasis().transpose(), 276 m_rbB.getCenterOfMassTransform().getBasis().transpose(), 277 m_rbA.getInvInertiaDiagLocal(), 278 m_rbB.getInvInertiaDiagLocal()); 279 280 new (&m_jacAng[2]) btJacobianEntry(hingeAxisWorld, 281 m_rbA.getCenterOfMassTransform().getBasis().transpose(), 282 m_rbB.getCenterOfMassTransform().getBasis().transpose(), 283 m_rbA.getInvInertiaDiagLocal(), 284 m_rbB.getInvInertiaDiagLocal()); 285 286 // clear accumulator 287 m_accLimitImpulse = btScalar(0.); 288 289 // test angular limit 290 testLimit(m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform()); 291 292 //Compute K = J*W*J' for hinge axis 293 btVector3 axisA = getRigidBodyA().getCenterOfMassTransform().getBasis() * m_rbAFrame.getBasis().getColumn(2); 294 m_kHinge = 1.0f / (getRigidBodyA().computeAngularImpulseDenominator(axisA) + 295 getRigidBodyB().computeAngularImpulseDenominator(axisA)); 296 297 } 298 } 299 300 301 #endif //__SPU__ 302 303 304 static inline btScalar btNormalizeAnglePositive(btScalar angle) 305 { 306 return btFmod(btFmod(angle, btScalar(2.0*SIMD_PI)) + btScalar(2.0*SIMD_PI), btScalar(2.0*SIMD_PI)); 307 } 308 309 310 311 static btScalar btShortestAngularDistance(btScalar accAngle, btScalar curAngle) 312 { 313 btScalar result = btNormalizeAngle(btNormalizeAnglePositive(btNormalizeAnglePositive(curAngle) - 314 btNormalizeAnglePositive(accAngle))); 315 return result; 316 } 317 318 static btScalar btShortestAngleUpdate(btScalar accAngle, btScalar curAngle) 319 { 320 btScalar tol(0.3); 321 btScalar result = btShortestAngularDistance(accAngle, curAngle); 322 323 if (btFabs(result) > tol) 324 return curAngle; 325 else 326 return accAngle + result; 327 328 return curAngle; 329 } 330 331 332 btScalar btHingeAccumulatedAngleConstraint::getAccumulatedHingeAngle() 333 { 334 btScalar hingeAngle = getHingeAngle(); 335 m_accumulatedAngle = btShortestAngleUpdate(m_accumulatedAngle,hingeAngle); 336 return m_accumulatedAngle; 337 } 338 void btHingeAccumulatedAngleConstraint::setAccumulatedHingeAngle(btScalar accAngle) 339 { 340 m_accumulatedAngle = accAngle; 341 } 342 343 void btHingeAccumulatedAngleConstraint::getInfo1(btConstraintInfo1* info) 344 { 345 //update m_accumulatedAngle 346 btScalar curHingeAngle = getHingeAngle(); 347 m_accumulatedAngle = btShortestAngleUpdate(m_accumulatedAngle,curHingeAngle); 348 349 btHingeConstraint::getInfo1(info); 350 351 } 352 353 354 void btHingeConstraint::getInfo1(btConstraintInfo1* info) 355 { 356 357 358 if (m_useSolveConstraintObsolete) 359 { 360 info->m_numConstraintRows = 0; 361 info->nub = 0; 362 } 363 else 364 { 365 info->m_numConstraintRows = 5; // Fixed 3 linear + 2 angular 366 info->nub = 1; 367 //always add the row, to avoid computation (data is not available yet) 368 //prepare constraint 369 testLimit(m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform()); 370 if(getSolveLimit() || getEnableAngularMotor()) 371 { 372 info->m_numConstraintRows++; // limit 3rd anguar as well 373 info->nub--; 374 } 375 376 } 377 } 378 379 void btHingeConstraint::getInfo1NonVirtual(btConstraintInfo1* info) 380 { 381 if (m_useSolveConstraintObsolete) 382 { 383 info->m_numConstraintRows = 0; 384 info->nub = 0; 385 } 386 else 387 { 388 //always add the 'limit' row, to avoid computation (data is not available yet) 389 info->m_numConstraintRows = 6; // Fixed 3 linear + 2 angular 390 info->nub = 0; 391 } 392 } 393 394 void btHingeConstraint::getInfo2 (btConstraintInfo2* info) 395 { 396 if(m_useOffsetForConstraintFrame) 397 { 398 getInfo2InternalUsingFrameOffset(info, m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform(),m_rbA.getAngularVelocity(),m_rbB.getAngularVelocity()); 399 } 400 else 401 { 402 getInfo2Internal(info, m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform(),m_rbA.getAngularVelocity(),m_rbB.getAngularVelocity()); 403 } 404 } 405 406 407 void btHingeConstraint::getInfo2NonVirtual (btConstraintInfo2* info,const btTransform& transA,const btTransform& transB,const btVector3& angVelA,const btVector3& angVelB) 408 { 409 ///the regular (virtual) implementation getInfo2 already performs 'testLimit' during getInfo1, so we need to do it now 410 testLimit(transA,transB); 411 412 getInfo2Internal(info,transA,transB,angVelA,angVelB); 413 } 414 415 416 void btHingeConstraint::getInfo2Internal(btConstraintInfo2* info, const btTransform& transA,const btTransform& transB,const btVector3& angVelA,const btVector3& angVelB) 417 { 418 419 btAssert(!m_useSolveConstraintObsolete); 420 int i, skip = info->rowskip; 421 // transforms in world space 422 btTransform trA = transA*m_rbAFrame; 423 btTransform trB = transB*m_rbBFrame; 424 // pivot point 425 btVector3 pivotAInW = trA.getOrigin(); 426 btVector3 pivotBInW = trB.getOrigin(); 427 #if 0 428 if (0) 429 { 430 for (i=0;i<6;i++) 431 { 432 info->m_J1linearAxis[i*skip]=0; 433 info->m_J1linearAxis[i*skip+1]=0; 434 info->m_J1linearAxis[i*skip+2]=0; 435 436 info->m_J1angularAxis[i*skip]=0; 437 info->m_J1angularAxis[i*skip+1]=0; 438 info->m_J1angularAxis[i*skip+2]=0; 439 440 info->m_J2linearAxis[i*skip]=0; 441 info->m_J2linearAxis[i*skip+1]=0; 442 info->m_J2linearAxis[i*skip+2]=0; 443 444 info->m_J2angularAxis[i*skip]=0; 445 info->m_J2angularAxis[i*skip+1]=0; 446 info->m_J2angularAxis[i*skip+2]=0; 447 448 info->m_constraintError[i*skip]=0.f; 449 } 450 } 451 #endif //#if 0 452 // linear (all fixed) 453 454 if (!m_angularOnly) 455 { 456 info->m_J1linearAxis[0] = 1; 457 info->m_J1linearAxis[skip + 1] = 1; 458 info->m_J1linearAxis[2 * skip + 2] = 1; 459 460 info->m_J2linearAxis[0] = -1; 461 info->m_J2linearAxis[skip + 1] = -1; 462 info->m_J2linearAxis[2 * skip + 2] = -1; 463 } 464 465 466 467 468 btVector3 a1 = pivotAInW - transA.getOrigin(); 469 { 470 btVector3* angular0 = (btVector3*)(info->m_J1angularAxis); 471 btVector3* angular1 = (btVector3*)(info->m_J1angularAxis + skip); 472 btVector3* angular2 = (btVector3*)(info->m_J1angularAxis + 2 * skip); 473 btVector3 a1neg = -a1; 474 a1neg.getSkewSymmetricMatrix(angular0,angular1,angular2); 475 } 476 btVector3 a2 = pivotBInW - transB.getOrigin(); 477 { 478 btVector3* angular0 = (btVector3*)(info->m_J2angularAxis); 479 btVector3* angular1 = (btVector3*)(info->m_J2angularAxis + skip); 480 btVector3* angular2 = (btVector3*)(info->m_J2angularAxis + 2 * skip); 481 a2.getSkewSymmetricMatrix(angular0,angular1,angular2); 482 } 483 // linear RHS 484 btScalar normalErp = (m_flags & BT_HINGE_FLAGS_ERP_NORM) ? m_normalERP : info->erp; 485 486 btScalar k = info->fps * normalErp; 487 if (!m_angularOnly) 488 { 489 for(i = 0; i < 3; i++) 490 { 491 info->m_constraintError[i * skip] = k * (pivotBInW[i] - pivotAInW[i]); 492 } 493 } 494 // make rotations around X and Y equal 495 // the hinge axis should be the only unconstrained 496 // rotational axis, the angular velocity of the two bodies perpendicular to 497 // the hinge axis should be equal. thus the constraint equations are 498 // p*w1 - p*w2 = 0 499 // q*w1 - q*w2 = 0 500 // where p and q are unit vectors normal to the hinge axis, and w1 and w2 501 // are the angular velocity vectors of the two bodies. 502 // get hinge axis (Z) 503 btVector3 ax1 = trA.getBasis().getColumn(2); 504 // get 2 orthos to hinge axis (X, Y) 505 btVector3 p = trA.getBasis().getColumn(0); 506 btVector3 q = trA.getBasis().getColumn(1); 507 // set the two hinge angular rows 508 int s3 = 3 * info->rowskip; 509 int s4 = 4 * info->rowskip; 510 511 info->m_J1angularAxis[s3 + 0] = p[0]; 512 info->m_J1angularAxis[s3 + 1] = p[1]; 513 info->m_J1angularAxis[s3 + 2] = p[2]; 514 info->m_J1angularAxis[s4 + 0] = q[0]; 515 info->m_J1angularAxis[s4 + 1] = q[1]; 516 info->m_J1angularAxis[s4 + 2] = q[2]; 517 518 info->m_J2angularAxis[s3 + 0] = -p[0]; 519 info->m_J2angularAxis[s3 + 1] = -p[1]; 520 info->m_J2angularAxis[s3 + 2] = -p[2]; 521 info->m_J2angularAxis[s4 + 0] = -q[0]; 522 info->m_J2angularAxis[s4 + 1] = -q[1]; 523 info->m_J2angularAxis[s4 + 2] = -q[2]; 524 // compute the right hand side of the constraint equation. set relative 525 // body velocities along p and q to bring the hinge back into alignment. 526 // if ax1,ax2 are the unit length hinge axes as computed from body1 and 527 // body2, we need to rotate both bodies along the axis u = (ax1 x ax2). 528 // if `theta' is the angle between ax1 and ax2, we need an angular velocity 529 // along u to cover angle erp*theta in one step : 530 // |angular_velocity| = angle/time = erp*theta / stepsize 531 // = (erp*fps) * theta 532 // angular_velocity = |angular_velocity| * (ax1 x ax2) / |ax1 x ax2| 533 // = (erp*fps) * theta * (ax1 x ax2) / sin(theta) 534 // ...as ax1 and ax2 are unit length. if theta is smallish, 535 // theta ~= sin(theta), so 536 // angular_velocity = (erp*fps) * (ax1 x ax2) 537 // ax1 x ax2 is in the plane space of ax1, so we project the angular 538 // velocity to p and q to find the right hand side. 539 btVector3 ax2 = trB.getBasis().getColumn(2); 540 btVector3 u = ax1.cross(ax2); 541 info->m_constraintError[s3] = k * u.dot(p); 542 info->m_constraintError[s4] = k * u.dot(q); 543 // check angular limits 544 int nrow = 4; // last filled row 545 int srow; 546 btScalar limit_err = btScalar(0.0); 547 int limit = 0; 548 if(getSolveLimit()) 549 { 550 #ifdef _BT_USE_CENTER_LIMIT_ 551 limit_err = m_limit.getCorrection() * m_referenceSign; 552 #else 553 limit_err = m_correction * m_referenceSign; 554 #endif 555 limit = (limit_err > btScalar(0.0)) ? 1 : 2; 556 557 } 558 // if the hinge has joint limits or motor, add in the extra row 559 int powered = 0; 560 if(getEnableAngularMotor()) 561 { 562 powered = 1; 563 } 564 if(limit || powered) 565 { 566 nrow++; 567 srow = nrow * info->rowskip; 568 info->m_J1angularAxis[srow+0] = ax1[0]; 569 info->m_J1angularAxis[srow+1] = ax1[1]; 570 info->m_J1angularAxis[srow+2] = ax1[2]; 571 572 info->m_J2angularAxis[srow+0] = -ax1[0]; 573 info->m_J2angularAxis[srow+1] = -ax1[1]; 574 info->m_J2angularAxis[srow+2] = -ax1[2]; 575 576 btScalar lostop = getLowerLimit(); 577 btScalar histop = getUpperLimit(); 578 if(limit && (lostop == histop)) 579 { // the joint motor is ineffective 580 powered = 0; 581 } 582 info->m_constraintError[srow] = btScalar(0.0f); 583 btScalar currERP = (m_flags & BT_HINGE_FLAGS_ERP_STOP) ? m_stopERP : normalErp; 584 if(powered) 585 { 586 if(m_flags & BT_HINGE_FLAGS_CFM_NORM) 587 { 588 info->cfm[srow] = m_normalCFM; 589 } 590 btScalar mot_fact = getMotorFactor(m_hingeAngle, lostop, histop, m_motorTargetVelocity, info->fps * currERP); 591 info->m_constraintError[srow] += mot_fact * m_motorTargetVelocity * m_referenceSign; 592 info->m_lowerLimit[srow] = - m_maxMotorImpulse; 593 info->m_upperLimit[srow] = m_maxMotorImpulse; 594 } 595 if(limit) 596 { 597 k = info->fps * currERP; 598 info->m_constraintError[srow] += k * limit_err; 599 if(m_flags & BT_HINGE_FLAGS_CFM_STOP) 600 { 601 info->cfm[srow] = m_stopCFM; 602 } 603 if(lostop == histop) 604 { 605 // limited low and high simultaneously 606 info->m_lowerLimit[srow] = -SIMD_INFINITY; 607 info->m_upperLimit[srow] = SIMD_INFINITY; 608 } 609 else if(limit == 1) 610 { // low limit 611 info->m_lowerLimit[srow] = 0; 612 info->m_upperLimit[srow] = SIMD_INFINITY; 613 } 614 else 615 { // high limit 616 info->m_lowerLimit[srow] = -SIMD_INFINITY; 617 info->m_upperLimit[srow] = 0; 618 } 619 // bounce (we'll use slider parameter abs(1.0 - m_dampingLimAng) for that) 620 #ifdef _BT_USE_CENTER_LIMIT_ 621 btScalar bounce = m_limit.getRelaxationFactor(); 622 #else 623 btScalar bounce = m_relaxationFactor; 624 #endif 625 if(bounce > btScalar(0.0)) 626 { 627 btScalar vel = angVelA.dot(ax1); 628 vel -= angVelB.dot(ax1); 629 // only apply bounce if the velocity is incoming, and if the 630 // resulting c[] exceeds what we already have. 631 if(limit == 1) 632 { // low limit 633 if(vel < 0) 634 { 635 btScalar newc = -bounce * vel; 636 if(newc > info->m_constraintError[srow]) 637 { 638 info->m_constraintError[srow] = newc; 639 } 640 } 641 } 642 else 643 { // high limit - all those computations are reversed 644 if(vel > 0) 645 { 646 btScalar newc = -bounce * vel; 647 if(newc < info->m_constraintError[srow]) 648 { 649 info->m_constraintError[srow] = newc; 650 } 651 } 652 } 653 } 654 #ifdef _BT_USE_CENTER_LIMIT_ 655 info->m_constraintError[srow] *= m_limit.getBiasFactor(); 656 #else 657 info->m_constraintError[srow] *= m_biasFactor; 658 #endif 659 } // if(limit) 660 } // if angular limit or powered 661 } 662 663 664 void btHingeConstraint::setFrames(const btTransform & frameA, const btTransform & frameB) 665 { 666 m_rbAFrame = frameA; 667 m_rbBFrame = frameB; 668 buildJacobian(); 669 } 670 671 672 void btHingeConstraint::updateRHS(btScalar timeStep) 673 { 674 (void)timeStep; 675 676 } 677 678 679 680 681 btScalar btHingeConstraint::getHingeAngle() 682 { 683 return getHingeAngle(m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform()); 684 } 685 686 btScalar btHingeConstraint::getHingeAngle(const btTransform& transA,const btTransform& transB) 687 { 688 const btVector3 refAxis0 = transA.getBasis() * m_rbAFrame.getBasis().getColumn(0); 689 const btVector3 refAxis1 = transA.getBasis() * m_rbAFrame.getBasis().getColumn(1); 690 const btVector3 swingAxis = transB.getBasis() * m_rbBFrame.getBasis().getColumn(1); 691 // btScalar angle = btAtan2Fast(swingAxis.dot(refAxis0), swingAxis.dot(refAxis1)); 692 btScalar angle = btAtan2(swingAxis.dot(refAxis0), swingAxis.dot(refAxis1)); 693 return m_referenceSign * angle; 694 } 695 696 697 698 void btHingeConstraint::testLimit(const btTransform& transA,const btTransform& transB) 699 { 700 // Compute limit information 701 m_hingeAngle = getHingeAngle(transA,transB); 702 #ifdef _BT_USE_CENTER_LIMIT_ 703 m_limit.test(m_hingeAngle); 704 #else 705 m_correction = btScalar(0.); 706 m_limitSign = btScalar(0.); 707 m_solveLimit = false; 708 if (m_lowerLimit <= m_upperLimit) 709 { 710 m_hingeAngle = btAdjustAngleToLimits(m_hingeAngle, m_lowerLimit, m_upperLimit); 711 if (m_hingeAngle <= m_lowerLimit) 712 { 713 m_correction = (m_lowerLimit - m_hingeAngle); 714 m_limitSign = 1.0f; 715 m_solveLimit = true; 716 } 717 else if (m_hingeAngle >= m_upperLimit) 718 { 719 m_correction = m_upperLimit - m_hingeAngle; 720 m_limitSign = -1.0f; 721 m_solveLimit = true; 722 } 723 } 724 #endif 725 return; 726 } 727 728 729 static btVector3 vHinge(0, 0, btScalar(1)); 730 731 void btHingeConstraint::setMotorTarget(const btQuaternion& qAinB, btScalar dt) 732 { 733 // convert target from body to constraint space 734 btQuaternion qConstraint = m_rbBFrame.getRotation().inverse() * qAinB * m_rbAFrame.getRotation(); 735 qConstraint.normalize(); 736 737 // extract "pure" hinge component 738 btVector3 vNoHinge = quatRotate(qConstraint, vHinge); vNoHinge.normalize(); 739 btQuaternion qNoHinge = shortestArcQuat(vHinge, vNoHinge); 740 btQuaternion qHinge = qNoHinge.inverse() * qConstraint; 741 qHinge.normalize(); 742 743 // compute angular target, clamped to limits 744 btScalar targetAngle = qHinge.getAngle(); 745 if (targetAngle > SIMD_PI) // long way around. flip quat and recalculate. 746 { 747 qHinge = -(qHinge); 748 targetAngle = qHinge.getAngle(); 749 } 750 if (qHinge.getZ() < 0) 751 targetAngle = -targetAngle; 752 753 setMotorTarget(targetAngle, dt); 754 } 755 756 void btHingeConstraint::setMotorTarget(btScalar targetAngle, btScalar dt) 757 { 758 #ifdef _BT_USE_CENTER_LIMIT_ 759 m_limit.fit(targetAngle); 760 #else 761 if (m_lowerLimit < m_upperLimit) 762 { 763 if (targetAngle < m_lowerLimit) 764 targetAngle = m_lowerLimit; 765 else if (targetAngle > m_upperLimit) 766 targetAngle = m_upperLimit; 767 } 768 #endif 769 // compute angular velocity 770 btScalar curAngle = getHingeAngle(m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform()); 771 btScalar dAngle = targetAngle - curAngle; 772 m_motorTargetVelocity = dAngle / dt; 773 } 774 775 776 777 void btHingeConstraint::getInfo2InternalUsingFrameOffset(btConstraintInfo2* info, const btTransform& transA,const btTransform& transB,const btVector3& angVelA,const btVector3& angVelB) 778 { 779 btAssert(!m_useSolveConstraintObsolete); 780 int i, s = info->rowskip; 781 // transforms in world space 782 btTransform trA = transA*m_rbAFrame; 783 btTransform trB = transB*m_rbBFrame; 784 // pivot point 785 // btVector3 pivotAInW = trA.getOrigin(); 786 // btVector3 pivotBInW = trB.getOrigin(); 787 #if 1 788 // difference between frames in WCS 789 btVector3 ofs = trB.getOrigin() - trA.getOrigin(); 790 // now get weight factors depending on masses 791 btScalar miA = getRigidBodyA().getInvMass(); 792 btScalar miB = getRigidBodyB().getInvMass(); 793 bool hasStaticBody = (miA < SIMD_EPSILON) || (miB < SIMD_EPSILON); 794 btScalar miS = miA + miB; 795 btScalar factA, factB; 796 if(miS > btScalar(0.f)) 797 { 798 factA = miB / miS; 799 } 800 else 801 { 802 factA = btScalar(0.5f); 803 } 804 factB = btScalar(1.0f) - factA; 805 // get the desired direction of hinge axis 806 // as weighted sum of Z-orthos of frameA and frameB in WCS 807 btVector3 ax1A = trA.getBasis().getColumn(2); 808 btVector3 ax1B = trB.getBasis().getColumn(2); 809 btVector3 ax1 = ax1A * factA + ax1B * factB; 810 ax1.normalize(); 811 // fill first 3 rows 812 // we want: velA + wA x relA == velB + wB x relB 813 btTransform bodyA_trans = transA; 814 btTransform bodyB_trans = transB; 815 int s0 = 0; 816 int s1 = s; 817 int s2 = s * 2; 818 int nrow = 2; // last filled row 819 btVector3 tmpA, tmpB, relA, relB, p, q; 820 // get vector from bodyB to frameB in WCS 821 relB = trB.getOrigin() - bodyB_trans.getOrigin(); 822 // get its projection to hinge axis 823 btVector3 projB = ax1 * relB.dot(ax1); 824 // get vector directed from bodyB to hinge axis (and orthogonal to it) 825 btVector3 orthoB = relB - projB; 826 // same for bodyA 827 relA = trA.getOrigin() - bodyA_trans.getOrigin(); 828 btVector3 projA = ax1 * relA.dot(ax1); 829 btVector3 orthoA = relA - projA; 830 btVector3 totalDist = projA - projB; 831 // get offset vectors relA and relB 832 relA = orthoA + totalDist * factA; 833 relB = orthoB - totalDist * factB; 834 // now choose average ortho to hinge axis 835 p = orthoB * factA + orthoA * factB; 836 btScalar len2 = p.length2(); 837 if(len2 > SIMD_EPSILON) 838 { 839 p /= btSqrt(len2); 840 } 841 else 842 { 843 p = trA.getBasis().getColumn(1); 844 } 845 // make one more ortho 846 q = ax1.cross(p); 847 // fill three rows 848 tmpA = relA.cross(p); 849 tmpB = relB.cross(p); 850 for (i=0; i<3; i++) info->m_J1angularAxis[s0+i] = tmpA[i]; 851 for (i=0; i<3; i++) info->m_J2angularAxis[s0+i] = -tmpB[i]; 852 tmpA = relA.cross(q); 853 tmpB = relB.cross(q); 854 if(hasStaticBody && getSolveLimit()) 855 { // to make constraint between static and dynamic objects more rigid 856 // remove wA (or wB) from equation if angular limit is hit 857 tmpB *= factB; 858 tmpA *= factA; 859 } 860 for (i=0; i<3; i++) info->m_J1angularAxis[s1+i] = tmpA[i]; 861 for (i=0; i<3; i++) info->m_J2angularAxis[s1+i] = -tmpB[i]; 862 tmpA = relA.cross(ax1); 863 tmpB = relB.cross(ax1); 864 if(hasStaticBody) 865 { // to make constraint between static and dynamic objects more rigid 866 // remove wA (or wB) from equation 867 tmpB *= factB; 868 tmpA *= factA; 869 } 870 for (i=0; i<3; i++) info->m_J1angularAxis[s2+i] = tmpA[i]; 871 for (i=0; i<3; i++) info->m_J2angularAxis[s2+i] = -tmpB[i]; 872 873 btScalar normalErp = (m_flags & BT_HINGE_FLAGS_ERP_NORM)? m_normalERP : info->erp; 874 btScalar k = info->fps * normalErp; 875 876 if (!m_angularOnly) 877 { 878 for (i=0; i<3; i++) info->m_J1linearAxis[s0+i] = p[i]; 879 for (i=0; i<3; i++) info->m_J1linearAxis[s1+i] = q[i]; 880 for (i=0; i<3; i++) info->m_J1linearAxis[s2+i] = ax1[i]; 881 882 for (i=0; i<3; i++) info->m_J2linearAxis[s0+i] = -p[i]; 883 for (i=0; i<3; i++) info->m_J2linearAxis[s1+i] = -q[i]; 884 for (i=0; i<3; i++) info->m_J2linearAxis[s2+i] = -ax1[i]; 885 886 // compute three elements of right hand side 887 888 btScalar rhs = k * p.dot(ofs); 889 info->m_constraintError[s0] = rhs; 890 rhs = k * q.dot(ofs); 891 info->m_constraintError[s1] = rhs; 892 rhs = k * ax1.dot(ofs); 893 info->m_constraintError[s2] = rhs; 894 } 895 // the hinge axis should be the only unconstrained 896 // rotational axis, the angular velocity of the two bodies perpendicular to 897 // the hinge axis should be equal. thus the constraint equations are 898 // p*w1 - p*w2 = 0 899 // q*w1 - q*w2 = 0 900 // where p and q are unit vectors normal to the hinge axis, and w1 and w2 901 // are the angular velocity vectors of the two bodies. 902 int s3 = 3 * s; 903 int s4 = 4 * s; 904 info->m_J1angularAxis[s3 + 0] = p[0]; 905 info->m_J1angularAxis[s3 + 1] = p[1]; 906 info->m_J1angularAxis[s3 + 2] = p[2]; 907 info->m_J1angularAxis[s4 + 0] = q[0]; 908 info->m_J1angularAxis[s4 + 1] = q[1]; 909 info->m_J1angularAxis[s4 + 2] = q[2]; 910 911 info->m_J2angularAxis[s3 + 0] = -p[0]; 912 info->m_J2angularAxis[s3 + 1] = -p[1]; 913 info->m_J2angularAxis[s3 + 2] = -p[2]; 914 info->m_J2angularAxis[s4 + 0] = -q[0]; 915 info->m_J2angularAxis[s4 + 1] = -q[1]; 916 info->m_J2angularAxis[s4 + 2] = -q[2]; 917 // compute the right hand side of the constraint equation. set relative 918 // body velocities along p and q to bring the hinge back into alignment. 919 // if ax1A,ax1B are the unit length hinge axes as computed from bodyA and 920 // bodyB, we need to rotate both bodies along the axis u = (ax1 x ax2). 921 // if "theta" is the angle between ax1 and ax2, we need an angular velocity 922 // along u to cover angle erp*theta in one step : 923 // |angular_velocity| = angle/time = erp*theta / stepsize 924 // = (erp*fps) * theta 925 // angular_velocity = |angular_velocity| * (ax1 x ax2) / |ax1 x ax2| 926 // = (erp*fps) * theta * (ax1 x ax2) / sin(theta) 927 // ...as ax1 and ax2 are unit length. if theta is smallish, 928 // theta ~= sin(theta), so 929 // angular_velocity = (erp*fps) * (ax1 x ax2) 930 // ax1 x ax2 is in the plane space of ax1, so we project the angular 931 // velocity to p and q to find the right hand side. 932 k = info->fps * normalErp;//?? 933 934 btVector3 u = ax1A.cross(ax1B); 935 info->m_constraintError[s3] = k * u.dot(p); 936 info->m_constraintError[s4] = k * u.dot(q); 937 #endif 938 // check angular limits 939 nrow = 4; // last filled row 940 int srow; 941 btScalar limit_err = btScalar(0.0); 942 int limit = 0; 943 if(getSolveLimit()) 944 { 945 #ifdef _BT_USE_CENTER_LIMIT_ 946 limit_err = m_limit.getCorrection() * m_referenceSign; 947 #else 948 limit_err = m_correction * m_referenceSign; 949 #endif 950 limit = (limit_err > btScalar(0.0)) ? 1 : 2; 951 952 } 953 // if the hinge has joint limits or motor, add in the extra row 954 int powered = 0; 955 if(getEnableAngularMotor()) 956 { 957 powered = 1; 958 } 959 if(limit || powered) 960 { 961 nrow++; 962 srow = nrow * info->rowskip; 963 info->m_J1angularAxis[srow+0] = ax1[0]; 964 info->m_J1angularAxis[srow+1] = ax1[1]; 965 info->m_J1angularAxis[srow+2] = ax1[2]; 966 967 info->m_J2angularAxis[srow+0] = -ax1[0]; 968 info->m_J2angularAxis[srow+1] = -ax1[1]; 969 info->m_J2angularAxis[srow+2] = -ax1[2]; 970 971 btScalar lostop = getLowerLimit(); 972 btScalar histop = getUpperLimit(); 973 if(limit && (lostop == histop)) 974 { // the joint motor is ineffective 975 powered = 0; 976 } 977 info->m_constraintError[srow] = btScalar(0.0f); 978 btScalar currERP = (m_flags & BT_HINGE_FLAGS_ERP_STOP) ? m_stopERP : normalErp; 979 if(powered) 980 { 981 if(m_flags & BT_HINGE_FLAGS_CFM_NORM) 982 { 983 info->cfm[srow] = m_normalCFM; 984 } 985 btScalar mot_fact = getMotorFactor(m_hingeAngle, lostop, histop, m_motorTargetVelocity, info->fps * currERP); 986 info->m_constraintError[srow] += mot_fact * m_motorTargetVelocity * m_referenceSign; 987 info->m_lowerLimit[srow] = - m_maxMotorImpulse; 988 info->m_upperLimit[srow] = m_maxMotorImpulse; 989 } 990 if(limit) 991 { 992 k = info->fps * currERP; 993 info->m_constraintError[srow] += k * limit_err; 994 if(m_flags & BT_HINGE_FLAGS_CFM_STOP) 995 { 996 info->cfm[srow] = m_stopCFM; 997 } 998 if(lostop == histop) 999 { 1000 // limited low and high simultaneously 1001 info->m_lowerLimit[srow] = -SIMD_INFINITY; 1002 info->m_upperLimit[srow] = SIMD_INFINITY; 1003 } 1004 else if(limit == 1) 1005 { // low limit 1006 info->m_lowerLimit[srow] = 0; 1007 info->m_upperLimit[srow] = SIMD_INFINITY; 1008 } 1009 else 1010 { // high limit 1011 info->m_lowerLimit[srow] = -SIMD_INFINITY; 1012 info->m_upperLimit[srow] = 0; 1013 } 1014 // bounce (we'll use slider parameter abs(1.0 - m_dampingLimAng) for that) 1015 #ifdef _BT_USE_CENTER_LIMIT_ 1016 btScalar bounce = m_limit.getRelaxationFactor(); 1017 #else 1018 btScalar bounce = m_relaxationFactor; 1019 #endif 1020 if(bounce > btScalar(0.0)) 1021 { 1022 btScalar vel = angVelA.dot(ax1); 1023 vel -= angVelB.dot(ax1); 1024 // only apply bounce if the velocity is incoming, and if the 1025 // resulting c[] exceeds what we already have. 1026 if(limit == 1) 1027 { // low limit 1028 if(vel < 0) 1029 { 1030 btScalar newc = -bounce * vel; 1031 if(newc > info->m_constraintError[srow]) 1032 { 1033 info->m_constraintError[srow] = newc; 1034 } 1035 } 1036 } 1037 else 1038 { // high limit - all those computations are reversed 1039 if(vel > 0) 1040 { 1041 btScalar newc = -bounce * vel; 1042 if(newc < info->m_constraintError[srow]) 1043 { 1044 info->m_constraintError[srow] = newc; 1045 } 1046 } 1047 } 1048 } 1049 #ifdef _BT_USE_CENTER_LIMIT_ 1050 info->m_constraintError[srow] *= m_limit.getBiasFactor(); 1051 #else 1052 info->m_constraintError[srow] *= m_biasFactor; 1053 #endif 1054 } // if(limit) 1055 } // if angular limit or powered 1056 } 1057 1058 1059 ///override the default global value of a parameter (such as ERP or CFM), optionally provide the axis (0..5). 1060 ///If no axis is provided, it uses the default axis for this constraint. 1061 void btHingeConstraint::setParam(int num, btScalar value, int axis) 1062 { 1063 if((axis == -1) || (axis == 5)) 1064 { 1065 switch(num) 1066 { 1067 case BT_CONSTRAINT_STOP_ERP : 1068 m_stopERP = value; 1069 m_flags |= BT_HINGE_FLAGS_ERP_STOP; 1070 break; 1071 case BT_CONSTRAINT_STOP_CFM : 1072 m_stopCFM = value; 1073 m_flags |= BT_HINGE_FLAGS_CFM_STOP; 1074 break; 1075 case BT_CONSTRAINT_CFM : 1076 m_normalCFM = value; 1077 m_flags |= BT_HINGE_FLAGS_CFM_NORM; 1078 break; 1079 case BT_CONSTRAINT_ERP: 1080 m_normalERP = value; 1081 m_flags |= BT_HINGE_FLAGS_ERP_NORM; 1082 break; 1083 default : 1084 btAssertConstrParams(0); 1085 } 1086 } 1087 else 1088 { 1089 btAssertConstrParams(0); 1090 } 1091 } 1092 1093 ///return the local value of parameter 1094 btScalar btHingeConstraint::getParam(int num, int axis) const 1095 { 1096 btScalar retVal = 0; 1097 if((axis == -1) || (axis == 5)) 1098 { 1099 switch(num) 1100 { 1101 case BT_CONSTRAINT_STOP_ERP : 1102 btAssertConstrParams(m_flags & BT_HINGE_FLAGS_ERP_STOP); 1103 retVal = m_stopERP; 1104 break; 1105 case BT_CONSTRAINT_STOP_CFM : 1106 btAssertConstrParams(m_flags & BT_HINGE_FLAGS_CFM_STOP); 1107 retVal = m_stopCFM; 1108 break; 1109 case BT_CONSTRAINT_CFM : 1110 btAssertConstrParams(m_flags & BT_HINGE_FLAGS_CFM_NORM); 1111 retVal = m_normalCFM; 1112 break; 1113 case BT_CONSTRAINT_ERP: 1114 btAssertConstrParams(m_flags & BT_HINGE_FLAGS_ERP_NORM); 1115 retVal = m_normalERP; 1116 break; 1117 default : 1118 btAssertConstrParams(0); 1119 } 1120 } 1121 else 1122 { 1123 btAssertConstrParams(0); 1124 } 1125 return retVal; 1126 } 1127 1128 1129