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