b3Generic6DofConstraint.cpp 24 KB

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