|
Bullet Collision Detection & Physics Library
|
00001 /* 00002 Bullet Continuous Collision Detection and Physics Library 00003 Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 00004 00005 This software is provided 'as-is', without any express or implied warranty. 00006 In no event will the authors be held liable for any damages arising from the use of this software. 00007 Permission is granted to anyone to use this software for any purpose, 00008 including commercial applications, and to alter it and redistribute it freely, 00009 subject to the following restrictions: 00010 00011 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. 00012 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 00013 3. This notice may not be removed or altered from any source distribution. 00014 */ 00015 /* 00016 2007-09-09 00017 Refactored by Francisco Le?n 00018 email: projectileman@yahoo.com 00019 http://gimpact.sf.net 00020 */ 00021 00022 #include "btGeneric6DofConstraint.h" 00023 #include "BulletDynamics/Dynamics/btRigidBody.h" 00024 #include "LinearMath/btTransformUtil.h" 00025 #include "LinearMath/btTransformUtil.h" 00026 #include <new> 00027 00028 00029 00030 #define D6_USE_OBSOLETE_METHOD false 00031 #define D6_USE_FRAME_OFFSET true 00032 00033 00034 00035 00036 00037 00038 btGeneric6DofConstraint::btGeneric6DofConstraint(btRigidBody& rbA, btRigidBody& rbB, const btTransform& frameInA, const btTransform& frameInB, bool useLinearReferenceFrameA) 00039 : btTypedConstraint(D6_CONSTRAINT_TYPE, rbA, rbB) 00040 , m_frameInA(frameInA) 00041 , m_frameInB(frameInB), 00042 m_useLinearReferenceFrameA(useLinearReferenceFrameA), 00043 m_useOffsetForConstraintFrame(D6_USE_FRAME_OFFSET), 00044 m_flags(0), 00045 m_useSolveConstraintObsolete(D6_USE_OBSOLETE_METHOD) 00046 { 00047 calculateTransforms(); 00048 } 00049 00050 00051 00052 btGeneric6DofConstraint::btGeneric6DofConstraint(btRigidBody& rbB, const btTransform& frameInB, bool useLinearReferenceFrameB) 00053 : btTypedConstraint(D6_CONSTRAINT_TYPE, getFixedBody(), rbB), 00054 m_frameInB(frameInB), 00055 m_useLinearReferenceFrameA(useLinearReferenceFrameB), 00056 m_useOffsetForConstraintFrame(D6_USE_FRAME_OFFSET), 00057 m_flags(0), 00058 m_useSolveConstraintObsolete(false) 00059 { 00061 m_frameInA = rbB.getCenterOfMassTransform() * m_frameInB; 00062 calculateTransforms(); 00063 } 00064 00065 00066 00067 00068 #define GENERIC_D6_DISABLE_WARMSTARTING 1 00069 00070 00071 00072 btScalar btGetMatrixElem(const btMatrix3x3& mat, int index); 00073 btScalar btGetMatrixElem(const btMatrix3x3& mat, int index) 00074 { 00075 int i = index%3; 00076 int j = index/3; 00077 return mat[i][j]; 00078 } 00079 00080 00081 00083 bool matrixToEulerXYZ(const btMatrix3x3& mat,btVector3& xyz); 00084 bool matrixToEulerXYZ(const btMatrix3x3& mat,btVector3& xyz) 00085 { 00086 // // rot = cy*cz -cy*sz sy 00087 // // cz*sx*sy+cx*sz cx*cz-sx*sy*sz -cy*sx 00088 // // -cx*cz*sy+sx*sz cz*sx+cx*sy*sz cx*cy 00089 // 00090 00091 btScalar fi = btGetMatrixElem(mat,2); 00092 if (fi < btScalar(1.0f)) 00093 { 00094 if (fi > btScalar(-1.0f)) 00095 { 00096 xyz[0] = btAtan2(-btGetMatrixElem(mat,5),btGetMatrixElem(mat,8)); 00097 xyz[1] = btAsin(btGetMatrixElem(mat,2)); 00098 xyz[2] = btAtan2(-btGetMatrixElem(mat,1),btGetMatrixElem(mat,0)); 00099 return true; 00100 } 00101 else 00102 { 00103 // WARNING. Not unique. XA - ZA = -atan2(r10,r11) 00104 xyz[0] = -btAtan2(btGetMatrixElem(mat,3),btGetMatrixElem(mat,4)); 00105 xyz[1] = -SIMD_HALF_PI; 00106 xyz[2] = btScalar(0.0); 00107 return false; 00108 } 00109 } 00110 else 00111 { 00112 // WARNING. Not unique. XAngle + ZAngle = atan2(r10,r11) 00113 xyz[0] = btAtan2(btGetMatrixElem(mat,3),btGetMatrixElem(mat,4)); 00114 xyz[1] = SIMD_HALF_PI; 00115 xyz[2] = 0.0; 00116 } 00117 return false; 00118 } 00119 00121 00122 int btRotationalLimitMotor::testLimitValue(btScalar test_value) 00123 { 00124 if(m_loLimit>m_hiLimit) 00125 { 00126 m_currentLimit = 0;//Free from violation 00127 return 0; 00128 } 00129 if (test_value < m_loLimit) 00130 { 00131 m_currentLimit = 1;//low limit violation 00132 m_currentLimitError = test_value - m_loLimit; 00133 if(m_currentLimitError>SIMD_PI) 00134 m_currentLimitError-=SIMD_2_PI; 00135 else if(m_currentLimitError<-SIMD_PI) 00136 m_currentLimitError+=SIMD_2_PI; 00137 return 1; 00138 } 00139 else if (test_value> m_hiLimit) 00140 { 00141 m_currentLimit = 2;//High limit violation 00142 m_currentLimitError = test_value - m_hiLimit; 00143 if(m_currentLimitError>SIMD_PI) 00144 m_currentLimitError-=SIMD_2_PI; 00145 else if(m_currentLimitError<-SIMD_PI) 00146 m_currentLimitError+=SIMD_2_PI; 00147 return 2; 00148 }; 00149 00150 m_currentLimit = 0;//Free from violation 00151 return 0; 00152 00153 } 00154 00155 00156 00157 btScalar btRotationalLimitMotor::solveAngularLimits( 00158 btScalar timeStep,btVector3& axis,btScalar jacDiagABInv, 00159 btRigidBody * body0, btRigidBody * body1 ) 00160 { 00161 if (needApplyTorques()==false) return 0.0f; 00162 00163 btScalar target_velocity = m_targetVelocity; 00164 btScalar maxMotorForce = m_maxMotorForce; 00165 00166 //current error correction 00167 if (m_currentLimit!=0) 00168 { 00169 target_velocity = -m_stopERP*m_currentLimitError/(timeStep); 00170 maxMotorForce = m_maxLimitForce; 00171 } 00172 00173 maxMotorForce *= timeStep; 00174 00175 // current velocity difference 00176 00177 btVector3 angVelA; 00178 body0->internalGetAngularVelocity(angVelA); 00179 btVector3 angVelB; 00180 body1->internalGetAngularVelocity(angVelB); 00181 00182 btVector3 vel_diff; 00183 vel_diff = angVelA-angVelB; 00184 00185 00186 00187 btScalar rel_vel = axis.dot(vel_diff); 00188 00189 // correction velocity 00190 btScalar motor_relvel = m_limitSoftness*(target_velocity - m_damping*rel_vel); 00191 00192 00193 if ( motor_relvel < SIMD_EPSILON && motor_relvel > -SIMD_EPSILON ) 00194 { 00195 return 0.0f;//no need for applying force 00196 } 00197 00198 00199 // correction impulse 00200 btScalar unclippedMotorImpulse = (1+m_bounce)*motor_relvel*jacDiagABInv; 00201 00202 // clip correction impulse 00203 btScalar clippedMotorImpulse; 00204 00206 if (unclippedMotorImpulse>0.0f) 00207 { 00208 clippedMotorImpulse = unclippedMotorImpulse > maxMotorForce? maxMotorForce: unclippedMotorImpulse; 00209 } 00210 else 00211 { 00212 clippedMotorImpulse = unclippedMotorImpulse < -maxMotorForce ? -maxMotorForce: unclippedMotorImpulse; 00213 } 00214 00215 00216 // sort with accumulated impulses 00217 btScalar lo = btScalar(-BT_LARGE_FLOAT); 00218 btScalar hi = btScalar(BT_LARGE_FLOAT); 00219 00220 btScalar oldaccumImpulse = m_accumulatedImpulse; 00221 btScalar sum = oldaccumImpulse + clippedMotorImpulse; 00222 m_accumulatedImpulse = sum > hi ? btScalar(0.) : sum < lo ? btScalar(0.) : sum; 00223 00224 clippedMotorImpulse = m_accumulatedImpulse - oldaccumImpulse; 00225 00226 btVector3 motorImp = clippedMotorImpulse * axis; 00227 00228 //body0->applyTorqueImpulse(motorImp); 00229 //body1->applyTorqueImpulse(-motorImp); 00230 00231 body0->internalApplyImpulse(btVector3(0,0,0), body0->getInvInertiaTensorWorld()*axis,clippedMotorImpulse); 00232 body1->internalApplyImpulse(btVector3(0,0,0), body1->getInvInertiaTensorWorld()*axis,-clippedMotorImpulse); 00233 00234 00235 return clippedMotorImpulse; 00236 00237 00238 } 00239 00241 00242 00243 00244 00246 00247 00248 int btTranslationalLimitMotor::testLimitValue(int limitIndex, btScalar test_value) 00249 { 00250 btScalar loLimit = m_lowerLimit[limitIndex]; 00251 btScalar hiLimit = m_upperLimit[limitIndex]; 00252 if(loLimit > hiLimit) 00253 { 00254 m_currentLimit[limitIndex] = 0;//Free from violation 00255 m_currentLimitError[limitIndex] = btScalar(0.f); 00256 return 0; 00257 } 00258 00259 if (test_value < loLimit) 00260 { 00261 m_currentLimit[limitIndex] = 2;//low limit violation 00262 m_currentLimitError[limitIndex] = test_value - loLimit; 00263 return 2; 00264 } 00265 else if (test_value> hiLimit) 00266 { 00267 m_currentLimit[limitIndex] = 1;//High limit violation 00268 m_currentLimitError[limitIndex] = test_value - hiLimit; 00269 return 1; 00270 }; 00271 00272 m_currentLimit[limitIndex] = 0;//Free from violation 00273 m_currentLimitError[limitIndex] = btScalar(0.f); 00274 return 0; 00275 } 00276 00277 00278 00279 btScalar btTranslationalLimitMotor::solveLinearAxis( 00280 btScalar timeStep, 00281 btScalar jacDiagABInv, 00282 btRigidBody& body1,const btVector3 &pointInA, 00283 btRigidBody& body2,const btVector3 &pointInB, 00284 int limit_index, 00285 const btVector3 & axis_normal_on_a, 00286 const btVector3 & anchorPos) 00287 { 00288 00290 // btVector3 rel_pos1 = pointInA - body1.getCenterOfMassPosition(); 00291 // btVector3 rel_pos2 = pointInB - body2.getCenterOfMassPosition(); 00292 btVector3 rel_pos1 = anchorPos - body1.getCenterOfMassPosition(); 00293 btVector3 rel_pos2 = anchorPos - body2.getCenterOfMassPosition(); 00294 00295 btVector3 vel1; 00296 body1.internalGetVelocityInLocalPointObsolete(rel_pos1,vel1); 00297 btVector3 vel2; 00298 body2.internalGetVelocityInLocalPointObsolete(rel_pos2,vel2); 00299 btVector3 vel = vel1 - vel2; 00300 00301 btScalar rel_vel = axis_normal_on_a.dot(vel); 00302 00303 00304 00306 00307 //positional error (zeroth order error) 00308 btScalar depth = -(pointInA - pointInB).dot(axis_normal_on_a); 00309 btScalar lo = btScalar(-BT_LARGE_FLOAT); 00310 btScalar hi = btScalar(BT_LARGE_FLOAT); 00311 00312 btScalar minLimit = m_lowerLimit[limit_index]; 00313 btScalar maxLimit = m_upperLimit[limit_index]; 00314 00315 //handle the limits 00316 if (minLimit < maxLimit) 00317 { 00318 { 00319 if (depth > maxLimit) 00320 { 00321 depth -= maxLimit; 00322 lo = btScalar(0.); 00323 00324 } 00325 else 00326 { 00327 if (depth < minLimit) 00328 { 00329 depth -= minLimit; 00330 hi = btScalar(0.); 00331 } 00332 else 00333 { 00334 return 0.0f; 00335 } 00336 } 00337 } 00338 } 00339 00340 btScalar normalImpulse= m_limitSoftness*(m_restitution*depth/timeStep - m_damping*rel_vel) * jacDiagABInv; 00341 00342 00343 00344 00345 btScalar oldNormalImpulse = m_accumulatedImpulse[limit_index]; 00346 btScalar sum = oldNormalImpulse + normalImpulse; 00347 m_accumulatedImpulse[limit_index] = sum > hi ? btScalar(0.) : sum < lo ? btScalar(0.) : sum; 00348 normalImpulse = m_accumulatedImpulse[limit_index] - oldNormalImpulse; 00349 00350 btVector3 impulse_vector = axis_normal_on_a * normalImpulse; 00351 //body1.applyImpulse( impulse_vector, rel_pos1); 00352 //body2.applyImpulse(-impulse_vector, rel_pos2); 00353 00354 btVector3 ftorqueAxis1 = rel_pos1.cross(axis_normal_on_a); 00355 btVector3 ftorqueAxis2 = rel_pos2.cross(axis_normal_on_a); 00356 body1.internalApplyImpulse(axis_normal_on_a*body1.getInvMass(), body1.getInvInertiaTensorWorld()*ftorqueAxis1,normalImpulse); 00357 body2.internalApplyImpulse(axis_normal_on_a*body2.getInvMass(), body2.getInvInertiaTensorWorld()*ftorqueAxis2,-normalImpulse); 00358 00359 00360 00361 00362 return normalImpulse; 00363 } 00364 00366 00367 void btGeneric6DofConstraint::calculateAngleInfo() 00368 { 00369 btMatrix3x3 relative_frame = m_calculatedTransformA.getBasis().inverse()*m_calculatedTransformB.getBasis(); 00370 matrixToEulerXYZ(relative_frame,m_calculatedAxisAngleDiff); 00371 // in euler angle mode we do not actually constrain the angular velocity 00372 // along the axes axis[0] and axis[2] (although we do use axis[1]) : 00373 // 00374 // to get constrain w2-w1 along ...not 00375 // ------ --------------------- ------ 00376 // d(angle[0])/dt = 0 ax[1] x ax[2] ax[0] 00377 // d(angle[1])/dt = 0 ax[1] 00378 // d(angle[2])/dt = 0 ax[0] x ax[1] ax[2] 00379 // 00380 // constraining w2-w1 along an axis 'a' means that a'*(w2-w1)=0. 00381 // to prove the result for angle[0], write the expression for angle[0] from 00382 // GetInfo1 then take the derivative. to prove this for angle[2] it is 00383 // easier to take the euler rate expression for d(angle[2])/dt with respect 00384 // to the components of w and set that to 0. 00385 btVector3 axis0 = m_calculatedTransformB.getBasis().getColumn(0); 00386 btVector3 axis2 = m_calculatedTransformA.getBasis().getColumn(2); 00387 00388 m_calculatedAxis[1] = axis2.cross(axis0); 00389 m_calculatedAxis[0] = m_calculatedAxis[1].cross(axis2); 00390 m_calculatedAxis[2] = axis0.cross(m_calculatedAxis[1]); 00391 00392 m_calculatedAxis[0].normalize(); 00393 m_calculatedAxis[1].normalize(); 00394 m_calculatedAxis[2].normalize(); 00395 00396 } 00397 00398 void btGeneric6DofConstraint::calculateTransforms() 00399 { 00400 calculateTransforms(m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform()); 00401 } 00402 00403 void btGeneric6DofConstraint::calculateTransforms(const btTransform& transA,const btTransform& transB) 00404 { 00405 m_calculatedTransformA = transA * m_frameInA; 00406 m_calculatedTransformB = transB * m_frameInB; 00407 calculateLinearInfo(); 00408 calculateAngleInfo(); 00409 if(m_useOffsetForConstraintFrame) 00410 { // get weight factors depending on masses 00411 btScalar miA = getRigidBodyA().getInvMass(); 00412 btScalar miB = getRigidBodyB().getInvMass(); 00413 m_hasStaticBody = (miA < SIMD_EPSILON) || (miB < SIMD_EPSILON); 00414 btScalar miS = miA + miB; 00415 if(miS > btScalar(0.f)) 00416 { 00417 m_factA = miB / miS; 00418 } 00419 else 00420 { 00421 m_factA = btScalar(0.5f); 00422 } 00423 m_factB = btScalar(1.0f) - m_factA; 00424 } 00425 } 00426 00427 00428 00429 void btGeneric6DofConstraint::buildLinearJacobian( 00430 btJacobianEntry & jacLinear,const btVector3 & normalWorld, 00431 const btVector3 & pivotAInW,const btVector3 & pivotBInW) 00432 { 00433 new (&jacLinear) btJacobianEntry( 00434 m_rbA.getCenterOfMassTransform().getBasis().transpose(), 00435 m_rbB.getCenterOfMassTransform().getBasis().transpose(), 00436 pivotAInW - m_rbA.getCenterOfMassPosition(), 00437 pivotBInW - m_rbB.getCenterOfMassPosition(), 00438 normalWorld, 00439 m_rbA.getInvInertiaDiagLocal(), 00440 m_rbA.getInvMass(), 00441 m_rbB.getInvInertiaDiagLocal(), 00442 m_rbB.getInvMass()); 00443 } 00444 00445 00446 00447 void btGeneric6DofConstraint::buildAngularJacobian( 00448 btJacobianEntry & jacAngular,const btVector3 & jointAxisW) 00449 { 00450 new (&jacAngular) btJacobianEntry(jointAxisW, 00451 m_rbA.getCenterOfMassTransform().getBasis().transpose(), 00452 m_rbB.getCenterOfMassTransform().getBasis().transpose(), 00453 m_rbA.getInvInertiaDiagLocal(), 00454 m_rbB.getInvInertiaDiagLocal()); 00455 00456 } 00457 00458 00459 00460 bool btGeneric6DofConstraint::testAngularLimitMotor(int axis_index) 00461 { 00462 btScalar angle = m_calculatedAxisAngleDiff[axis_index]; 00463 angle = btAdjustAngleToLimits(angle, m_angularLimits[axis_index].m_loLimit, m_angularLimits[axis_index].m_hiLimit); 00464 m_angularLimits[axis_index].m_currentPosition = angle; 00465 //test limits 00466 m_angularLimits[axis_index].testLimitValue(angle); 00467 return m_angularLimits[axis_index].needApplyTorques(); 00468 } 00469 00470 00471 00472 void btGeneric6DofConstraint::buildJacobian() 00473 { 00474 #ifndef __SPU__ 00475 if (m_useSolveConstraintObsolete) 00476 { 00477 00478 // Clear accumulated impulses for the next simulation step 00479 m_linearLimits.m_accumulatedImpulse.setValue(btScalar(0.), btScalar(0.), btScalar(0.)); 00480 int i; 00481 for(i = 0; i < 3; i++) 00482 { 00483 m_angularLimits[i].m_accumulatedImpulse = btScalar(0.); 00484 } 00485 //calculates transform 00486 calculateTransforms(m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform()); 00487 00488 // const btVector3& pivotAInW = m_calculatedTransformA.getOrigin(); 00489 // const btVector3& pivotBInW = m_calculatedTransformB.getOrigin(); 00490 calcAnchorPos(); 00491 btVector3 pivotAInW = m_AnchorPos; 00492 btVector3 pivotBInW = m_AnchorPos; 00493 00494 // not used here 00495 // btVector3 rel_pos1 = pivotAInW - m_rbA.getCenterOfMassPosition(); 00496 // btVector3 rel_pos2 = pivotBInW - m_rbB.getCenterOfMassPosition(); 00497 00498 btVector3 normalWorld; 00499 //linear part 00500 for (i=0;i<3;i++) 00501 { 00502 if (m_linearLimits.isLimited(i)) 00503 { 00504 if (m_useLinearReferenceFrameA) 00505 normalWorld = m_calculatedTransformA.getBasis().getColumn(i); 00506 else 00507 normalWorld = m_calculatedTransformB.getBasis().getColumn(i); 00508 00509 buildLinearJacobian( 00510 m_jacLinear[i],normalWorld , 00511 pivotAInW,pivotBInW); 00512 00513 } 00514 } 00515 00516 // angular part 00517 for (i=0;i<3;i++) 00518 { 00519 //calculates error angle 00520 if (testAngularLimitMotor(i)) 00521 { 00522 normalWorld = this->getAxis(i); 00523 // Create angular atom 00524 buildAngularJacobian(m_jacAng[i],normalWorld); 00525 } 00526 } 00527 00528 } 00529 #endif //__SPU__ 00530 00531 } 00532 00533 00534 void btGeneric6DofConstraint::getInfo1 (btConstraintInfo1* info) 00535 { 00536 if (m_useSolveConstraintObsolete) 00537 { 00538 info->m_numConstraintRows = 0; 00539 info->nub = 0; 00540 } else 00541 { 00542 //prepare constraint 00543 calculateTransforms(m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform()); 00544 info->m_numConstraintRows = 0; 00545 info->nub = 6; 00546 int i; 00547 //test linear limits 00548 for(i = 0; i < 3; i++) 00549 { 00550 if(m_linearLimits.needApplyForce(i)) 00551 { 00552 info->m_numConstraintRows++; 00553 info->nub--; 00554 } 00555 } 00556 //test angular limits 00557 for (i=0;i<3 ;i++ ) 00558 { 00559 if(testAngularLimitMotor(i)) 00560 { 00561 info->m_numConstraintRows++; 00562 info->nub--; 00563 } 00564 } 00565 } 00566 } 00567 00568 void btGeneric6DofConstraint::getInfo1NonVirtual (btConstraintInfo1* info) 00569 { 00570 if (m_useSolveConstraintObsolete) 00571 { 00572 info->m_numConstraintRows = 0; 00573 info->nub = 0; 00574 } else 00575 { 00576 //pre-allocate all 6 00577 info->m_numConstraintRows = 6; 00578 info->nub = 0; 00579 } 00580 } 00581 00582 00583 void btGeneric6DofConstraint::getInfo2 (btConstraintInfo2* info) 00584 { 00585 btAssert(!m_useSolveConstraintObsolete); 00586 00587 const btTransform& transA = m_rbA.getCenterOfMassTransform(); 00588 const btTransform& transB = m_rbB.getCenterOfMassTransform(); 00589 const btVector3& linVelA = m_rbA.getLinearVelocity(); 00590 const btVector3& linVelB = m_rbB.getLinearVelocity(); 00591 const btVector3& angVelA = m_rbA.getAngularVelocity(); 00592 const btVector3& angVelB = m_rbB.getAngularVelocity(); 00593 00594 if(m_useOffsetForConstraintFrame) 00595 { // for stability better to solve angular limits first 00596 int row = setAngularLimits(info, 0,transA,transB,linVelA,linVelB,angVelA,angVelB); 00597 setLinearLimits(info, row, transA,transB,linVelA,linVelB,angVelA,angVelB); 00598 } 00599 else 00600 { // leave old version for compatibility 00601 int row = setLinearLimits(info, 0, transA,transB,linVelA,linVelB,angVelA,angVelB); 00602 setAngularLimits(info, row,transA,transB,linVelA,linVelB,angVelA,angVelB); 00603 } 00604 00605 } 00606 00607 00608 void btGeneric6DofConstraint::getInfo2NonVirtual (btConstraintInfo2* info, const btTransform& transA,const btTransform& transB,const btVector3& linVelA,const btVector3& linVelB,const btVector3& angVelA,const btVector3& angVelB) 00609 { 00610 00611 btAssert(!m_useSolveConstraintObsolete); 00612 //prepare constraint 00613 calculateTransforms(transA,transB); 00614 00615 int i; 00616 for (i=0;i<3 ;i++ ) 00617 { 00618 testAngularLimitMotor(i); 00619 } 00620 00621 if(m_useOffsetForConstraintFrame) 00622 { // for stability better to solve angular limits first 00623 int row = setAngularLimits(info, 0,transA,transB,linVelA,linVelB,angVelA,angVelB); 00624 setLinearLimits(info, row, transA,transB,linVelA,linVelB,angVelA,angVelB); 00625 } 00626 else 00627 { // leave old version for compatibility 00628 int row = setLinearLimits(info, 0, transA,transB,linVelA,linVelB,angVelA,angVelB); 00629 setAngularLimits(info, row,transA,transB,linVelA,linVelB,angVelA,angVelB); 00630 } 00631 } 00632 00633 00634 00635 int btGeneric6DofConstraint::setLinearLimits(btConstraintInfo2* info, int row, const btTransform& transA,const btTransform& transB,const btVector3& linVelA,const btVector3& linVelB,const btVector3& angVelA,const btVector3& angVelB) 00636 { 00637 // int row = 0; 00638 //solve linear limits 00639 btRotationalLimitMotor limot; 00640 for (int i=0;i<3 ;i++ ) 00641 { 00642 if(m_linearLimits.needApplyForce(i)) 00643 { // re-use rotational motor code 00644 limot.m_bounce = btScalar(0.f); 00645 limot.m_currentLimit = m_linearLimits.m_currentLimit[i]; 00646 limot.m_currentPosition = m_linearLimits.m_currentLinearDiff[i]; 00647 limot.m_currentLimitError = m_linearLimits.m_currentLimitError[i]; 00648 limot.m_damping = m_linearLimits.m_damping; 00649 limot.m_enableMotor = m_linearLimits.m_enableMotor[i]; 00650 limot.m_hiLimit = m_linearLimits.m_upperLimit[i]; 00651 limot.m_limitSoftness = m_linearLimits.m_limitSoftness; 00652 limot.m_loLimit = m_linearLimits.m_lowerLimit[i]; 00653 limot.m_maxLimitForce = btScalar(0.f); 00654 limot.m_maxMotorForce = m_linearLimits.m_maxMotorForce[i]; 00655 limot.m_targetVelocity = m_linearLimits.m_targetVelocity[i]; 00656 btVector3 axis = m_calculatedTransformA.getBasis().getColumn(i); 00657 int flags = m_flags >> (i * BT_6DOF_FLAGS_AXIS_SHIFT); 00658 limot.m_normalCFM = (flags & BT_6DOF_FLAGS_CFM_NORM) ? m_linearLimits.m_normalCFM[i] : info->cfm[0]; 00659 limot.m_stopCFM = (flags & BT_6DOF_FLAGS_CFM_STOP) ? m_linearLimits.m_stopCFM[i] : info->cfm[0]; 00660 limot.m_stopERP = (flags & BT_6DOF_FLAGS_ERP_STOP) ? m_linearLimits.m_stopERP[i] : info->erp; 00661 if(m_useOffsetForConstraintFrame) 00662 { 00663 int indx1 = (i + 1) % 3; 00664 int indx2 = (i + 2) % 3; 00665 int rotAllowed = 1; // rotations around orthos to current axis 00666 if(m_angularLimits[indx1].m_currentLimit && m_angularLimits[indx2].m_currentLimit) 00667 { 00668 rotAllowed = 0; 00669 } 00670 row += get_limit_motor_info2(&limot, transA,transB,linVelA,linVelB,angVelA,angVelB, info, row, axis, 0, rotAllowed); 00671 } 00672 else 00673 { 00674 row += get_limit_motor_info2(&limot, transA,transB,linVelA,linVelB,angVelA,angVelB, info, row, axis, 0); 00675 } 00676 } 00677 } 00678 return row; 00679 } 00680 00681 00682 00683 int btGeneric6DofConstraint::setAngularLimits(btConstraintInfo2 *info, int row_offset, const btTransform& transA,const btTransform& transB,const btVector3& linVelA,const btVector3& linVelB,const btVector3& angVelA,const btVector3& angVelB) 00684 { 00685 btGeneric6DofConstraint * d6constraint = this; 00686 int row = row_offset; 00687 //solve angular limits 00688 for (int i=0;i<3 ;i++ ) 00689 { 00690 if(d6constraint->getRotationalLimitMotor(i)->needApplyTorques()) 00691 { 00692 btVector3 axis = d6constraint->getAxis(i); 00693 int flags = m_flags >> ((i + 3) * BT_6DOF_FLAGS_AXIS_SHIFT); 00694 if(!(flags & BT_6DOF_FLAGS_CFM_NORM)) 00695 { 00696 m_angularLimits[i].m_normalCFM = info->cfm[0]; 00697 } 00698 if(!(flags & BT_6DOF_FLAGS_CFM_STOP)) 00699 { 00700 m_angularLimits[i].m_stopCFM = info->cfm[0]; 00701 } 00702 if(!(flags & BT_6DOF_FLAGS_ERP_STOP)) 00703 { 00704 m_angularLimits[i].m_stopERP = info->erp; 00705 } 00706 row += get_limit_motor_info2(d6constraint->getRotationalLimitMotor(i), 00707 transA,transB,linVelA,linVelB,angVelA,angVelB, info,row,axis,1); 00708 } 00709 } 00710 00711 return row; 00712 } 00713 00714 00715 00716 00717 void btGeneric6DofConstraint::updateRHS(btScalar timeStep) 00718 { 00719 (void)timeStep; 00720 00721 } 00722 00723 00724 void btGeneric6DofConstraint::setFrames(const btTransform& frameA, const btTransform& frameB) 00725 { 00726 m_frameInA = frameA; 00727 m_frameInB = frameB; 00728 buildJacobian(); 00729 calculateTransforms(); 00730 } 00731 00732 00733 00734 btVector3 btGeneric6DofConstraint::getAxis(int axis_index) const 00735 { 00736 return m_calculatedAxis[axis_index]; 00737 } 00738 00739 00740 btScalar btGeneric6DofConstraint::getRelativePivotPosition(int axisIndex) const 00741 { 00742 return m_calculatedLinearDiff[axisIndex]; 00743 } 00744 00745 00746 btScalar btGeneric6DofConstraint::getAngle(int axisIndex) const 00747 { 00748 return m_calculatedAxisAngleDiff[axisIndex]; 00749 } 00750 00751 00752 00753 void btGeneric6DofConstraint::calcAnchorPos(void) 00754 { 00755 btScalar imA = m_rbA.getInvMass(); 00756 btScalar imB = m_rbB.getInvMass(); 00757 btScalar weight; 00758 if(imB == btScalar(0.0)) 00759 { 00760 weight = btScalar(1.0); 00761 } 00762 else 00763 { 00764 weight = imA / (imA + imB); 00765 } 00766 const btVector3& pA = m_calculatedTransformA.getOrigin(); 00767 const btVector3& pB = m_calculatedTransformB.getOrigin(); 00768 m_AnchorPos = pA * weight + pB * (btScalar(1.0) - weight); 00769 return; 00770 } 00771 00772 00773 00774 void btGeneric6DofConstraint::calculateLinearInfo() 00775 { 00776 m_calculatedLinearDiff = m_calculatedTransformB.getOrigin() - m_calculatedTransformA.getOrigin(); 00777 m_calculatedLinearDiff = m_calculatedTransformA.getBasis().inverse() * m_calculatedLinearDiff; 00778 for(int i = 0; i < 3; i++) 00779 { 00780 m_linearLimits.m_currentLinearDiff[i] = m_calculatedLinearDiff[i]; 00781 m_linearLimits.testLimitValue(i, m_calculatedLinearDiff[i]); 00782 } 00783 } 00784 00785 00786 00787 int btGeneric6DofConstraint::get_limit_motor_info2( 00788 btRotationalLimitMotor * limot, 00789 const btTransform& transA,const btTransform& transB,const btVector3& linVelA,const btVector3& linVelB,const btVector3& angVelA,const btVector3& angVelB, 00790 btConstraintInfo2 *info, int row, btVector3& ax1, int rotational,int rotAllowed) 00791 { 00792 int srow = row * info->rowskip; 00793 int powered = limot->m_enableMotor; 00794 int limit = limot->m_currentLimit; 00795 if (powered || limit) 00796 { // if the joint is powered, or has joint limits, add in the extra row 00797 btScalar *J1 = rotational ? info->m_J1angularAxis : info->m_J1linearAxis; 00798 btScalar *J2 = rotational ? info->m_J2angularAxis : 0; 00799 J1[srow+0] = ax1[0]; 00800 J1[srow+1] = ax1[1]; 00801 J1[srow+2] = ax1[2]; 00802 if(rotational) 00803 { 00804 J2[srow+0] = -ax1[0]; 00805 J2[srow+1] = -ax1[1]; 00806 J2[srow+2] = -ax1[2]; 00807 } 00808 if((!rotational)) 00809 { 00810 if (m_useOffsetForConstraintFrame) 00811 { 00812 btVector3 tmpA, tmpB, relA, relB; 00813 // get vector from bodyB to frameB in WCS 00814 relB = m_calculatedTransformB.getOrigin() - transB.getOrigin(); 00815 // get its projection to constraint axis 00816 btVector3 projB = ax1 * relB.dot(ax1); 00817 // get vector directed from bodyB to constraint axis (and orthogonal to it) 00818 btVector3 orthoB = relB - projB; 00819 // same for bodyA 00820 relA = m_calculatedTransformA.getOrigin() - transA.getOrigin(); 00821 btVector3 projA = ax1 * relA.dot(ax1); 00822 btVector3 orthoA = relA - projA; 00823 // get desired offset between frames A and B along constraint axis 00824 btScalar desiredOffs = limot->m_currentPosition - limot->m_currentLimitError; 00825 // desired vector from projection of center of bodyA to projection of center of bodyB to constraint axis 00826 btVector3 totalDist = projA + ax1 * desiredOffs - projB; 00827 // get offset vectors relA and relB 00828 relA = orthoA + totalDist * m_factA; 00829 relB = orthoB - totalDist * m_factB; 00830 tmpA = relA.cross(ax1); 00831 tmpB = relB.cross(ax1); 00832 if(m_hasStaticBody && (!rotAllowed)) 00833 { 00834 tmpA *= m_factA; 00835 tmpB *= m_factB; 00836 } 00837 int i; 00838 for (i=0; i<3; i++) info->m_J1angularAxis[srow+i] = tmpA[i]; 00839 for (i=0; i<3; i++) info->m_J2angularAxis[srow+i] = -tmpB[i]; 00840 } else 00841 { 00842 btVector3 ltd; // Linear Torque Decoupling vector 00843 btVector3 c = m_calculatedTransformB.getOrigin() - transA.getOrigin(); 00844 ltd = c.cross(ax1); 00845 info->m_J1angularAxis[srow+0] = ltd[0]; 00846 info->m_J1angularAxis[srow+1] = ltd[1]; 00847 info->m_J1angularAxis[srow+2] = ltd[2]; 00848 00849 c = m_calculatedTransformB.getOrigin() - transB.getOrigin(); 00850 ltd = -c.cross(ax1); 00851 info->m_J2angularAxis[srow+0] = ltd[0]; 00852 info->m_J2angularAxis[srow+1] = ltd[1]; 00853 info->m_J2angularAxis[srow+2] = ltd[2]; 00854 } 00855 } 00856 // if we're limited low and high simultaneously, the joint motor is 00857 // ineffective 00858 if (limit && (limot->m_loLimit == limot->m_hiLimit)) powered = 0; 00859 info->m_constraintError[srow] = btScalar(0.f); 00860 if (powered) 00861 { 00862 info->cfm[srow] = limot->m_normalCFM; 00863 if(!limit) 00864 { 00865 btScalar tag_vel = rotational ? limot->m_targetVelocity : -limot->m_targetVelocity; 00866 00867 btScalar mot_fact = getMotorFactor( limot->m_currentPosition, 00868 limot->m_loLimit, 00869 limot->m_hiLimit, 00870 tag_vel, 00871 info->fps * limot->m_stopERP); 00872 info->m_constraintError[srow] += mot_fact * limot->m_targetVelocity; 00873 info->m_lowerLimit[srow] = -limot->m_maxMotorForce; 00874 info->m_upperLimit[srow] = limot->m_maxMotorForce; 00875 } 00876 } 00877 if(limit) 00878 { 00879 btScalar k = info->fps * limot->m_stopERP; 00880 if(!rotational) 00881 { 00882 info->m_constraintError[srow] += k * limot->m_currentLimitError; 00883 } 00884 else 00885 { 00886 info->m_constraintError[srow] += -k * limot->m_currentLimitError; 00887 } 00888 info->cfm[srow] = limot->m_stopCFM; 00889 if (limot->m_loLimit == limot->m_hiLimit) 00890 { // limited low and high simultaneously 00891 info->m_lowerLimit[srow] = -SIMD_INFINITY; 00892 info->m_upperLimit[srow] = SIMD_INFINITY; 00893 } 00894 else 00895 { 00896 if (limit == 1) 00897 { 00898 info->m_lowerLimit[srow] = 0; 00899 info->m_upperLimit[srow] = SIMD_INFINITY; 00900 } 00901 else 00902 { 00903 info->m_lowerLimit[srow] = -SIMD_INFINITY; 00904 info->m_upperLimit[srow] = 0; 00905 } 00906 // deal with bounce 00907 if (limot->m_bounce > 0) 00908 { 00909 // calculate joint velocity 00910 btScalar vel; 00911 if (rotational) 00912 { 00913 vel = angVelA.dot(ax1); 00914 //make sure that if no body -> angVelB == zero vec 00915 // if (body1) 00916 vel -= angVelB.dot(ax1); 00917 } 00918 else 00919 { 00920 vel = linVelA.dot(ax1); 00921 //make sure that if no body -> angVelB == zero vec 00922 // if (body1) 00923 vel -= linVelB.dot(ax1); 00924 } 00925 // only apply bounce if the velocity is incoming, and if the 00926 // resulting c[] exceeds what we already have. 00927 if (limit == 1) 00928 { 00929 if (vel < 0) 00930 { 00931 btScalar newc = -limot->m_bounce* vel; 00932 if (newc > info->m_constraintError[srow]) 00933 info->m_constraintError[srow] = newc; 00934 } 00935 } 00936 else 00937 { 00938 if (vel > 0) 00939 { 00940 btScalar newc = -limot->m_bounce * vel; 00941 if (newc < info->m_constraintError[srow]) 00942 info->m_constraintError[srow] = newc; 00943 } 00944 } 00945 } 00946 } 00947 } 00948 return 1; 00949 } 00950 else return 0; 00951 } 00952 00953 00954 00955 00956 00957 00960 void btGeneric6DofConstraint::setParam(int num, btScalar value, int axis) 00961 { 00962 if((axis >= 0) && (axis < 3)) 00963 { 00964 switch(num) 00965 { 00966 case BT_CONSTRAINT_STOP_ERP : 00967 m_linearLimits.m_stopERP[axis] = value; 00968 m_flags |= BT_6DOF_FLAGS_ERP_STOP << (axis * BT_6DOF_FLAGS_AXIS_SHIFT); 00969 break; 00970 case BT_CONSTRAINT_STOP_CFM : 00971 m_linearLimits.m_stopCFM[axis] = value; 00972 m_flags |= BT_6DOF_FLAGS_CFM_STOP << (axis * BT_6DOF_FLAGS_AXIS_SHIFT); 00973 break; 00974 case BT_CONSTRAINT_CFM : 00975 m_linearLimits.m_normalCFM[axis] = value; 00976 m_flags |= BT_6DOF_FLAGS_CFM_NORM << (axis * BT_6DOF_FLAGS_AXIS_SHIFT); 00977 break; 00978 default : 00979 btAssertConstrParams(0); 00980 } 00981 } 00982 else if((axis >=3) && (axis < 6)) 00983 { 00984 switch(num) 00985 { 00986 case BT_CONSTRAINT_STOP_ERP : 00987 m_angularLimits[axis - 3].m_stopERP = value; 00988 m_flags |= BT_6DOF_FLAGS_ERP_STOP << (axis * BT_6DOF_FLAGS_AXIS_SHIFT); 00989 break; 00990 case BT_CONSTRAINT_STOP_CFM : 00991 m_angularLimits[axis - 3].m_stopCFM = value; 00992 m_flags |= BT_6DOF_FLAGS_CFM_STOP << (axis * BT_6DOF_FLAGS_AXIS_SHIFT); 00993 break; 00994 case BT_CONSTRAINT_CFM : 00995 m_angularLimits[axis - 3].m_normalCFM = value; 00996 m_flags |= BT_6DOF_FLAGS_CFM_NORM << (axis * BT_6DOF_FLAGS_AXIS_SHIFT); 00997 break; 00998 default : 00999 btAssertConstrParams(0); 01000 } 01001 } 01002 else 01003 { 01004 btAssertConstrParams(0); 01005 } 01006 } 01007 01009 btScalar btGeneric6DofConstraint::getParam(int num, int axis) const 01010 { 01011 btScalar retVal = 0; 01012 if((axis >= 0) && (axis < 3)) 01013 { 01014 switch(num) 01015 { 01016 case BT_CONSTRAINT_STOP_ERP : 01017 btAssertConstrParams(m_flags & (BT_6DOF_FLAGS_ERP_STOP << (axis * BT_6DOF_FLAGS_AXIS_SHIFT))); 01018 retVal = m_linearLimits.m_stopERP[axis]; 01019 break; 01020 case BT_CONSTRAINT_STOP_CFM : 01021 btAssertConstrParams(m_flags & (BT_6DOF_FLAGS_CFM_STOP << (axis * BT_6DOF_FLAGS_AXIS_SHIFT))); 01022 retVal = m_linearLimits.m_stopCFM[axis]; 01023 break; 01024 case BT_CONSTRAINT_CFM : 01025 btAssertConstrParams(m_flags & (BT_6DOF_FLAGS_CFM_NORM << (axis * BT_6DOF_FLAGS_AXIS_SHIFT))); 01026 retVal = m_linearLimits.m_normalCFM[axis]; 01027 break; 01028 default : 01029 btAssertConstrParams(0); 01030 } 01031 } 01032 else if((axis >=3) && (axis < 6)) 01033 { 01034 switch(num) 01035 { 01036 case BT_CONSTRAINT_STOP_ERP : 01037 btAssertConstrParams(m_flags & (BT_6DOF_FLAGS_ERP_STOP << (axis * BT_6DOF_FLAGS_AXIS_SHIFT))); 01038 retVal = m_angularLimits[axis - 3].m_stopERP; 01039 break; 01040 case BT_CONSTRAINT_STOP_CFM : 01041 btAssertConstrParams(m_flags & (BT_6DOF_FLAGS_CFM_STOP << (axis * BT_6DOF_FLAGS_AXIS_SHIFT))); 01042 retVal = m_angularLimits[axis - 3].m_stopCFM; 01043 break; 01044 case BT_CONSTRAINT_CFM : 01045 btAssertConstrParams(m_flags & (BT_6DOF_FLAGS_CFM_NORM << (axis * BT_6DOF_FLAGS_AXIS_SHIFT))); 01046 retVal = m_angularLimits[axis - 3].m_normalCFM; 01047 break; 01048 default : 01049 btAssertConstrParams(0); 01050 } 01051 } 01052 else 01053 { 01054 btAssertConstrParams(0); 01055 } 01056 return retVal; 01057 } 01058 01059 01060 01061 void btGeneric6DofConstraint::setAxis(const btVector3& axis1,const btVector3& axis2) 01062 { 01063 btVector3 zAxis = axis1.normalized(); 01064 btVector3 yAxis = axis2.normalized(); 01065 btVector3 xAxis = yAxis.cross(zAxis); // we want right coordinate system 01066 01067 btTransform frameInW; 01068 frameInW.setIdentity(); 01069 frameInW.getBasis().setValue( xAxis[0], yAxis[0], zAxis[0], 01070 xAxis[1], yAxis[1], zAxis[1], 01071 xAxis[2], yAxis[2], zAxis[2]); 01072 01073 // now get constraint frame in local coordinate systems 01074 m_frameInA = m_rbA.getCenterOfMassTransform().inverse() * frameInW; 01075 m_frameInB = m_rbB.getCenterOfMassTransform().inverse() * frameInW; 01076 01077 calculateTransforms(); 01078 }