b3Generic6DofConstraint.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808
  1. /*
  2. Bullet Continuous Collision Detection and Physics Library
  3. Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
  4. This software is provided 'as-is', without any express or implied warranty.
  5. In no event will the authors be held liable for any damages arising from the use of this software.
  6. Permission is granted to anyone to use this software for any purpose,
  7. including commercial applications, and to alter it and redistribute it freely,
  8. subject to the following restrictions:
  9. 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.
  10. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
  11. 3. This notice may not be removed or altered from any source distribution.
  12. */
  13. /*
  14. 2007-09-09
  15. Refactored by Francisco Le?n
  16. email: projectileman@yahoo.com
  17. http://gimpact.sf.net
  18. */
  19. #include "b3Generic6DofConstraint.h"
  20. #include "Bullet3Collision/NarrowPhaseCollision/shared/b3RigidBodyData.h"
  21. #include "Bullet3Common/b3TransformUtil.h"
  22. #include "Bullet3Common/b3TransformUtil.h"
  23. #include <new>
  24. #define D6_USE_OBSOLETE_METHOD false
  25. #define D6_USE_FRAME_OFFSET true
  26. b3Generic6DofConstraint::b3Generic6DofConstraint(int rbA,int rbB, const b3Transform& frameInA, const b3Transform& frameInB, bool useLinearReferenceFrameA, const b3RigidBodyData* bodies)
  27. : b3TypedConstraint(B3_D6_CONSTRAINT_TYPE, rbA, rbB)
  28. , m_frameInA(frameInA)
  29. , m_frameInB(frameInB),
  30. m_useLinearReferenceFrameA(useLinearReferenceFrameA),
  31. m_useOffsetForConstraintFrame(D6_USE_FRAME_OFFSET),
  32. m_flags(0)
  33. {
  34. calculateTransforms(bodies);
  35. }
  36. #define GENERIC_D6_DISABLE_WARMSTARTING 1
  37. b3Scalar btGetMatrixElem(const b3Matrix3x3& mat, int index);
  38. b3Scalar btGetMatrixElem(const b3Matrix3x3& mat, int index)
  39. {
  40. int i = index%3;
  41. int j = index/3;
  42. return mat[i][j];
  43. }
  44. ///MatrixToEulerXYZ from http://www.geometrictools.com/LibFoundation/Mathematics/Wm4Matrix3.inl.html
  45. bool matrixToEulerXYZ(const b3Matrix3x3& mat,b3Vector3& xyz);
  46. bool matrixToEulerXYZ(const b3Matrix3x3& mat,b3Vector3& xyz)
  47. {
  48. // // rot = cy*cz -cy*sz sy
  49. // // cz*sx*sy+cx*sz cx*cz-sx*sy*sz -cy*sx
  50. // // -cx*cz*sy+sx*sz cz*sx+cx*sy*sz cx*cy
  51. //
  52. b3Scalar fi = btGetMatrixElem(mat,2);
  53. if (fi < b3Scalar(1.0f))
  54. {
  55. if (fi > b3Scalar(-1.0f))
  56. {
  57. xyz[0] = b3Atan2(-btGetMatrixElem(mat,5),btGetMatrixElem(mat,8));
  58. xyz[1] = b3Asin(btGetMatrixElem(mat,2));
  59. xyz[2] = b3Atan2(-btGetMatrixElem(mat,1),btGetMatrixElem(mat,0));
  60. return true;
  61. }
  62. else
  63. {
  64. // WARNING. Not unique. XA - ZA = -atan2(r10,r11)
  65. xyz[0] = -b3Atan2(btGetMatrixElem(mat,3),btGetMatrixElem(mat,4));
  66. xyz[1] = -B3_HALF_PI;
  67. xyz[2] = b3Scalar(0.0);
  68. return false;
  69. }
  70. }
  71. else
  72. {
  73. // WARNING. Not unique. XAngle + ZAngle = atan2(r10,r11)
  74. xyz[0] = b3Atan2(btGetMatrixElem(mat,3),btGetMatrixElem(mat,4));
  75. xyz[1] = B3_HALF_PI;
  76. xyz[2] = 0.0;
  77. }
  78. return false;
  79. }
  80. //////////////////////////// b3RotationalLimitMotor ////////////////////////////////////
  81. int b3RotationalLimitMotor::testLimitValue(b3Scalar test_value)
  82. {
  83. if(m_loLimit>m_hiLimit)
  84. {
  85. m_currentLimit = 0;//Free from violation
  86. return 0;
  87. }
  88. if (test_value < m_loLimit)
  89. {
  90. m_currentLimit = 1;//low limit violation
  91. m_currentLimitError = test_value - m_loLimit;
  92. if(m_currentLimitError>B3_PI)
  93. m_currentLimitError-=B3_2_PI;
  94. else if(m_currentLimitError<-B3_PI)
  95. m_currentLimitError+=B3_2_PI;
  96. return 1;
  97. }
  98. else if (test_value> m_hiLimit)
  99. {
  100. m_currentLimit = 2;//High limit violation
  101. m_currentLimitError = test_value - m_hiLimit;
  102. if(m_currentLimitError>B3_PI)
  103. m_currentLimitError-=B3_2_PI;
  104. else if(m_currentLimitError<-B3_PI)
  105. m_currentLimitError+=B3_2_PI;
  106. return 2;
  107. };
  108. m_currentLimit = 0;//Free from violation
  109. return 0;
  110. }
  111. //////////////////////////// End b3RotationalLimitMotor ////////////////////////////////////
  112. //////////////////////////// b3TranslationalLimitMotor ////////////////////////////////////
  113. int b3TranslationalLimitMotor::testLimitValue(int limitIndex, b3Scalar test_value)
  114. {
  115. b3Scalar loLimit = m_lowerLimit[limitIndex];
  116. b3Scalar hiLimit = m_upperLimit[limitIndex];
  117. if(loLimit > hiLimit)
  118. {
  119. m_currentLimit[limitIndex] = 0;//Free from violation
  120. m_currentLimitError[limitIndex] = b3Scalar(0.f);
  121. return 0;
  122. }
  123. if (test_value < loLimit)
  124. {
  125. m_currentLimit[limitIndex] = 2;//low limit violation
  126. m_currentLimitError[limitIndex] = test_value - loLimit;
  127. return 2;
  128. }
  129. else if (test_value> hiLimit)
  130. {
  131. m_currentLimit[limitIndex] = 1;//High limit violation
  132. m_currentLimitError[limitIndex] = test_value - hiLimit;
  133. return 1;
  134. };
  135. m_currentLimit[limitIndex] = 0;//Free from violation
  136. m_currentLimitError[limitIndex] = b3Scalar(0.f);
  137. return 0;
  138. }
  139. //////////////////////////// b3TranslationalLimitMotor ////////////////////////////////////
  140. void b3Generic6DofConstraint::calculateAngleInfo()
  141. {
  142. b3Matrix3x3 relative_frame = m_calculatedTransformA.getBasis().inverse()*m_calculatedTransformB.getBasis();
  143. matrixToEulerXYZ(relative_frame,m_calculatedAxisAngleDiff);
  144. // in euler angle mode we do not actually constrain the angular velocity
  145. // along the axes axis[0] and axis[2] (although we do use axis[1]) :
  146. //
  147. // to get constrain w2-w1 along ...not
  148. // ------ --------------------- ------
  149. // d(angle[0])/dt = 0 ax[1] x ax[2] ax[0]
  150. // d(angle[1])/dt = 0 ax[1]
  151. // d(angle[2])/dt = 0 ax[0] x ax[1] ax[2]
  152. //
  153. // constraining w2-w1 along an axis 'a' means that a'*(w2-w1)=0.
  154. // to prove the result for angle[0], write the expression for angle[0] from
  155. // GetInfo1 then take the derivative. to prove this for angle[2] it is
  156. // easier to take the euler rate expression for d(angle[2])/dt with respect
  157. // to the components of w and set that to 0.
  158. b3Vector3 axis0 = m_calculatedTransformB.getBasis().getColumn(0);
  159. b3Vector3 axis2 = m_calculatedTransformA.getBasis().getColumn(2);
  160. m_calculatedAxis[1] = axis2.cross(axis0);
  161. m_calculatedAxis[0] = m_calculatedAxis[1].cross(axis2);
  162. m_calculatedAxis[2] = axis0.cross(m_calculatedAxis[1]);
  163. m_calculatedAxis[0].normalize();
  164. m_calculatedAxis[1].normalize();
  165. m_calculatedAxis[2].normalize();
  166. }
  167. static b3Transform getCenterOfMassTransform(const b3RigidBodyData& body)
  168. {
  169. b3Transform tr(body.m_quat,body.m_pos);
  170. return tr;
  171. }
  172. void b3Generic6DofConstraint::calculateTransforms(const b3RigidBodyData* bodies)
  173. {
  174. b3Transform transA;
  175. b3Transform transB;
  176. transA = getCenterOfMassTransform(bodies[m_rbA]);
  177. transB = getCenterOfMassTransform(bodies[m_rbB]);
  178. calculateTransforms(transA,transB,bodies);
  179. }
  180. void b3Generic6DofConstraint::calculateTransforms(const b3Transform& transA,const b3Transform& transB,const b3RigidBodyData* bodies)
  181. {
  182. m_calculatedTransformA = transA * m_frameInA;
  183. m_calculatedTransformB = transB * m_frameInB;
  184. calculateLinearInfo();
  185. calculateAngleInfo();
  186. if(m_useOffsetForConstraintFrame)
  187. { // get weight factors depending on masses
  188. b3Scalar miA = bodies[m_rbA].m_invMass;
  189. b3Scalar miB = bodies[m_rbB].m_invMass;
  190. m_hasStaticBody = (miA < B3_EPSILON) || (miB < B3_EPSILON);
  191. b3Scalar miS = miA + miB;
  192. if(miS > b3Scalar(0.f))
  193. {
  194. m_factA = miB / miS;
  195. }
  196. else
  197. {
  198. m_factA = b3Scalar(0.5f);
  199. }
  200. m_factB = b3Scalar(1.0f) - m_factA;
  201. }
  202. }
  203. bool b3Generic6DofConstraint::testAngularLimitMotor(int axis_index)
  204. {
  205. b3Scalar angle = m_calculatedAxisAngleDiff[axis_index];
  206. angle = b3AdjustAngleToLimits(angle, m_angularLimits[axis_index].m_loLimit, m_angularLimits[axis_index].m_hiLimit);
  207. m_angularLimits[axis_index].m_currentPosition = angle;
  208. //test limits
  209. m_angularLimits[axis_index].testLimitValue(angle);
  210. return m_angularLimits[axis_index].needApplyTorques();
  211. }
  212. void b3Generic6DofConstraint::getInfo1 (b3ConstraintInfo1* info,const b3RigidBodyData* bodies)
  213. {
  214. //prepare constraint
  215. calculateTransforms(getCenterOfMassTransform(bodies[m_rbA]),getCenterOfMassTransform(bodies[m_rbB]),bodies);
  216. info->m_numConstraintRows = 0;
  217. info->nub = 6;
  218. int i;
  219. //test linear limits
  220. for(i = 0; i < 3; i++)
  221. {
  222. if(m_linearLimits.needApplyForce(i))
  223. {
  224. info->m_numConstraintRows++;
  225. info->nub--;
  226. }
  227. }
  228. //test angular limits
  229. for (i=0;i<3 ;i++ )
  230. {
  231. if(testAngularLimitMotor(i))
  232. {
  233. info->m_numConstraintRows++;
  234. info->nub--;
  235. }
  236. }
  237. // printf("info->m_numConstraintRows=%d\n",info->m_numConstraintRows);
  238. }
  239. void b3Generic6DofConstraint::getInfo1NonVirtual (b3ConstraintInfo1* info,const b3RigidBodyData* bodies)
  240. {
  241. //pre-allocate all 6
  242. info->m_numConstraintRows = 6;
  243. info->nub = 0;
  244. }
  245. void b3Generic6DofConstraint::getInfo2 (b3ConstraintInfo2* info,const b3RigidBodyData* bodies)
  246. {
  247. b3Transform transA = getCenterOfMassTransform(bodies[m_rbA]);
  248. b3Transform transB = getCenterOfMassTransform(bodies[m_rbB]);
  249. const b3Vector3& linVelA = bodies[m_rbA].m_linVel;
  250. const b3Vector3& linVelB = bodies[m_rbB].m_linVel;
  251. const b3Vector3& angVelA = bodies[m_rbA].m_angVel;
  252. const b3Vector3& angVelB = bodies[m_rbB].m_angVel;
  253. if(m_useOffsetForConstraintFrame)
  254. { // for stability better to solve angular limits first
  255. int row = setAngularLimits(info, 0,transA,transB,linVelA,linVelB,angVelA,angVelB);
  256. setLinearLimits(info, row, transA,transB,linVelA,linVelB,angVelA,angVelB);
  257. }
  258. else
  259. { // leave old version for compatibility
  260. int row = setLinearLimits(info, 0, transA,transB,linVelA,linVelB,angVelA,angVelB);
  261. setAngularLimits(info, row,transA,transB,linVelA,linVelB,angVelA,angVelB);
  262. }
  263. }
  264. void b3Generic6DofConstraint::getInfo2NonVirtual (b3ConstraintInfo2* info, const b3Transform& transA,const b3Transform& transB,const b3Vector3& linVelA,const b3Vector3& linVelB,const b3Vector3& angVelA,const b3Vector3& angVelB,const b3RigidBodyData* bodies)
  265. {
  266. //prepare constraint
  267. calculateTransforms(transA,transB,bodies);
  268. int i;
  269. for (i=0;i<3 ;i++ )
  270. {
  271. testAngularLimitMotor(i);
  272. }
  273. if(m_useOffsetForConstraintFrame)
  274. { // for stability better to solve angular limits first
  275. int row = setAngularLimits(info, 0,transA,transB,linVelA,linVelB,angVelA,angVelB);
  276. setLinearLimits(info, row, transA,transB,linVelA,linVelB,angVelA,angVelB);
  277. }
  278. else
  279. { // leave old version for compatibility
  280. int row = setLinearLimits(info, 0, transA,transB,linVelA,linVelB,angVelA,angVelB);
  281. setAngularLimits(info, row,transA,transB,linVelA,linVelB,angVelA,angVelB);
  282. }
  283. }
  284. int b3Generic6DofConstraint::setLinearLimits(b3ConstraintInfo2* info, int row, const b3Transform& transA,const b3Transform& transB,const b3Vector3& linVelA,const b3Vector3& linVelB,const b3Vector3& angVelA,const b3Vector3& angVelB)
  285. {
  286. // int row = 0;
  287. //solve linear limits
  288. b3RotationalLimitMotor limot;
  289. for (int i=0;i<3 ;i++ )
  290. {
  291. if(m_linearLimits.needApplyForce(i))
  292. { // re-use rotational motor code
  293. limot.m_bounce = b3Scalar(0.f);
  294. limot.m_currentLimit = m_linearLimits.m_currentLimit[i];
  295. limot.m_currentPosition = m_linearLimits.m_currentLinearDiff[i];
  296. limot.m_currentLimitError = m_linearLimits.m_currentLimitError[i];
  297. limot.m_damping = m_linearLimits.m_damping;
  298. limot.m_enableMotor = m_linearLimits.m_enableMotor[i];
  299. limot.m_hiLimit = m_linearLimits.m_upperLimit[i];
  300. limot.m_limitSoftness = m_linearLimits.m_limitSoftness;
  301. limot.m_loLimit = m_linearLimits.m_lowerLimit[i];
  302. limot.m_maxLimitForce = b3Scalar(0.f);
  303. limot.m_maxMotorForce = m_linearLimits.m_maxMotorForce[i];
  304. limot.m_targetVelocity = m_linearLimits.m_targetVelocity[i];
  305. b3Vector3 axis = m_calculatedTransformA.getBasis().getColumn(i);
  306. int flags = m_flags >> (i * B3_6DOF_FLAGS_AXIS_SHIFT);
  307. limot.m_normalCFM = (flags & B3_6DOF_FLAGS_CFM_NORM) ? m_linearLimits.m_normalCFM[i] : info->cfm[0];
  308. limot.m_stopCFM = (flags & B3_6DOF_FLAGS_CFM_STOP) ? m_linearLimits.m_stopCFM[i] : info->cfm[0];
  309. limot.m_stopERP = (flags & B3_6DOF_FLAGS_ERP_STOP) ? m_linearLimits.m_stopERP[i] : info->erp;
  310. if(m_useOffsetForConstraintFrame)
  311. {
  312. int indx1 = (i + 1) % 3;
  313. int indx2 = (i + 2) % 3;
  314. int rotAllowed = 1; // rotations around orthos to current axis
  315. if(m_angularLimits[indx1].m_currentLimit && m_angularLimits[indx2].m_currentLimit)
  316. {
  317. rotAllowed = 0;
  318. }
  319. row += get_limit_motor_info2(&limot, transA,transB,linVelA,linVelB,angVelA,angVelB, info, row, axis, 0, rotAllowed);
  320. }
  321. else
  322. {
  323. row += get_limit_motor_info2(&limot, transA,transB,linVelA,linVelB,angVelA,angVelB, info, row, axis, 0);
  324. }
  325. }
  326. }
  327. return row;
  328. }
  329. int b3Generic6DofConstraint::setAngularLimits(b3ConstraintInfo2 *info, int row_offset, const b3Transform& transA,const b3Transform& transB,const b3Vector3& linVelA,const b3Vector3& linVelB,const b3Vector3& angVelA,const b3Vector3& angVelB)
  330. {
  331. b3Generic6DofConstraint * d6constraint = this;
  332. int row = row_offset;
  333. //solve angular limits
  334. for (int i=0;i<3 ;i++ )
  335. {
  336. if(d6constraint->getRotationalLimitMotor(i)->needApplyTorques())
  337. {
  338. b3Vector3 axis = d6constraint->getAxis(i);
  339. int flags = m_flags >> ((i + 3) * B3_6DOF_FLAGS_AXIS_SHIFT);
  340. if(!(flags & B3_6DOF_FLAGS_CFM_NORM))
  341. {
  342. m_angularLimits[i].m_normalCFM = info->cfm[0];
  343. }
  344. if(!(flags & B3_6DOF_FLAGS_CFM_STOP))
  345. {
  346. m_angularLimits[i].m_stopCFM = info->cfm[0];
  347. }
  348. if(!(flags & B3_6DOF_FLAGS_ERP_STOP))
  349. {
  350. m_angularLimits[i].m_stopERP = info->erp;
  351. }
  352. row += get_limit_motor_info2(d6constraint->getRotationalLimitMotor(i),
  353. transA,transB,linVelA,linVelB,angVelA,angVelB, info,row,axis,1);
  354. }
  355. }
  356. return row;
  357. }
  358. void b3Generic6DofConstraint::updateRHS(b3Scalar timeStep)
  359. {
  360. (void)timeStep;
  361. }
  362. void b3Generic6DofConstraint::setFrames(const b3Transform& frameA, const b3Transform& frameB,const b3RigidBodyData* bodies)
  363. {
  364. m_frameInA = frameA;
  365. m_frameInB = frameB;
  366. calculateTransforms(bodies);
  367. }
  368. b3Vector3 b3Generic6DofConstraint::getAxis(int axis_index) const
  369. {
  370. return m_calculatedAxis[axis_index];
  371. }
  372. b3Scalar b3Generic6DofConstraint::getRelativePivotPosition(int axisIndex) const
  373. {
  374. return m_calculatedLinearDiff[axisIndex];
  375. }
  376. b3Scalar b3Generic6DofConstraint::getAngle(int axisIndex) const
  377. {
  378. return m_calculatedAxisAngleDiff[axisIndex];
  379. }
  380. void b3Generic6DofConstraint::calcAnchorPos(const b3RigidBodyData* bodies)
  381. {
  382. b3Scalar imA = bodies[m_rbA].m_invMass;
  383. b3Scalar imB = bodies[m_rbB].m_invMass;
  384. b3Scalar weight;
  385. if(imB == b3Scalar(0.0))
  386. {
  387. weight = b3Scalar(1.0);
  388. }
  389. else
  390. {
  391. weight = imA / (imA + imB);
  392. }
  393. const b3Vector3& pA = m_calculatedTransformA.getOrigin();
  394. const b3Vector3& pB = m_calculatedTransformB.getOrigin();
  395. m_AnchorPos = pA * weight + pB * (b3Scalar(1.0) - weight);
  396. return;
  397. }
  398. void b3Generic6DofConstraint::calculateLinearInfo()
  399. {
  400. m_calculatedLinearDiff = m_calculatedTransformB.getOrigin() - m_calculatedTransformA.getOrigin();
  401. m_calculatedLinearDiff = m_calculatedTransformA.getBasis().inverse() * m_calculatedLinearDiff;
  402. for(int i = 0; i < 3; i++)
  403. {
  404. m_linearLimits.m_currentLinearDiff[i] = m_calculatedLinearDiff[i];
  405. m_linearLimits.testLimitValue(i, m_calculatedLinearDiff[i]);
  406. }
  407. }
  408. int b3Generic6DofConstraint::get_limit_motor_info2(
  409. b3RotationalLimitMotor * limot,
  410. const b3Transform& transA,const b3Transform& transB,const b3Vector3& linVelA,const b3Vector3& linVelB,const b3Vector3& angVelA,const b3Vector3& angVelB,
  411. b3ConstraintInfo2 *info, int row, b3Vector3& ax1, int rotational,int rotAllowed)
  412. {
  413. int srow = row * info->rowskip;
  414. bool powered = limot->m_enableMotor;
  415. int limit = limot->m_currentLimit;
  416. if (powered || limit)
  417. { // if the joint is powered, or has joint limits, add in the extra row
  418. b3Scalar *J1 = rotational ? info->m_J1angularAxis : info->m_J1linearAxis;
  419. b3Scalar *J2 = rotational ? info->m_J2angularAxis : info->m_J2linearAxis;
  420. if (J1)
  421. {
  422. J1[srow+0] = ax1[0];
  423. J1[srow+1] = ax1[1];
  424. J1[srow+2] = ax1[2];
  425. }
  426. if (J2)
  427. {
  428. J2[srow+0] = -ax1[0];
  429. J2[srow+1] = -ax1[1];
  430. J2[srow+2] = -ax1[2];
  431. }
  432. if((!rotational))
  433. {
  434. if (m_useOffsetForConstraintFrame)
  435. {
  436. b3Vector3 tmpA, tmpB, relA, relB;
  437. // get vector from bodyB to frameB in WCS
  438. relB = m_calculatedTransformB.getOrigin() - transB.getOrigin();
  439. // get its projection to constraint axis
  440. b3Vector3 projB = ax1 * relB.dot(ax1);
  441. // get vector directed from bodyB to constraint axis (and orthogonal to it)
  442. b3Vector3 orthoB = relB - projB;
  443. // same for bodyA
  444. relA = m_calculatedTransformA.getOrigin() - transA.getOrigin();
  445. b3Vector3 projA = ax1 * relA.dot(ax1);
  446. b3Vector3 orthoA = relA - projA;
  447. // get desired offset between frames A and B along constraint axis
  448. b3Scalar desiredOffs = limot->m_currentPosition - limot->m_currentLimitError;
  449. // desired vector from projection of center of bodyA to projection of center of bodyB to constraint axis
  450. b3Vector3 totalDist = projA + ax1 * desiredOffs - projB;
  451. // get offset vectors relA and relB
  452. relA = orthoA + totalDist * m_factA;
  453. relB = orthoB - totalDist * m_factB;
  454. tmpA = relA.cross(ax1);
  455. tmpB = relB.cross(ax1);
  456. if(m_hasStaticBody && (!rotAllowed))
  457. {
  458. tmpA *= m_factA;
  459. tmpB *= m_factB;
  460. }
  461. int i;
  462. for (i=0; i<3; i++) info->m_J1angularAxis[srow+i] = tmpA[i];
  463. for (i=0; i<3; i++) info->m_J2angularAxis[srow+i] = -tmpB[i];
  464. } else
  465. {
  466. b3Vector3 ltd; // Linear Torque Decoupling vector
  467. b3Vector3 c = m_calculatedTransformB.getOrigin() - transA.getOrigin();
  468. ltd = c.cross(ax1);
  469. info->m_J1angularAxis[srow+0] = ltd[0];
  470. info->m_J1angularAxis[srow+1] = ltd[1];
  471. info->m_J1angularAxis[srow+2] = ltd[2];
  472. c = m_calculatedTransformB.getOrigin() - transB.getOrigin();
  473. ltd = -c.cross(ax1);
  474. info->m_J2angularAxis[srow+0] = ltd[0];
  475. info->m_J2angularAxis[srow+1] = ltd[1];
  476. info->m_J2angularAxis[srow+2] = ltd[2];
  477. }
  478. }
  479. // if we're limited low and high simultaneously, the joint motor is
  480. // ineffective
  481. if (limit && (limot->m_loLimit == limot->m_hiLimit)) powered = false;
  482. info->m_constraintError[srow] = b3Scalar(0.f);
  483. if (powered)
  484. {
  485. info->cfm[srow] = limot->m_normalCFM;
  486. if(!limit)
  487. {
  488. b3Scalar tag_vel = rotational ? limot->m_targetVelocity : -limot->m_targetVelocity;
  489. b3Scalar mot_fact = getMotorFactor( limot->m_currentPosition,
  490. limot->m_loLimit,
  491. limot->m_hiLimit,
  492. tag_vel,
  493. info->fps * limot->m_stopERP);
  494. info->m_constraintError[srow] += mot_fact * limot->m_targetVelocity;
  495. info->m_lowerLimit[srow] = -limot->m_maxMotorForce;
  496. info->m_upperLimit[srow] = limot->m_maxMotorForce;
  497. }
  498. }
  499. if(limit)
  500. {
  501. b3Scalar k = info->fps * limot->m_stopERP;
  502. if(!rotational)
  503. {
  504. info->m_constraintError[srow] += k * limot->m_currentLimitError;
  505. }
  506. else
  507. {
  508. info->m_constraintError[srow] += -k * limot->m_currentLimitError;
  509. }
  510. info->cfm[srow] = limot->m_stopCFM;
  511. if (limot->m_loLimit == limot->m_hiLimit)
  512. { // limited low and high simultaneously
  513. info->m_lowerLimit[srow] = -B3_INFINITY;
  514. info->m_upperLimit[srow] = B3_INFINITY;
  515. }
  516. else
  517. {
  518. if (limit == 1)
  519. {
  520. info->m_lowerLimit[srow] = 0;
  521. info->m_upperLimit[srow] = B3_INFINITY;
  522. }
  523. else
  524. {
  525. info->m_lowerLimit[srow] = -B3_INFINITY;
  526. info->m_upperLimit[srow] = 0;
  527. }
  528. // deal with bounce
  529. if (limot->m_bounce > 0)
  530. {
  531. // calculate joint velocity
  532. b3Scalar vel;
  533. if (rotational)
  534. {
  535. vel = angVelA.dot(ax1);
  536. //make sure that if no body -> angVelB == zero vec
  537. // if (body1)
  538. vel -= angVelB.dot(ax1);
  539. }
  540. else
  541. {
  542. vel = linVelA.dot(ax1);
  543. //make sure that if no body -> angVelB == zero vec
  544. // if (body1)
  545. vel -= linVelB.dot(ax1);
  546. }
  547. // only apply bounce if the velocity is incoming, and if the
  548. // resulting c[] exceeds what we already have.
  549. if (limit == 1)
  550. {
  551. if (vel < 0)
  552. {
  553. b3Scalar newc = -limot->m_bounce* vel;
  554. if (newc > info->m_constraintError[srow])
  555. info->m_constraintError[srow] = newc;
  556. }
  557. }
  558. else
  559. {
  560. if (vel > 0)
  561. {
  562. b3Scalar newc = -limot->m_bounce * vel;
  563. if (newc < info->m_constraintError[srow])
  564. info->m_constraintError[srow] = newc;
  565. }
  566. }
  567. }
  568. }
  569. }
  570. return 1;
  571. }
  572. else return 0;
  573. }
  574. ///override the default global value of a parameter (such as ERP or CFM), optionally provide the axis (0..5).
  575. ///If no axis is provided, it uses the default axis for this constraint.
  576. void b3Generic6DofConstraint::setParam(int num, b3Scalar value, int axis)
  577. {
  578. if((axis >= 0) && (axis < 3))
  579. {
  580. switch(num)
  581. {
  582. case B3_CONSTRAINT_STOP_ERP :
  583. m_linearLimits.m_stopERP[axis] = value;
  584. m_flags |= B3_6DOF_FLAGS_ERP_STOP << (axis * B3_6DOF_FLAGS_AXIS_SHIFT);
  585. break;
  586. case B3_CONSTRAINT_STOP_CFM :
  587. m_linearLimits.m_stopCFM[axis] = value;
  588. m_flags |= B3_6DOF_FLAGS_CFM_STOP << (axis * B3_6DOF_FLAGS_AXIS_SHIFT);
  589. break;
  590. case B3_CONSTRAINT_CFM :
  591. m_linearLimits.m_normalCFM[axis] = value;
  592. m_flags |= B3_6DOF_FLAGS_CFM_NORM << (axis * B3_6DOF_FLAGS_AXIS_SHIFT);
  593. break;
  594. default :
  595. b3AssertConstrParams(0);
  596. }
  597. }
  598. else if((axis >=3) && (axis < 6))
  599. {
  600. switch(num)
  601. {
  602. case B3_CONSTRAINT_STOP_ERP :
  603. m_angularLimits[axis - 3].m_stopERP = value;
  604. m_flags |= B3_6DOF_FLAGS_ERP_STOP << (axis * B3_6DOF_FLAGS_AXIS_SHIFT);
  605. break;
  606. case B3_CONSTRAINT_STOP_CFM :
  607. m_angularLimits[axis - 3].m_stopCFM = value;
  608. m_flags |= B3_6DOF_FLAGS_CFM_STOP << (axis * B3_6DOF_FLAGS_AXIS_SHIFT);
  609. break;
  610. case B3_CONSTRAINT_CFM :
  611. m_angularLimits[axis - 3].m_normalCFM = value;
  612. m_flags |= B3_6DOF_FLAGS_CFM_NORM << (axis * B3_6DOF_FLAGS_AXIS_SHIFT);
  613. break;
  614. default :
  615. b3AssertConstrParams(0);
  616. }
  617. }
  618. else
  619. {
  620. b3AssertConstrParams(0);
  621. }
  622. }
  623. ///return the local value of parameter
  624. b3Scalar b3Generic6DofConstraint::getParam(int num, int axis) const
  625. {
  626. b3Scalar retVal = 0;
  627. if((axis >= 0) && (axis < 3))
  628. {
  629. switch(num)
  630. {
  631. case B3_CONSTRAINT_STOP_ERP :
  632. b3AssertConstrParams(m_flags & (B3_6DOF_FLAGS_ERP_STOP << (axis * B3_6DOF_FLAGS_AXIS_SHIFT)));
  633. retVal = m_linearLimits.m_stopERP[axis];
  634. break;
  635. case B3_CONSTRAINT_STOP_CFM :
  636. b3AssertConstrParams(m_flags & (B3_6DOF_FLAGS_CFM_STOP << (axis * B3_6DOF_FLAGS_AXIS_SHIFT)));
  637. retVal = m_linearLimits.m_stopCFM[axis];
  638. break;
  639. case B3_CONSTRAINT_CFM :
  640. b3AssertConstrParams(m_flags & (B3_6DOF_FLAGS_CFM_NORM << (axis * B3_6DOF_FLAGS_AXIS_SHIFT)));
  641. retVal = m_linearLimits.m_normalCFM[axis];
  642. break;
  643. default :
  644. b3AssertConstrParams(0);
  645. }
  646. }
  647. else if((axis >=3) && (axis < 6))
  648. {
  649. switch(num)
  650. {
  651. case B3_CONSTRAINT_STOP_ERP :
  652. b3AssertConstrParams(m_flags & (B3_6DOF_FLAGS_ERP_STOP << (axis * B3_6DOF_FLAGS_AXIS_SHIFT)));
  653. retVal = m_angularLimits[axis - 3].m_stopERP;
  654. break;
  655. case B3_CONSTRAINT_STOP_CFM :
  656. b3AssertConstrParams(m_flags & (B3_6DOF_FLAGS_CFM_STOP << (axis * B3_6DOF_FLAGS_AXIS_SHIFT)));
  657. retVal = m_angularLimits[axis - 3].m_stopCFM;
  658. break;
  659. case B3_CONSTRAINT_CFM :
  660. b3AssertConstrParams(m_flags & (B3_6DOF_FLAGS_CFM_NORM << (axis * B3_6DOF_FLAGS_AXIS_SHIFT)));
  661. retVal = m_angularLimits[axis - 3].m_normalCFM;
  662. break;
  663. default :
  664. b3AssertConstrParams(0);
  665. }
  666. }
  667. else
  668. {
  669. b3AssertConstrParams(0);
  670. }
  671. return retVal;
  672. }
  673. void b3Generic6DofConstraint::setAxis(const b3Vector3& axis1,const b3Vector3& axis2, const b3RigidBodyData* bodies)
  674. {
  675. b3Vector3 zAxis = axis1.normalized();
  676. b3Vector3 yAxis = axis2.normalized();
  677. b3Vector3 xAxis = yAxis.cross(zAxis); // we want right coordinate system
  678. b3Transform frameInW;
  679. frameInW.setIdentity();
  680. frameInW.getBasis().setValue( xAxis[0], yAxis[0], zAxis[0],
  681. xAxis[1], yAxis[1], zAxis[1],
  682. xAxis[2], yAxis[2], zAxis[2]);
  683. // now get constraint frame in local coordinate systems
  684. m_frameInA = getCenterOfMassTransform(bodies[m_rbA]).inverse() * frameInW;
  685. m_frameInB = getCenterOfMassTransform(bodies[m_rbB]).inverse() * frameInW;
  686. calculateTransforms(bodies);
  687. }