3 * Class representing an articulated rigid body. Stores the body's
4 * current state, allows forces and torques to be set, handles
5 * timestepping and implements Featherstone's algorithm.
8 * Copyright (C) Stephen Thompson, <stephen@solarflare.org.uk>, 2011-2013
9 * Portions written By Erwin Coumans: connection to LCP solver, various multibody constraints, replacing Eigen math library by Bullet LinearMath and a dedicated 6x6 matrix inverse (solveImatrix)
10 * Portions written By Jakub Stepien: support for multi-DOF constraints, introduction of spatial algebra and several other improvements
12 This software is provided 'as-is', without any express or implied warranty.
13 In no event will the authors be held liable for any damages arising from the use of this software.
14 Permission is granted to anyone to use this software for any purpose,
15 including commercial applications, and to alter it and redistribute it freely,
16 subject to the following restrictions:
18 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.
19 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
20 3. This notice may not be removed or altered from any source distribution.
24 #include "btMultiBody.h"
25 #include "btMultiBodyLink.h"
26 #include "btMultiBodyLinkCollider.h"
27 #include "btMultiBodyJointFeedback.h"
28 #include "LinearMath/btTransformUtil.h"
29 #include "LinearMath/btSerializer.h"
30 //#include "Bullet3Common/b3Logging.h"
31 // #define INCLUDE_GYRO_TERM
36 const btScalar INITIAL_SLEEP_EPSILON = btScalar(0.05); // this is a squared velocity (m^2 s^-2)
37 const btScalar INITIAL_SLEEP_TIMEOUT = btScalar(2); // in seconds
40 void btMultiBody::spatialTransform(const btMatrix3x3 &rotation_matrix, // rotates vectors in 'from' frame to vectors in 'to' frame
41 const btVector3 &displacement, // vector from origin of 'from' frame to origin of 'to' frame, in 'to' coordinates
42 const btVector3 &top_in, // top part of input vector
43 const btVector3 &bottom_in, // bottom part of input vector
44 btVector3 &top_out, // top part of output vector
45 btVector3 &bottom_out) // bottom part of output vector
47 top_out = rotation_matrix * top_in;
48 bottom_out = -displacement.cross(top_out) + rotation_matrix * bottom_in;
56 void InverseSpatialTransform(const btMatrix3x3 &rotation_matrix,
57 const btVector3 &displacement,
58 const btVector3 &top_in,
59 const btVector3 &bottom_in,
61 btVector3 &bottom_out)
63 top_out = rotation_matrix.transpose() * top_in;
64 bottom_out = rotation_matrix.transpose() * (bottom_in + displacement.cross(top_in));
67 btScalar SpatialDotProduct(const btVector3 &a_top,
68 const btVector3 &a_bottom,
69 const btVector3 &b_top,
70 const btVector3 &b_bottom)
72 return a_bottom.dot(b_top) + a_top.dot(b_bottom);
75 void SpatialCrossProduct(const btVector3 &a_top,
76 const btVector3 &a_bottom,
77 const btVector3 &b_top,
78 const btVector3 &b_bottom,
80 btVector3 &bottom_out)
82 top_out = a_top.cross(b_top);
83 bottom_out = a_bottom.cross(b_top) + a_top.cross(b_bottom);
90 // Implementation of class btMultiBody
93 btMultiBody::btMultiBody(int n_links,
95 const btVector3 &inertia,
98 bool /*deprecatedUseMultiDof*/)
102 m_baseQuat(0, 0, 0, 1),
103 m_basePos_interpolate(0, 0, 0),
104 m_baseQuat_interpolate(0, 0, 0, 1),
106 m_baseInertia(inertia),
108 m_fixedBase(fixedBase),
110 m_canSleep(canSleep),
113 m_sleepEpsilon(INITIAL_SLEEP_EPSILON),
114 m_sleepTimeout(INITIAL_SLEEP_TIMEOUT),
116 m_userObjectPointer(0),
120 m_linearDamping(0.04f),
121 m_angularDamping(0.04f),
123 m_maxAppliedImpulse(1000.f),
124 m_maxCoordinateVelocity(100.f),
125 m_hasSelfCollision(true),
130 m_useGlobalVelocities(false),
131 m_internalNeedsJointFeedback(false),
132 m_kinematic_calculate_velocity(false)
134 m_cachedInertiaTopLeft.setValue(0, 0, 0, 0, 0, 0, 0, 0, 0);
135 m_cachedInertiaTopRight.setValue(0, 0, 0, 0, 0, 0, 0, 0, 0);
136 m_cachedInertiaLowerLeft.setValue(0, 0, 0, 0, 0, 0, 0, 0, 0);
137 m_cachedInertiaLowerRight.setValue(0, 0, 0, 0, 0, 0, 0, 0, 0);
138 m_cachedInertiaValid = false;
140 m_links.resize(n_links);
141 m_matrixBuf.resize(n_links + 1);
143 m_baseForce.setValue(0, 0, 0);
144 m_baseTorque.setValue(0, 0, 0);
146 clearConstraintForces();
147 clearForcesAndTorques();
150 btMultiBody::~btMultiBody()
154 void btMultiBody::setupFixed(int i,
156 const btVector3 &inertia,
158 const btQuaternion &rotParentToThis,
159 const btVector3 &parentComToThisPivotOffset,
160 const btVector3 &thisPivotToThisComOffset, bool /*deprecatedDisableParentCollision*/)
162 m_links[i].m_mass = mass;
163 m_links[i].m_inertiaLocal = inertia;
164 m_links[i].m_parent = parent;
165 m_links[i].setAxisTop(0, 0., 0., 0.);
166 m_links[i].setAxisBottom(0, btVector3(0, 0, 0));
167 m_links[i].m_zeroRotParentToThis = rotParentToThis;
168 m_links[i].m_dVector = thisPivotToThisComOffset;
169 m_links[i].m_eVector = parentComToThisPivotOffset;
171 m_links[i].m_jointType = btMultibodyLink::eFixed;
172 m_links[i].m_dofCount = 0;
173 m_links[i].m_posVarCount = 0;
175 m_links[i].m_flags |= BT_MULTIBODYLINKFLAGS_DISABLE_PARENT_COLLISION;
177 m_links[i].updateCacheMultiDof();
179 updateLinksDofOffsets();
182 void btMultiBody::setupPrismatic(int i,
184 const btVector3 &inertia,
186 const btQuaternion &rotParentToThis,
187 const btVector3 &jointAxis,
188 const btVector3 &parentComToThisPivotOffset,
189 const btVector3 &thisPivotToThisComOffset,
190 bool disableParentCollision)
195 m_links[i].m_mass = mass;
196 m_links[i].m_inertiaLocal = inertia;
197 m_links[i].m_parent = parent;
198 m_links[i].m_zeroRotParentToThis = rotParentToThis;
199 m_links[i].setAxisTop(0, 0., 0., 0.);
200 m_links[i].setAxisBottom(0, jointAxis);
201 m_links[i].m_eVector = parentComToThisPivotOffset;
202 m_links[i].m_dVector = thisPivotToThisComOffset;
203 m_links[i].m_cachedRotParentToThis = rotParentToThis;
205 m_links[i].m_jointType = btMultibodyLink::ePrismatic;
206 m_links[i].m_dofCount = 1;
207 m_links[i].m_posVarCount = 1;
208 m_links[i].m_jointPos[0] = 0.f;
209 m_links[i].m_jointTorque[0] = 0.f;
211 if (disableParentCollision)
212 m_links[i].m_flags |= BT_MULTIBODYLINKFLAGS_DISABLE_PARENT_COLLISION;
215 m_links[i].updateCacheMultiDof();
217 updateLinksDofOffsets();
220 void btMultiBody::setupRevolute(int i,
222 const btVector3 &inertia,
224 const btQuaternion &rotParentToThis,
225 const btVector3 &jointAxis,
226 const btVector3 &parentComToThisPivotOffset,
227 const btVector3 &thisPivotToThisComOffset,
228 bool disableParentCollision)
233 m_links[i].m_mass = mass;
234 m_links[i].m_inertiaLocal = inertia;
235 m_links[i].m_parent = parent;
236 m_links[i].m_zeroRotParentToThis = rotParentToThis;
237 m_links[i].setAxisTop(0, jointAxis);
238 m_links[i].setAxisBottom(0, jointAxis.cross(thisPivotToThisComOffset));
239 m_links[i].m_dVector = thisPivotToThisComOffset;
240 m_links[i].m_eVector = parentComToThisPivotOffset;
242 m_links[i].m_jointType = btMultibodyLink::eRevolute;
243 m_links[i].m_dofCount = 1;
244 m_links[i].m_posVarCount = 1;
245 m_links[i].m_jointPos[0] = 0.f;
246 m_links[i].m_jointTorque[0] = 0.f;
248 if (disableParentCollision)
249 m_links[i].m_flags |= BT_MULTIBODYLINKFLAGS_DISABLE_PARENT_COLLISION;
251 m_links[i].updateCacheMultiDof();
253 updateLinksDofOffsets();
256 void btMultiBody::setupSpherical(int i,
258 const btVector3 &inertia,
260 const btQuaternion &rotParentToThis,
261 const btVector3 &parentComToThisPivotOffset,
262 const btVector3 &thisPivotToThisComOffset,
263 bool disableParentCollision)
268 m_links[i].m_mass = mass;
269 m_links[i].m_inertiaLocal = inertia;
270 m_links[i].m_parent = parent;
271 m_links[i].m_zeroRotParentToThis = rotParentToThis;
272 m_links[i].m_dVector = thisPivotToThisComOffset;
273 m_links[i].m_eVector = parentComToThisPivotOffset;
275 m_links[i].m_jointType = btMultibodyLink::eSpherical;
276 m_links[i].m_dofCount = 3;
277 m_links[i].m_posVarCount = 4;
278 m_links[i].setAxisTop(0, 1.f, 0.f, 0.f);
279 m_links[i].setAxisTop(1, 0.f, 1.f, 0.f);
280 m_links[i].setAxisTop(2, 0.f, 0.f, 1.f);
281 m_links[i].setAxisBottom(0, m_links[i].getAxisTop(0).cross(thisPivotToThisComOffset));
282 m_links[i].setAxisBottom(1, m_links[i].getAxisTop(1).cross(thisPivotToThisComOffset));
283 m_links[i].setAxisBottom(2, m_links[i].getAxisTop(2).cross(thisPivotToThisComOffset));
284 m_links[i].m_jointPos[0] = m_links[i].m_jointPos[1] = m_links[i].m_jointPos[2] = 0.f;
285 m_links[i].m_jointPos[3] = 1.f;
286 m_links[i].m_jointTorque[0] = m_links[i].m_jointTorque[1] = m_links[i].m_jointTorque[2] = 0.f;
288 if (disableParentCollision)
289 m_links[i].m_flags |= BT_MULTIBODYLINKFLAGS_DISABLE_PARENT_COLLISION;
291 m_links[i].updateCacheMultiDof();
293 updateLinksDofOffsets();
296 void btMultiBody::setupPlanar(int i,
298 const btVector3 &inertia,
300 const btQuaternion &rotParentToThis,
301 const btVector3 &rotationAxis,
302 const btVector3 &parentComToThisComOffset,
303 bool disableParentCollision)
308 m_links[i].m_mass = mass;
309 m_links[i].m_inertiaLocal = inertia;
310 m_links[i].m_parent = parent;
311 m_links[i].m_zeroRotParentToThis = rotParentToThis;
312 m_links[i].m_dVector.setZero();
313 m_links[i].m_eVector = parentComToThisComOffset;
316 btVector3 vecNonParallelToRotAxis(1, 0, 0);
317 if (rotationAxis.normalized().dot(vecNonParallelToRotAxis) > 0.999)
318 vecNonParallelToRotAxis.setValue(0, 1, 0);
321 m_links[i].m_jointType = btMultibodyLink::ePlanar;
322 m_links[i].m_dofCount = 3;
323 m_links[i].m_posVarCount = 3;
324 btVector3 n = rotationAxis.normalized();
325 m_links[i].setAxisTop(0, n[0], n[1], n[2]);
326 m_links[i].setAxisTop(1, 0, 0, 0);
327 m_links[i].setAxisTop(2, 0, 0, 0);
328 m_links[i].setAxisBottom(0, 0, 0, 0);
329 btVector3 cr = m_links[i].getAxisTop(0).cross(vecNonParallelToRotAxis);
330 m_links[i].setAxisBottom(1, cr[0], cr[1], cr[2]);
331 cr = m_links[i].getAxisBottom(1).cross(m_links[i].getAxisTop(0));
332 m_links[i].setAxisBottom(2, cr[0], cr[1], cr[2]);
333 m_links[i].m_jointPos[0] = m_links[i].m_jointPos[1] = m_links[i].m_jointPos[2] = 0.f;
334 m_links[i].m_jointTorque[0] = m_links[i].m_jointTorque[1] = m_links[i].m_jointTorque[2] = 0.f;
336 if (disableParentCollision)
337 m_links[i].m_flags |= BT_MULTIBODYLINKFLAGS_DISABLE_PARENT_COLLISION;
339 m_links[i].updateCacheMultiDof();
341 updateLinksDofOffsets();
343 m_links[i].setAxisBottom(1, m_links[i].getAxisBottom(1).normalized());
344 m_links[i].setAxisBottom(2, m_links[i].getAxisBottom(2).normalized());
347 void btMultiBody::finalizeMultiDof()
350 m_deltaV.resize(6 + m_dofCount);
352 m_splitV.resize(6 + m_dofCount);
353 m_realBuf.resize(6 + m_dofCount + m_dofCount * m_dofCount + 6 + m_dofCount); //m_dofCount for joint-space vels + m_dofCount^2 for "D" matrices + delta-pos vector (6 base "vels" + joint "vels")
354 m_vectorBuf.resize(2 * m_dofCount); //two 3-vectors (i.e. one six-vector) for each system dof ("h" matrices)
355 m_matrixBuf.resize(m_links.size() + 1);
356 for (int i = 0; i < m_vectorBuf.size(); i++)
358 m_vectorBuf[i].setValue(0, 0, 0);
360 updateLinksDofOffsets();
363 int btMultiBody::getParent(int link_num) const
365 return m_links[link_num].m_parent;
368 btScalar btMultiBody::getLinkMass(int i) const
370 return m_links[i].m_mass;
373 const btVector3 &btMultiBody::getLinkInertia(int i) const
375 return m_links[i].m_inertiaLocal;
378 btScalar btMultiBody::getJointPos(int i) const
380 return m_links[i].m_jointPos[0];
383 btScalar btMultiBody::getJointVel(int i) const
385 return m_realBuf[6 + m_links[i].m_dofOffset];
388 btScalar *btMultiBody::getJointPosMultiDof(int i)
390 return &m_links[i].m_jointPos[0];
393 btScalar *btMultiBody::getJointVelMultiDof(int i)
395 return &m_realBuf[6 + m_links[i].m_dofOffset];
398 const btScalar *btMultiBody::getJointPosMultiDof(int i) const
400 return &m_links[i].m_jointPos[0];
403 const btScalar *btMultiBody::getJointVelMultiDof(int i) const
405 return &m_realBuf[6 + m_links[i].m_dofOffset];
408 void btMultiBody::setJointPos(int i, btScalar q)
410 m_links[i].m_jointPos[0] = q;
411 m_links[i].updateCacheMultiDof();
415 void btMultiBody::setJointPosMultiDof(int i, const double *q)
417 for (int pos = 0; pos < m_links[i].m_posVarCount; ++pos)
418 m_links[i].m_jointPos[pos] = (btScalar)q[pos];
420 m_links[i].updateCacheMultiDof();
423 void btMultiBody::setJointPosMultiDof(int i, const float *q)
425 for (int pos = 0; pos < m_links[i].m_posVarCount; ++pos)
426 m_links[i].m_jointPos[pos] = (btScalar)q[pos];
428 m_links[i].updateCacheMultiDof();
433 void btMultiBody::setJointVel(int i, btScalar qdot)
435 m_realBuf[6 + m_links[i].m_dofOffset] = qdot;
438 void btMultiBody::setJointVelMultiDof(int i, const double *qdot)
440 for (int dof = 0; dof < m_links[i].m_dofCount; ++dof)
441 m_realBuf[6 + m_links[i].m_dofOffset + dof] = (btScalar)qdot[dof];
444 void btMultiBody::setJointVelMultiDof(int i, const float* qdot)
446 for (int dof = 0; dof < m_links[i].m_dofCount; ++dof)
447 m_realBuf[6 + m_links[i].m_dofOffset + dof] = (btScalar)qdot[dof];
450 const btVector3 &btMultiBody::getRVector(int i) const
452 return m_links[i].m_cachedRVector;
455 const btQuaternion &btMultiBody::getParentToLocalRot(int i) const
457 return m_links[i].m_cachedRotParentToThis;
460 const btVector3 &btMultiBody::getInterpolateRVector(int i) const
462 return m_links[i].m_cachedRVector_interpolate;
465 const btQuaternion &btMultiBody::getInterpolateParentToLocalRot(int i) const
467 return m_links[i].m_cachedRotParentToThis_interpolate;
470 btVector3 btMultiBody::localPosToWorld(int i, const btVector3 &local_pos) const
473 btAssert(i < m_links.size());
474 if ((i < -1) || (i >= m_links.size()))
476 return btVector3(SIMD_INFINITY, SIMD_INFINITY, SIMD_INFINITY);
479 btVector3 result = local_pos;
482 // 'result' is in frame i. transform it to frame parent(i)
483 result += getRVector(i);
484 result = quatRotate(getParentToLocalRot(i).inverse(), result);
488 // 'result' is now in the base frame. transform it to world frame
489 result = quatRotate(getWorldToBaseRot().inverse(), result);
490 result += getBasePos();
495 btVector3 btMultiBody::worldPosToLocal(int i, const btVector3 &world_pos) const
498 btAssert(i < m_links.size());
499 if ((i < -1) || (i >= m_links.size()))
501 return btVector3(SIMD_INFINITY, SIMD_INFINITY, SIMD_INFINITY);
507 return quatRotate(getWorldToBaseRot(), (world_pos - getBasePos()));
511 // find position in parent frame, then transform to current frame
512 return quatRotate(getParentToLocalRot(i), worldPosToLocal(getParent(i), world_pos)) - getRVector(i);
516 btVector3 btMultiBody::localDirToWorld(int i, const btVector3 &local_dir) const
519 btAssert(i < m_links.size());
520 if ((i < -1) || (i >= m_links.size()))
522 return btVector3(SIMD_INFINITY, SIMD_INFINITY, SIMD_INFINITY);
525 btVector3 result = local_dir;
528 result = quatRotate(getParentToLocalRot(i).inverse(), result);
531 result = quatRotate(getWorldToBaseRot().inverse(), result);
535 btVector3 btMultiBody::worldDirToLocal(int i, const btVector3 &world_dir) const
538 btAssert(i < m_links.size());
539 if ((i < -1) || (i >= m_links.size()))
541 return btVector3(SIMD_INFINITY, SIMD_INFINITY, SIMD_INFINITY);
546 return quatRotate(getWorldToBaseRot(), world_dir);
550 return quatRotate(getParentToLocalRot(i), worldDirToLocal(getParent(i), world_dir));
554 btMatrix3x3 btMultiBody::localFrameToWorld(int i, const btMatrix3x3 &local_frame) const
556 btMatrix3x3 result = local_frame;
557 btVector3 frameInWorld0 = localDirToWorld(i, local_frame.getColumn(0));
558 btVector3 frameInWorld1 = localDirToWorld(i, local_frame.getColumn(1));
559 btVector3 frameInWorld2 = localDirToWorld(i, local_frame.getColumn(2));
560 result.setValue(frameInWorld0[0], frameInWorld1[0], frameInWorld2[0], frameInWorld0[1], frameInWorld1[1], frameInWorld2[1], frameInWorld0[2], frameInWorld1[2], frameInWorld2[2]);
564 void btMultiBody::compTreeLinkVelocities(btVector3 *omega, btVector3 *vel) const
566 int num_links = getNumLinks();
567 // Calculates the velocities of each link (and the base) in its local frame
568 const btQuaternion& base_rot = getWorldToBaseRot();
569 omega[0] = quatRotate(base_rot, getBaseOmega());
570 vel[0] = quatRotate(base_rot, getBaseVel());
572 for (int i = 0; i < num_links; ++i)
574 const btMultibodyLink& link = getLink(i);
575 const int parent = link.m_parent;
577 // transform parent vel into this frame, store in omega[i+1], vel[i+1]
578 spatialTransform(btMatrix3x3(link.m_cachedRotParentToThis), link.m_cachedRVector,
579 omega[parent + 1], vel[parent + 1],
580 omega[i + 1], vel[i + 1]);
582 // now add qidot * shat_i
583 const btScalar* jointVel = getJointVelMultiDof(i);
584 for (int dof = 0; dof < link.m_dofCount; ++dof)
586 omega[i + 1] += jointVel[dof] * link.getAxisTop(dof);
587 vel[i + 1] += jointVel[dof] * link.getAxisBottom(dof);
593 void btMultiBody::clearConstraintForces()
595 m_baseConstraintForce.setValue(0, 0, 0);
596 m_baseConstraintTorque.setValue(0, 0, 0);
598 for (int i = 0; i < getNumLinks(); ++i)
600 m_links[i].m_appliedConstraintForce.setValue(0, 0, 0);
601 m_links[i].m_appliedConstraintTorque.setValue(0, 0, 0);
604 void btMultiBody::clearForcesAndTorques()
606 m_baseForce.setValue(0, 0, 0);
607 m_baseTorque.setValue(0, 0, 0);
609 for (int i = 0; i < getNumLinks(); ++i)
611 m_links[i].m_appliedForce.setValue(0, 0, 0);
612 m_links[i].m_appliedTorque.setValue(0, 0, 0);
613 m_links[i].m_jointTorque[0] = m_links[i].m_jointTorque[1] = m_links[i].m_jointTorque[2] = m_links[i].m_jointTorque[3] = m_links[i].m_jointTorque[4] = m_links[i].m_jointTorque[5] = 0.f;
617 void btMultiBody::clearVelocities()
619 for (int i = 0; i < 6 + getNumDofs(); ++i)
624 void btMultiBody::addLinkForce(int i, const btVector3 &f)
626 m_links[i].m_appliedForce += f;
629 void btMultiBody::addLinkTorque(int i, const btVector3 &t)
631 m_links[i].m_appliedTorque += t;
634 void btMultiBody::addLinkConstraintForce(int i, const btVector3 &f)
636 m_links[i].m_appliedConstraintForce += f;
639 void btMultiBody::addLinkConstraintTorque(int i, const btVector3 &t)
641 m_links[i].m_appliedConstraintTorque += t;
644 void btMultiBody::addJointTorque(int i, btScalar Q)
646 m_links[i].m_jointTorque[0] += Q;
649 void btMultiBody::addJointTorqueMultiDof(int i, int dof, btScalar Q)
651 m_links[i].m_jointTorque[dof] += Q;
654 void btMultiBody::addJointTorqueMultiDof(int i, const btScalar *Q)
656 for (int dof = 0; dof < m_links[i].m_dofCount; ++dof)
657 m_links[i].m_jointTorque[dof] = Q[dof];
660 const btVector3 &btMultiBody::getLinkForce(int i) const
662 return m_links[i].m_appliedForce;
665 const btVector3 &btMultiBody::getLinkTorque(int i) const
667 return m_links[i].m_appliedTorque;
670 btScalar btMultiBody::getJointTorque(int i) const
672 return m_links[i].m_jointTorque[0];
675 btScalar *btMultiBody::getJointTorqueMultiDof(int i)
677 return &m_links[i].m_jointTorque[0];
680 bool btMultiBody::hasFixedBase() const
682 return m_fixedBase || (getBaseCollider() && getBaseCollider()->isStaticObject());
685 bool btMultiBody::isBaseStaticOrKinematic() const
687 return m_fixedBase || (getBaseCollider() && getBaseCollider()->isStaticOrKinematicObject());
690 bool btMultiBody::isBaseKinematic() const
692 return getBaseCollider() && getBaseCollider()->isKinematicObject();
695 void btMultiBody::setBaseDynamicType(int dynamicType)
697 if(getBaseCollider()) {
698 int oldFlags = getBaseCollider()->getCollisionFlags();
699 oldFlags &= ~(btCollisionObject::CF_STATIC_OBJECT | btCollisionObject::CF_KINEMATIC_OBJECT);
700 getBaseCollider()->setCollisionFlags(oldFlags | dynamicType);
704 inline btMatrix3x3 outerProduct(const btVector3 &v0, const btVector3 &v1) //renamed it from vecMulVecTranspose (http://en.wikipedia.org/wiki/Outer_product); maybe it should be moved to btVector3 like dot and cross?
706 btVector3 row0 = btVector3(
710 btVector3 row1 = btVector3(
714 btVector3 row2 = btVector3(
719 btMatrix3x3 m(row0[0], row0[1], row0[2],
720 row1[0], row1[1], row1[2],
721 row2[0], row2[1], row2[2]);
725 #define vecMulVecTranspose(v0, v1Transposed) outerProduct(v0, v1Transposed)
728 void btMultiBody::computeAccelerationsArticulatedBodyAlgorithmMultiDof(btScalar dt,
729 btAlignedObjectArray<btScalar> &scratch_r,
730 btAlignedObjectArray<btVector3> &scratch_v,
731 btAlignedObjectArray<btMatrix3x3> &scratch_m,
732 bool isConstraintPass,
733 bool jointFeedbackInWorldSpace,
734 bool jointFeedbackInJointFrame)
736 // Implement Featherstone's algorithm to calculate joint accelerations (q_double_dot)
737 // and the base linear & angular accelerations.
739 // We apply damping forces in this routine as well as any external forces specified by the
740 // caller (via addBaseForce etc).
742 // output should point to an array of 6 + num_links reals.
743 // Format is: 3 angular accelerations (in world frame), 3 linear accelerations (in world frame),
744 // num_links joint acceleration values.
746 // We added support for multi degree of freedom (multi dof) joints.
747 // In addition we also can compute the joint reaction forces. This is performed in a second pass,
748 // so that we can include the effect of the constraint solver forces (computed in the PGS LCP solver)
750 m_internalNeedsJointFeedback = false;
752 int num_links = getNumLinks();
754 const btScalar DAMPING_K1_LINEAR = m_linearDamping;
755 const btScalar DAMPING_K2_LINEAR = m_linearDamping;
757 const btScalar DAMPING_K1_ANGULAR = m_angularDamping;
758 const btScalar DAMPING_K2_ANGULAR = m_angularDamping;
760 const btVector3 base_vel = getBaseVel();
761 const btVector3 base_omega = getBaseOmega();
763 // Temporary matrices/vectors -- use scratch space from caller
764 // so that we don't have to keep reallocating every frame
766 scratch_r.resize(2 * m_dofCount + 7); //multidof? ("Y"s use it and it is used to store qdd) => 2 x m_dofCount
767 scratch_v.resize(8 * num_links + 6);
768 scratch_m.resize(4 * num_links + 4);
770 //btScalar * r_ptr = &scratch_r[0];
771 btScalar *output = &scratch_r[m_dofCount]; // "output" holds the q_double_dot results
772 btVector3 *v_ptr = &scratch_v[0];
774 // vhat_i (top = angular, bottom = linear part)
775 btSpatialMotionVector *spatVel = (btSpatialMotionVector *)v_ptr;
776 v_ptr += num_links * 2 + 2;
779 btSpatialForceVector *zeroAccSpatFrc = (btSpatialForceVector *)v_ptr;
780 v_ptr += num_links * 2 + 2;
782 // chat_i (note NOT defined for the base)
783 btSpatialMotionVector *spatCoriolisAcc = (btSpatialMotionVector *)v_ptr;
784 v_ptr += num_links * 2;
787 btSymmetricSpatialDyad *spatInertia = (btSymmetricSpatialDyad *)&scratch_m[num_links + 1];
789 // Cached 3x3 rotation matrices from parent frame to this frame.
790 btMatrix3x3 *rot_from_parent = &m_matrixBuf[0];
791 btMatrix3x3 *rot_from_world = &scratch_m[0];
794 // hhat is NOT stored for the base (but ahat is)
795 btSpatialForceVector *h = (btSpatialForceVector *)(m_dofCount > 0 ? &m_vectorBuf[0] : 0);
796 btSpatialMotionVector *spatAcc = (btSpatialMotionVector *)v_ptr;
797 v_ptr += num_links * 2 + 2;
800 btScalar *invD = m_dofCount > 0 ? &m_realBuf[6 + m_dofCount] : 0;
801 btScalar *Y = &scratch_r[0];
804 btSpatialMotionVector spatJointVel; //spatial velocity due to the joint motion (i.e. without predecessors' influence)
805 btScalar D[36]; //"D" matrix; it's dofxdof for each body so asingle 6x6 D matrix will do
806 btScalar invD_times_Y[6]; //D^{-1} * Y [dofxdof x dofx1 = dofx1] <=> D^{-1} * u; better moved to buffers since it is recalced in calcAccelerationDeltasMultiDof; num_dof of btScalar would cover all bodies
807 btSpatialMotionVector result; //holds results of the SolveImatrix op; it is a spatial motion vector (accel)
808 btScalar Y_minus_hT_a[6]; //Y - h^{T} * a; it's dofx1 for each body so a single 6x1 temp is enough
809 btSpatialForceVector spatForceVecTemps[6]; //6 temporary spatial force vectors
810 btSpatialTransformationMatrix fromParent; //spatial transform from parent to child
811 btSymmetricSpatialDyad dyadTemp; //inertia matrix temp
812 btSpatialTransformationMatrix fromWorld;
813 fromWorld.m_trnVec.setZero();
816 // ptr to the joint accel part of the output
817 btScalar *joint_accel = output + 6;
819 // Start of the algorithm proper.
821 // First 'upward' loop.
822 // Combines CompTreeLinkVelocities and InitTreeLinks from Mirtich.
824 rot_from_parent[0] = btMatrix3x3(m_baseQuat); //m_baseQuat assumed to be alias!?
826 //create the vector of spatial velocity of the base by transforming global-coor linear and angular velocities into base-local coordinates
827 spatVel[0].setVector(rot_from_parent[0] * base_omega, rot_from_parent[0] * base_vel);
829 if (isBaseStaticOrKinematic())
831 zeroAccSpatFrc[0].setZero();
835 const btVector3 &baseForce = isConstraintPass ? m_baseConstraintForce : m_baseForce;
836 const btVector3 &baseTorque = isConstraintPass ? m_baseConstraintTorque : m_baseTorque;
838 zeroAccSpatFrc[0].setVector(-(rot_from_parent[0] * baseTorque), -(rot_from_parent[0] * baseForce));
840 //adding damping terms (only)
841 const btScalar linDampMult = 1., angDampMult = 1.;
842 zeroAccSpatFrc[0].addVector(angDampMult * m_baseInertia * spatVel[0].getAngular() * (DAMPING_K1_ANGULAR + DAMPING_K2_ANGULAR * spatVel[0].getAngular().safeNorm()),
843 linDampMult * m_baseMass * spatVel[0].getLinear() * (DAMPING_K1_LINEAR + DAMPING_K2_LINEAR * spatVel[0].getLinear().safeNorm()));
846 //p += vhat x Ihat vhat - done in a simpler way
848 zeroAccSpatFrc[0].addAngular(spatVel[0].getAngular().cross(m_baseInertia * spatVel[0].getAngular()));
850 zeroAccSpatFrc[0].addLinear(m_baseMass * spatVel[0].getAngular().cross(spatVel[0].getLinear()));
853 //init the spatial AB inertia (it has the simple form thanks to choosing local body frames origins at their COMs)
854 spatInertia[0].setMatrix(btMatrix3x3(0, 0, 0, 0, 0, 0, 0, 0, 0),
856 btMatrix3x3(m_baseMass, 0, 0,
860 btMatrix3x3(m_baseInertia[0], 0, 0,
861 0, m_baseInertia[1], 0,
862 0, 0, m_baseInertia[2]));
864 rot_from_world[0] = rot_from_parent[0];
867 for (int i = 0; i < num_links; ++i)
869 const int parent = m_links[i].m_parent;
870 rot_from_parent[i + 1] = btMatrix3x3(m_links[i].m_cachedRotParentToThis);
871 rot_from_world[i + 1] = rot_from_parent[i + 1] * rot_from_world[parent + 1];
873 fromParent.m_rotMat = rot_from_parent[i + 1];
874 fromParent.m_trnVec = m_links[i].m_cachedRVector;
875 fromWorld.m_rotMat = rot_from_world[i + 1];
876 fromParent.transform(spatVel[parent + 1], spatVel[i + 1]);
878 // now set vhat_i to its true value by doing
879 // vhat_i += qidot * shat_i
880 if (!m_useGlobalVelocities)
882 spatJointVel.setZero();
884 for (int dof = 0; dof < m_links[i].m_dofCount; ++dof)
885 spatJointVel += m_links[i].m_axes[dof] * getJointVelMultiDof(i)[dof];
887 // remember vhat_i is really vhat_p(i) (but in current frame) at this point => we need to add velocity across the inboard joint
888 spatVel[i + 1] += spatJointVel;
891 // vhat_i is vhat_p(i) transformed to local coors + the velocity across the i-th inboard joint
892 //spatVel[i+1] = fromParent * spatVel[parent+1] + spatJointVel;
896 fromWorld.transformRotationOnly(m_links[i].m_absFrameTotVelocity, spatVel[i + 1]);
897 fromWorld.transformRotationOnly(m_links[i].m_absFrameLocVelocity, spatJointVel);
900 // we can now calculate chat_i
901 spatVel[i + 1].cross(spatJointVel, spatCoriolisAcc[i]);
903 // calculate zhat_i^A
905 if (isLinkAndAllAncestorsKinematic(i))
907 zeroAccSpatFrc[i].setZero();
911 btVector3 linkAppliedForce = isConstraintPass ? m_links[i].m_appliedConstraintForce : m_links[i].m_appliedForce;
912 btVector3 linkAppliedTorque = isConstraintPass ? m_links[i].m_appliedConstraintTorque : m_links[i].m_appliedTorque;
914 zeroAccSpatFrc[i + 1].setVector(-(rot_from_world[i + 1] * linkAppliedTorque), -(rot_from_world[i + 1] * linkAppliedForce));
919 b3Printf("stepVelocitiesMultiDof zeroAccSpatFrc[%d] linear:%f,%f,%f, angular:%f,%f,%f",
921 zeroAccSpatFrc[i+1].m_topVec[0],
922 zeroAccSpatFrc[i+1].m_topVec[1],
923 zeroAccSpatFrc[i+1].m_topVec[2],
925 zeroAccSpatFrc[i+1].m_bottomVec[0],
926 zeroAccSpatFrc[i+1].m_bottomVec[1],
927 zeroAccSpatFrc[i+1].m_bottomVec[2]);
931 //adding damping terms (only)
932 btScalar linDampMult = 1., angDampMult = 1.;
933 zeroAccSpatFrc[i + 1].addVector(angDampMult * m_links[i].m_inertiaLocal * spatVel[i + 1].getAngular() * (DAMPING_K1_ANGULAR + DAMPING_K2_ANGULAR * spatVel[i + 1].getAngular().safeNorm()),
934 linDampMult * m_links[i].m_mass * spatVel[i + 1].getLinear() * (DAMPING_K1_LINEAR + DAMPING_K2_LINEAR * spatVel[i + 1].getLinear().safeNorm()));
935 //p += vhat x Ihat vhat - done in a simpler way
937 zeroAccSpatFrc[i + 1].addAngular(spatVel[i + 1].getAngular().cross(m_links[i].m_inertiaLocal * spatVel[i + 1].getAngular()));
939 zeroAccSpatFrc[i + 1].addLinear(m_links[i].m_mass * spatVel[i + 1].getAngular().cross(spatVel[i + 1].getLinear()));
941 //btVector3 temp = m_links[i].m_mass * spatVel[i+1].getAngular().cross(spatVel[i+1].getLinear());
942 ////clamp parent's omega
943 //btScalar parOmegaMod = temp.length();
944 //btScalar parOmegaModMax = 1000;
945 //if(parOmegaMod > parOmegaModMax)
946 // temp *= parOmegaModMax / parOmegaMod;
947 //zeroAccSpatFrc[i+1].addLinear(temp);
948 //printf("|zeroAccSpatFrc[%d]| = %.4f\n", i+1, temp.length());
949 //temp = spatCoriolisAcc[i].getLinear();
950 //printf("|spatCoriolisAcc[%d]| = %.4f\n", i+1, temp.length());
953 // calculate Ihat_i^A
954 //init the spatial AB inertia (it has the simple form thanks to choosing local body frames origins at their COMs)
955 spatInertia[i + 1].setMatrix(btMatrix3x3(0, 0, 0, 0, 0, 0, 0, 0, 0),
957 btMatrix3x3(m_links[i].m_mass, 0, 0,
958 0, m_links[i].m_mass, 0,
959 0, 0, m_links[i].m_mass),
961 btMatrix3x3(m_links[i].m_inertiaLocal[0], 0, 0,
962 0, m_links[i].m_inertiaLocal[1], 0,
963 0, 0, m_links[i].m_inertiaLocal[2]));
965 //printf("w[%d] = [%.4f %.4f %.4f]\n", i, vel_top_angular[i+1].x(), vel_top_angular[i+1].y(), vel_top_angular[i+1].z());
966 //printf("v[%d] = [%.4f %.4f %.4f]\n", i, vel_bottom_linear[i+1].x(), vel_bottom_linear[i+1].y(), vel_bottom_linear[i+1].z());
967 //printf("c[%d] = [%.4f %.4f %.4f]\n", i, coriolis_bottom_linear[i].x(), coriolis_bottom_linear[i].y(), coriolis_bottom_linear[i].z());
971 // (part of TreeForwardDynamics in Mirtich.)
972 for (int i = num_links - 1; i >= 0; --i)
974 if(isLinkAndAllAncestorsKinematic(i))
976 const int parent = m_links[i].m_parent;
977 fromParent.m_rotMat = rot_from_parent[i + 1];
978 fromParent.m_trnVec = m_links[i].m_cachedRVector;
980 for (int dof = 0; dof < m_links[i].m_dofCount; ++dof)
982 btSpatialForceVector &hDof = h[m_links[i].m_dofOffset + dof];
984 hDof = spatInertia[i + 1] * m_links[i].m_axes[dof];
986 Y[m_links[i].m_dofOffset + dof] = m_links[i].m_jointTorque[dof] - m_links[i].m_axes[dof].dot(zeroAccSpatFrc[i + 1]) - spatCoriolisAcc[i].dot(hDof);
988 for (int dof = 0; dof < m_links[i].m_dofCount; ++dof)
990 btScalar *D_row = &D[dof * m_links[i].m_dofCount];
991 for (int dof2 = 0; dof2 < m_links[i].m_dofCount; ++dof2)
993 const btSpatialForceVector &hDof2 = h[m_links[i].m_dofOffset + dof2];
994 D_row[dof2] = m_links[i].m_axes[dof].dot(hDof2);
998 btScalar *invDi = &invD[m_links[i].m_dofOffset * m_links[i].m_dofOffset];
999 switch (m_links[i].m_jointType)
1001 case btMultibodyLink::ePrismatic:
1002 case btMultibodyLink::eRevolute:
1004 if (D[0] >= SIMD_EPSILON)
1006 invDi[0] = 1.0f / D[0];
1014 case btMultibodyLink::eSpherical:
1015 case btMultibodyLink::ePlanar:
1017 const btMatrix3x3 D3x3(D[0], D[1], D[2], D[3], D[4], D[5], D[6], D[7], D[8]);
1018 const btMatrix3x3 invD3x3(D3x3.inverse());
1021 for (int row = 0; row < 3; ++row)
1023 for (int col = 0; col < 3; ++col)
1025 invDi[row * 3 + col] = invD3x3[row][col];
1036 //determine h*D^{-1}
1037 for (int dof = 0; dof < m_links[i].m_dofCount; ++dof)
1039 spatForceVecTemps[dof].setZero();
1041 for (int dof2 = 0; dof2 < m_links[i].m_dofCount; ++dof2)
1043 const btSpatialForceVector &hDof2 = h[m_links[i].m_dofOffset + dof2];
1045 spatForceVecTemps[dof] += hDof2 * invDi[dof2 * m_links[i].m_dofCount + dof];
1049 dyadTemp = spatInertia[i + 1];
1051 //determine (h*D^{-1}) * h^{T}
1052 for (int dof = 0; dof < m_links[i].m_dofCount; ++dof)
1054 const btSpatialForceVector &hDof = h[m_links[i].m_dofOffset + dof];
1056 dyadTemp -= symmetricSpatialOuterProduct(hDof, spatForceVecTemps[dof]);
1059 fromParent.transformInverse(dyadTemp, spatInertia[parent + 1], btSpatialTransformationMatrix::Add);
1061 for (int dof = 0; dof < m_links[i].m_dofCount; ++dof)
1063 invD_times_Y[dof] = 0.f;
1065 for (int dof2 = 0; dof2 < m_links[i].m_dofCount; ++dof2)
1067 invD_times_Y[dof] += invDi[dof * m_links[i].m_dofCount + dof2] * Y[m_links[i].m_dofOffset + dof2];
1071 spatForceVecTemps[0] = zeroAccSpatFrc[i + 1] + spatInertia[i + 1] * spatCoriolisAcc[i];
1073 for (int dof = 0; dof < m_links[i].m_dofCount; ++dof)
1075 const btSpatialForceVector &hDof = h[m_links[i].m_dofOffset + dof];
1077 spatForceVecTemps[0] += hDof * invD_times_Y[dof];
1080 fromParent.transformInverse(spatForceVecTemps[0], spatForceVecTemps[1]);
1082 zeroAccSpatFrc[parent + 1] += spatForceVecTemps[1];
1085 // Second 'upward' loop
1086 // (part of TreeForwardDynamics in Mirtich)
1088 if (isBaseStaticOrKinematic())
1090 spatAcc[0].setZero();
1096 m_cachedInertiaValid = true;
1097 m_cachedInertiaTopLeft = spatInertia[0].m_topLeftMat;
1098 m_cachedInertiaTopRight = spatInertia[0].m_topRightMat;
1099 m_cachedInertiaLowerLeft = spatInertia[0].m_bottomLeftMat;
1100 m_cachedInertiaLowerRight = spatInertia[0].m_topLeftMat.transpose();
1103 solveImatrix(zeroAccSpatFrc[0], result);
1104 spatAcc[0] = -result;
1107 // now do the loop over the m_links
1108 for (int i = 0; i < num_links; ++i)
1110 // qdd = D^{-1} * (Y - h^{T}*apar) = (S^{T}*I*S)^{-1} * (tau - S^{T}*I*cor - S^{T}*zeroAccFrc - S^{T}*I*apar)
1111 // a = apar + cor + Sqdd
1113 // qdd = D^{-1} * (Y - h^{T}*(apar+cor))
1116 const int parent = m_links[i].m_parent;
1117 fromParent.m_rotMat = rot_from_parent[i + 1];
1118 fromParent.m_trnVec = m_links[i].m_cachedRVector;
1120 fromParent.transform(spatAcc[parent + 1], spatAcc[i + 1]);
1122 if(!isLinkAndAllAncestorsKinematic(i))
1124 for (int dof = 0; dof < m_links[i].m_dofCount; ++dof)
1126 const btSpatialForceVector &hDof = h[m_links[i].m_dofOffset + dof];
1128 Y_minus_hT_a[dof] = Y[m_links[i].m_dofOffset + dof] - spatAcc[i + 1].dot(hDof);
1130 btScalar *invDi = &invD[m_links[i].m_dofOffset * m_links[i].m_dofOffset];
1131 //D^{-1} * (Y - h^{T}*apar)
1132 mulMatrix(invDi, Y_minus_hT_a, m_links[i].m_dofCount, m_links[i].m_dofCount, m_links[i].m_dofCount, 1, &joint_accel[m_links[i].m_dofOffset]);
1134 spatAcc[i + 1] += spatCoriolisAcc[i];
1136 for (int dof = 0; dof < m_links[i].m_dofCount; ++dof)
1137 spatAcc[i + 1] += m_links[i].m_axes[dof] * joint_accel[m_links[i].m_dofOffset + dof];
1140 if (m_links[i].m_jointFeedback)
1142 m_internalNeedsJointFeedback = true;
1144 btVector3 angularBotVec = (spatInertia[i + 1] * spatAcc[i + 1] + zeroAccSpatFrc[i + 1]).m_bottomVec;
1145 btVector3 linearTopVec = (spatInertia[i + 1] * spatAcc[i + 1] + zeroAccSpatFrc[i + 1]).m_topVec;
1147 if (jointFeedbackInJointFrame)
1149 //shift the reaction forces to the joint frame
1150 //linear (force) component is the same
1151 //shift the angular (torque, moment) component using the relative position, m_links[i].m_dVector
1152 angularBotVec = angularBotVec - linearTopVec.cross(m_links[i].m_dVector);
1155 if (jointFeedbackInWorldSpace)
1157 if (isConstraintPass)
1159 m_links[i].m_jointFeedback->m_reactionForces.m_bottomVec += m_links[i].m_cachedWorldTransform.getBasis() * angularBotVec;
1160 m_links[i].m_jointFeedback->m_reactionForces.m_topVec += m_links[i].m_cachedWorldTransform.getBasis() * linearTopVec;
1164 m_links[i].m_jointFeedback->m_reactionForces.m_bottomVec = m_links[i].m_cachedWorldTransform.getBasis() * angularBotVec;
1165 m_links[i].m_jointFeedback->m_reactionForces.m_topVec = m_links[i].m_cachedWorldTransform.getBasis() * linearTopVec;
1170 if (isConstraintPass)
1172 m_links[i].m_jointFeedback->m_reactionForces.m_bottomVec += angularBotVec;
1173 m_links[i].m_jointFeedback->m_reactionForces.m_topVec += linearTopVec;
1177 m_links[i].m_jointFeedback->m_reactionForces.m_bottomVec = angularBotVec;
1178 m_links[i].m_jointFeedback->m_reactionForces.m_topVec = linearTopVec;
1184 // transform base accelerations back to the world frame.
1185 const btVector3 omegadot_out = rot_from_parent[0].transpose() * spatAcc[0].getAngular();
1186 output[0] = omegadot_out[0];
1187 output[1] = omegadot_out[1];
1188 output[2] = omegadot_out[2];
1190 const btVector3 vdot_out = rot_from_parent[0].transpose() * (spatAcc[0].getLinear() + spatVel[0].getAngular().cross(spatVel[0].getLinear()));
1191 output[3] = vdot_out[0];
1192 output[4] = vdot_out[1];
1193 output[5] = vdot_out[2];
1197 //printf("%.6f, %.6f, %.6f, %.6f, %.6f, %.6f, %.6f ", m_baseQuat.x(), m_baseQuat.y(), m_baseQuat.z(), m_baseQuat.w(), m_basePos.x(), m_basePos.y(), m_basePos.z());
1198 //for(int link = 0; link < getNumLinks(); ++link)
1199 // for(int dof = 0; dof < m_links[link].m_dofCount; ++dof)
1200 // printf("%.6f ", m_links[link].m_jointPos[dof]);
1204 //for(int dof = 0; dof < getNumDofs() + 6; ++dof)
1205 // printf("%.6f ", m_realBuf[dof]);
1207 //printf("qdd = [");
1208 //for(int dof = 0; dof < getNumDofs() + 6; ++dof)
1209 // printf("%.6f ", output[dof]);
1213 // Final step: add the accelerations (times dt) to the velocities.
1215 if (!isConstraintPass)
1218 applyDeltaVeeMultiDof(output, dt);
1221 //btScalar angularThres = 1;
1222 //btScalar maxAngVel = 0.;
1223 //bool scaleDown = 1.;
1224 //for(int link = 0; link < m_links.size(); ++link)
1226 // if(spatVel[link+1].getAngular().length() > maxAngVel)
1228 // maxAngVel = spatVel[link+1].getAngular().length();
1229 // scaleDown = angularThres / spatVel[link+1].getAngular().length();
1234 //if(scaleDown != 1.)
1236 // for(int link = 0; link < m_links.size(); ++link)
1238 // if(m_links[link].m_jointType == btMultibodyLink::eRevolute || m_links[link].m_jointType == btMultibodyLink::eSpherical)
1240 // for(int dof = 0; dof < m_links[link].m_dofCount; ++dof)
1241 // getJointVelMultiDof(link)[dof] *= scaleDown;
1247 /////////////////////
1248 if (m_useGlobalVelocities)
1250 for (int i = 0; i < num_links; ++i)
1252 const int parent = m_links[i].m_parent;
1253 //rot_from_parent[i+1] = btMatrix3x3(m_links[i].m_cachedRotParentToThis); /// <- done
1254 //rot_from_world[i+1] = rot_from_parent[i+1] * rot_from_world[parent+1]; /// <- done
1256 fromParent.m_rotMat = rot_from_parent[i + 1];
1257 fromParent.m_trnVec = m_links[i].m_cachedRVector;
1258 fromWorld.m_rotMat = rot_from_world[i + 1];
1260 // vhat_i = i_xhat_p(i) * vhat_p(i)
1261 fromParent.transform(spatVel[parent + 1], spatVel[i + 1]);
1262 //nice alternative below (using operator *) but it generates temps
1263 /////////////////////////////////////////////////////////////
1265 // now set vhat_i to its true value by doing
1266 // vhat_i += qidot * shat_i
1267 spatJointVel.setZero();
1269 for (int dof = 0; dof < m_links[i].m_dofCount; ++dof)
1270 spatJointVel += m_links[i].m_axes[dof] * getJointVelMultiDof(i)[dof];
1272 // remember vhat_i is really vhat_p(i) (but in current frame) at this point => we need to add velocity across the inboard joint
1273 spatVel[i + 1] += spatJointVel;
1275 fromWorld.transformInverseRotationOnly(spatVel[i + 1], m_links[i].m_absFrameTotVelocity);
1276 fromWorld.transformInverseRotationOnly(spatJointVel, m_links[i].m_absFrameLocVelocity);
1281 void btMultiBody::solveImatrix(const btVector3 &rhs_top, const btVector3 &rhs_bot, btScalar result[6]) const
1283 int num_links = getNumLinks();
1284 ///solve I * x = rhs, so the result = invI * rhs
1287 // in the case of 0 m_links (i.e. a plain rigid body, not a multibody) rhs * invI is easier
1289 if ((m_baseInertia[0] >= SIMD_EPSILON) && (m_baseInertia[1] >= SIMD_EPSILON) && (m_baseInertia[2] >= SIMD_EPSILON))
1291 result[0] = rhs_bot[0] / m_baseInertia[0];
1292 result[1] = rhs_bot[1] / m_baseInertia[1];
1293 result[2] = rhs_bot[2] / m_baseInertia[2];
1301 if (m_baseMass >= SIMD_EPSILON)
1303 result[3] = rhs_top[0] / m_baseMass;
1304 result[4] = rhs_top[1] / m_baseMass;
1305 result[5] = rhs_top[2] / m_baseMass;
1316 if (!m_cachedInertiaValid)
1318 for (int i = 0; i < 6; i++)
1324 /// Special routine for calculating the inverse of a spatial inertia matrix
1325 ///the 6x6 matrix is stored as 4 blocks of 3x3 matrices
1326 btMatrix3x3 Binv = m_cachedInertiaTopRight.inverse() * -1.f;
1327 btMatrix3x3 tmp = m_cachedInertiaLowerRight * Binv;
1328 btMatrix3x3 invIupper_right = (tmp * m_cachedInertiaTopLeft + m_cachedInertiaLowerLeft).inverse();
1329 tmp = invIupper_right * m_cachedInertiaLowerRight;
1330 btMatrix3x3 invI_upper_left = (tmp * Binv);
1331 btMatrix3x3 invI_lower_right = (invI_upper_left).transpose();
1332 tmp = m_cachedInertiaTopLeft * invI_upper_left;
1336 btMatrix3x3 invI_lower_left = (Binv * tmp);
1338 //multiply result = invI * rhs
1340 btVector3 vtop = invI_upper_left * rhs_top;
1342 tmp = invIupper_right * rhs_bot;
1344 btVector3 vbot = invI_lower_left * rhs_top;
1345 tmp = invI_lower_right * rhs_bot;
1347 result[0] = vtop[0];
1348 result[1] = vtop[1];
1349 result[2] = vtop[2];
1350 result[3] = vbot[0];
1351 result[4] = vbot[1];
1352 result[5] = vbot[2];
1356 void btMultiBody::solveImatrix(const btSpatialForceVector &rhs, btSpatialMotionVector &result) const
1358 int num_links = getNumLinks();
1359 ///solve I * x = rhs, so the result = invI * rhs
1362 // in the case of 0 m_links (i.e. a plain rigid body, not a multibody) rhs * invI is easier
1363 if ((m_baseInertia[0] >= SIMD_EPSILON) && (m_baseInertia[1] >= SIMD_EPSILON) && (m_baseInertia[2] >= SIMD_EPSILON))
1365 result.setAngular(rhs.getAngular() / m_baseInertia);
1369 result.setAngular(btVector3(0, 0, 0));
1371 if (m_baseMass >= SIMD_EPSILON)
1373 result.setLinear(rhs.getLinear() / m_baseMass);
1377 result.setLinear(btVector3(0, 0, 0));
1382 /// Special routine for calculating the inverse of a spatial inertia matrix
1383 ///the 6x6 matrix is stored as 4 blocks of 3x3 matrices
1384 if (!m_cachedInertiaValid)
1386 result.setLinear(btVector3(0, 0, 0));
1387 result.setAngular(btVector3(0, 0, 0));
1388 result.setVector(btVector3(0, 0, 0), btVector3(0, 0, 0));
1391 btMatrix3x3 Binv = m_cachedInertiaTopRight.inverse() * -1.f;
1392 btMatrix3x3 tmp = m_cachedInertiaLowerRight * Binv;
1393 btMatrix3x3 invIupper_right = (tmp * m_cachedInertiaTopLeft + m_cachedInertiaLowerLeft).inverse();
1394 tmp = invIupper_right * m_cachedInertiaLowerRight;
1395 btMatrix3x3 invI_upper_left = (tmp * Binv);
1396 btMatrix3x3 invI_lower_right = (invI_upper_left).transpose();
1397 tmp = m_cachedInertiaTopLeft * invI_upper_left;
1401 btMatrix3x3 invI_lower_left = (Binv * tmp);
1403 //multiply result = invI * rhs
1405 btVector3 vtop = invI_upper_left * rhs.getLinear();
1407 tmp = invIupper_right * rhs.getAngular();
1409 btVector3 vbot = invI_lower_left * rhs.getLinear();
1410 tmp = invI_lower_right * rhs.getAngular();
1412 result.setVector(vtop, vbot);
1417 void btMultiBody::mulMatrix(const btScalar *pA, const btScalar *pB, int rowsA, int colsA, int rowsB, int colsB, btScalar *pC) const
1419 for (int row = 0; row < rowsA; row++)
1421 for (int col = 0; col < colsB; col++)
1423 pC[row * colsB + col] = 0.f;
1424 for (int inner = 0; inner < rowsB; inner++)
1426 pC[row * colsB + col] += pA[row * colsA + inner] * pB[col + inner * colsB];
1432 void btMultiBody::calcAccelerationDeltasMultiDof(const btScalar *force, btScalar *output,
1433 btAlignedObjectArray<btScalar> &scratch_r, btAlignedObjectArray<btVector3> &scratch_v) const
1435 // Temporary matrices/vectors -- use scratch space from caller
1436 // so that we don't have to keep reallocating every frame
1438 int num_links = getNumLinks();
1439 scratch_r.resize(m_dofCount);
1440 scratch_v.resize(4 * num_links + 4);
1442 btScalar *r_ptr = m_dofCount ? &scratch_r[0] : 0;
1443 btVector3 *v_ptr = &scratch_v[0];
1445 // zhat_i^A (scratch space)
1446 btSpatialForceVector *zeroAccSpatFrc = (btSpatialForceVector *)v_ptr;
1447 v_ptr += num_links * 2 + 2;
1449 // rot_from_parent (cached from calcAccelerations)
1450 const btMatrix3x3 *rot_from_parent = &m_matrixBuf[0];
1452 // hhat (cached), accel (scratch)
1453 // hhat is NOT stored for the base (but ahat is)
1454 const btSpatialForceVector *h = (btSpatialForceVector *)(m_dofCount > 0 ? &m_vectorBuf[0] : 0);
1455 btSpatialMotionVector *spatAcc = (btSpatialMotionVector *)v_ptr;
1456 v_ptr += num_links * 2 + 2;
1458 // Y_i (scratch), invD_i (cached)
1459 const btScalar *invD = m_dofCount > 0 ? &m_realBuf[6 + m_dofCount] : 0;
1460 btScalar *Y = r_ptr;
1463 btScalar invD_times_Y[6]; //D^{-1} * Y [dofxdof x dofx1 = dofx1] <=> D^{-1} * u; better moved to buffers since it is recalced in calcAccelerationDeltasMultiDof; num_dof of btScalar would cover all bodies
1464 btSpatialMotionVector result; //holds results of the SolveImatrix op; it is a spatial motion vector (accel)
1465 btScalar Y_minus_hT_a[6]; //Y - h^{T} * a; it's dofx1 for each body so a single 6x1 temp is enough
1466 btSpatialForceVector spatForceVecTemps[6]; //6 temporary spatial force vectors
1467 btSpatialTransformationMatrix fromParent;
1470 // First 'upward' loop.
1471 // Combines CompTreeLinkVelocities and InitTreeLinks from Mirtich.
1474 // -- set to force/torque on the base, zero otherwise
1475 if (isBaseStaticOrKinematic())
1477 zeroAccSpatFrc[0].setZero();
1482 fromParent.m_rotMat = rot_from_parent[0];
1483 fromParent.transformRotationOnly(btSpatialForceVector(-force[0], -force[1], -force[2], -force[3], -force[4], -force[5]), zeroAccSpatFrc[0]);
1485 for (int i = 0; i < num_links; ++i)
1487 zeroAccSpatFrc[i + 1].setZero();
1491 // (part of TreeForwardDynamics in Mirtich.)
1492 for (int i = num_links - 1; i >= 0; --i)
1494 if(isLinkAndAllAncestorsKinematic(i))
1496 const int parent = m_links[i].m_parent;
1497 fromParent.m_rotMat = rot_from_parent[i + 1];
1498 fromParent.m_trnVec = m_links[i].m_cachedRVector;
1500 for (int dof = 0; dof < m_links[i].m_dofCount; ++dof)
1502 Y[m_links[i].m_dofOffset + dof] = force[6 + m_links[i].m_dofOffset + dof] - m_links[i].m_axes[dof].dot(zeroAccSpatFrc[i + 1]);
1505 btVector3 in_top, in_bottom, out_top, out_bottom;
1506 const btScalar *invDi = &invD[m_links[i].m_dofOffset * m_links[i].m_dofOffset];
1508 for (int dof = 0; dof < m_links[i].m_dofCount; ++dof)
1510 invD_times_Y[dof] = 0.f;
1512 for (int dof2 = 0; dof2 < m_links[i].m_dofCount; ++dof2)
1514 invD_times_Y[dof] += invDi[dof * m_links[i].m_dofCount + dof2] * Y[m_links[i].m_dofOffset + dof2];
1518 // Zp += pXi * (Zi + hi*Yi/Di)
1519 spatForceVecTemps[0] = zeroAccSpatFrc[i + 1];
1521 for (int dof = 0; dof < m_links[i].m_dofCount; ++dof)
1523 const btSpatialForceVector &hDof = h[m_links[i].m_dofOffset + dof];
1525 spatForceVecTemps[0] += hDof * invD_times_Y[dof];
1528 fromParent.transformInverse(spatForceVecTemps[0], spatForceVecTemps[1]);
1530 zeroAccSpatFrc[parent + 1] += spatForceVecTemps[1];
1533 // ptr to the joint accel part of the output
1534 btScalar *joint_accel = output + 6;
1536 // Second 'upward' loop
1537 // (part of TreeForwardDynamics in Mirtich)
1539 if (isBaseStaticOrKinematic())
1541 spatAcc[0].setZero();
1545 solveImatrix(zeroAccSpatFrc[0], result);
1546 spatAcc[0] = -result;
1549 // now do the loop over the m_links
1550 for (int i = 0; i < num_links; ++i)
1552 if(isLinkAndAllAncestorsKinematic(i))
1554 const int parent = m_links[i].m_parent;
1555 fromParent.m_rotMat = rot_from_parent[i + 1];
1556 fromParent.m_trnVec = m_links[i].m_cachedRVector;
1558 fromParent.transform(spatAcc[parent + 1], spatAcc[i + 1]);
1560 for (int dof = 0; dof < m_links[i].m_dofCount; ++dof)
1562 const btSpatialForceVector &hDof = h[m_links[i].m_dofOffset + dof];
1564 Y_minus_hT_a[dof] = Y[m_links[i].m_dofOffset + dof] - spatAcc[i + 1].dot(hDof);
1567 const btScalar *invDi = &invD[m_links[i].m_dofOffset * m_links[i].m_dofOffset];
1568 mulMatrix(const_cast<btScalar *>(invDi), Y_minus_hT_a, m_links[i].m_dofCount, m_links[i].m_dofCount, m_links[i].m_dofCount, 1, &joint_accel[m_links[i].m_dofOffset]);
1570 for (int dof = 0; dof < m_links[i].m_dofCount; ++dof)
1571 spatAcc[i + 1] += m_links[i].m_axes[dof] * joint_accel[m_links[i].m_dofOffset + dof];
1574 // transform base accelerations back to the world frame.
1575 btVector3 omegadot_out;
1576 omegadot_out = rot_from_parent[0].transpose() * spatAcc[0].getAngular();
1577 output[0] = omegadot_out[0];
1578 output[1] = omegadot_out[1];
1579 output[2] = omegadot_out[2];
1582 vdot_out = rot_from_parent[0].transpose() * spatAcc[0].getLinear();
1583 output[3] = vdot_out[0];
1584 output[4] = vdot_out[1];
1585 output[5] = vdot_out[2];
1588 //printf("delta = [");
1589 //for(int dof = 0; dof < getNumDofs() + 6; ++dof)
1590 // printf("%.2f ", output[dof]);
1594 void btMultiBody::predictPositionsMultiDof(btScalar dt)
1596 int num_links = getNumLinks();
1597 if(!isBaseKinematic())
1599 // step position by adding dt * velocity
1600 //btVector3 v = getBaseVel();
1601 //m_basePos += dt * v;
1604 btScalar *pBaseVel = &m_realBuf[3]; //note: the !pqd case assumes m_realBuf holds with base velocity at 3,4,5 (should be wrapped for safety)
1606 // reset to current position
1607 for (int i = 0; i < 3; ++i)
1609 m_basePos_interpolate[i] = m_basePos[i];
1611 pBasePos = m_basePos_interpolate;
1613 pBasePos[0] += dt * pBaseVel[0];
1614 pBasePos[1] += dt * pBaseVel[1];
1615 pBasePos[2] += dt * pBaseVel[2];
1618 ///////////////////////////////
1619 //local functor for quaternion integration (to avoid error prone redundancy)
1622 //"exponential map" based on btTransformUtil::integrateTransform(..)
1623 void operator()(const btVector3 &omega, btQuaternion &quat, bool baseBody, btScalar dt)
1625 //baseBody => quat is alias and omega is global coor
1626 //!baseBody => quat is alibi and omega is local coor
1632 angvel = quatRotate(quat, omega); //if quat is not m_baseQuat, it is alibi => ok
1636 btScalar fAngle = angvel.length();
1637 //limit the angular motion
1638 if (fAngle * dt > ANGULAR_MOTION_THRESHOLD)
1640 fAngle = btScalar(0.5) * SIMD_HALF_PI / dt;
1643 if (fAngle < btScalar(0.001))
1645 // use Taylor's expansions of sync function
1646 axis = angvel * (btScalar(0.5) * dt - (dt * dt * dt) * (btScalar(0.020833333333)) * fAngle * fAngle);
1650 // sync(fAngle) = sin(c*fAngle)/t
1651 axis = angvel * (btSin(btScalar(0.5) * fAngle * dt) / fAngle);
1655 quat = btQuaternion(axis.x(), axis.y(), axis.z(), btCos(fAngle * dt * btScalar(0.5))) * quat;
1657 quat = quat * btQuaternion(-axis.x(), -axis.y(), -axis.z(), btCos(fAngle * dt * btScalar(0.5)));
1658 //equivalent to: quat = (btQuaternion(axis.x(),axis.y(),axis.z(),btCos( fAngle*dt*btScalar(0.5) )) * quat.inverse()).inverse();
1663 ///////////////////////////////
1665 //pQuatUpdateFun(getBaseOmega(), m_baseQuat, true, dt);
1667 if(!isBaseKinematic())
1669 btScalar *pBaseQuat;
1671 // reset to current orientation
1672 for (int i = 0; i < 4; ++i)
1674 m_baseQuat_interpolate[i] = m_baseQuat[i];
1676 pBaseQuat = m_baseQuat_interpolate;
1678 btScalar *pBaseOmega = &m_realBuf[0]; //note: the !pqd case assumes m_realBuf starts with base omega (should be wrapped for safety)
1680 btQuaternion baseQuat;
1681 baseQuat.setValue(pBaseQuat[0], pBaseQuat[1], pBaseQuat[2], pBaseQuat[3]);
1682 btVector3 baseOmega;
1683 baseOmega.setValue(pBaseOmega[0], pBaseOmega[1], pBaseOmega[2]);
1684 pQuatUpdateFun(baseOmega, baseQuat, true, dt);
1685 pBaseQuat[0] = baseQuat.x();
1686 pBaseQuat[1] = baseQuat.y();
1687 pBaseQuat[2] = baseQuat.z();
1688 pBaseQuat[3] = baseQuat.w();
1691 // Finally we can update m_jointPos for each of the m_links
1692 for (int i = 0; i < num_links; ++i)
1694 btScalar *pJointPos;
1695 pJointPos = &m_links[i].m_jointPos_interpolate[0];
1697 if (m_links[i].m_collider && m_links[i].m_collider->isStaticOrKinematic())
1699 switch (m_links[i].m_jointType)
1701 case btMultibodyLink::ePrismatic:
1702 case btMultibodyLink::eRevolute:
1704 pJointPos[0] = m_links[i].m_jointPos[0];
1707 case btMultibodyLink::eSpherical:
1709 for (int j = 0; j < 4; ++j)
1711 pJointPos[j] = m_links[i].m_jointPos[j];
1715 case btMultibodyLink::ePlanar:
1717 for (int j = 0; j < 3; ++j)
1719 pJointPos[j] = m_links[i].m_jointPos[j];
1729 btScalar *pJointVel = getJointVelMultiDof(i);
1731 switch (m_links[i].m_jointType)
1733 case btMultibodyLink::ePrismatic:
1734 case btMultibodyLink::eRevolute:
1736 //reset to current pos
1737 pJointPos[0] = m_links[i].m_jointPos[0];
1738 btScalar jointVel = pJointVel[0];
1739 pJointPos[0] += dt * jointVel;
1742 case btMultibodyLink::eSpherical:
1744 //reset to current pos
1746 for (int j = 0; j < 4; ++j)
1748 pJointPos[j] = m_links[i].m_jointPos[j];
1752 jointVel.setValue(pJointVel[0], pJointVel[1], pJointVel[2]);
1753 btQuaternion jointOri;
1754 jointOri.setValue(pJointPos[0], pJointPos[1], pJointPos[2], pJointPos[3]);
1755 pQuatUpdateFun(jointVel, jointOri, false, dt);
1756 pJointPos[0] = jointOri.x();
1757 pJointPos[1] = jointOri.y();
1758 pJointPos[2] = jointOri.z();
1759 pJointPos[3] = jointOri.w();
1762 case btMultibodyLink::ePlanar:
1764 for (int j = 0; j < 3; ++j)
1766 pJointPos[j] = m_links[i].m_jointPos[j];
1768 pJointPos[0] += dt * getJointVelMultiDof(i)[0];
1770 btVector3 q0_coors_qd1qd2 = getJointVelMultiDof(i)[1] * m_links[i].getAxisBottom(1) + getJointVelMultiDof(i)[2] * m_links[i].getAxisBottom(2);
1771 btVector3 no_q0_coors_qd1qd2 = quatRotate(btQuaternion(m_links[i].getAxisTop(0), pJointPos[0]), q0_coors_qd1qd2);
1772 pJointPos[1] += m_links[i].getAxisBottom(1).dot(no_q0_coors_qd1qd2) * dt;
1773 pJointPos[2] += m_links[i].getAxisBottom(2).dot(no_q0_coors_qd1qd2) * dt;
1782 m_links[i].updateInterpolationCacheMultiDof();
1786 void btMultiBody::stepPositionsMultiDof(btScalar dt, btScalar *pq, btScalar *pqd)
1788 int num_links = getNumLinks();
1789 if(!isBaseKinematic())
1791 // step position by adding dt * velocity
1792 //btVector3 v = getBaseVel();
1793 //m_basePos += dt * v;
1795 btScalar *pBasePos = (pq ? &pq[4] : m_basePos);
1796 btScalar *pBaseVel = (pqd ? &pqd[3] : &m_realBuf[3]); //note: the !pqd case assumes m_realBuf holds with base velocity at 3,4,5 (should be wrapped for safety)
1798 pBasePos[0] += dt * pBaseVel[0];
1799 pBasePos[1] += dt * pBaseVel[1];
1800 pBasePos[2] += dt * pBaseVel[2];
1803 ///////////////////////////////
1804 //local functor for quaternion integration (to avoid error prone redundancy)
1807 //"exponential map" based on btTransformUtil::integrateTransform(..)
1808 void operator()(const btVector3 &omega, btQuaternion &quat, bool baseBody, btScalar dt)
1810 //baseBody => quat is alias and omega is global coor
1811 //!baseBody => quat is alibi and omega is local coor
1817 angvel = quatRotate(quat, omega); //if quat is not m_baseQuat, it is alibi => ok
1821 btScalar fAngle = angvel.length();
1822 //limit the angular motion
1823 if (fAngle * dt > ANGULAR_MOTION_THRESHOLD)
1825 fAngle = btScalar(0.5) * SIMD_HALF_PI / dt;
1828 if (fAngle < btScalar(0.001))
1830 // use Taylor's expansions of sync function
1831 axis = angvel * (btScalar(0.5) * dt - (dt * dt * dt) * (btScalar(0.020833333333)) * fAngle * fAngle);
1835 // sync(fAngle) = sin(c*fAngle)/t
1836 axis = angvel * (btSin(btScalar(0.5) * fAngle * dt) / fAngle);
1840 quat = btQuaternion(axis.x(), axis.y(), axis.z(), btCos(fAngle * dt * btScalar(0.5))) * quat;
1842 quat = quat * btQuaternion(-axis.x(), -axis.y(), -axis.z(), btCos(fAngle * dt * btScalar(0.5)));
1843 //equivalent to: quat = (btQuaternion(axis.x(),axis.y(),axis.z(),btCos( fAngle*dt*btScalar(0.5) )) * quat.inverse()).inverse();
1848 ///////////////////////////////
1850 //pQuatUpdateFun(getBaseOmega(), m_baseQuat, true, dt);
1852 if(!isBaseKinematic())
1854 btScalar *pBaseQuat = pq ? pq : m_baseQuat;
1855 btScalar *pBaseOmega = pqd ? pqd : &m_realBuf[0]; //note: the !pqd case assumes m_realBuf starts with base omega (should be wrapped for safety)
1857 btQuaternion baseQuat;
1858 baseQuat.setValue(pBaseQuat[0], pBaseQuat[1], pBaseQuat[2], pBaseQuat[3]);
1859 btVector3 baseOmega;
1860 baseOmega.setValue(pBaseOmega[0], pBaseOmega[1], pBaseOmega[2]);
1861 pQuatUpdateFun(baseOmega, baseQuat, true, dt);
1862 pBaseQuat[0] = baseQuat.x();
1863 pBaseQuat[1] = baseQuat.y();
1864 pBaseQuat[2] = baseQuat.z();
1865 pBaseQuat[3] = baseQuat.w();
1867 //printf("pBaseOmega = %.4f %.4f %.4f\n", pBaseOmega->x(), pBaseOmega->y(), pBaseOmega->z());
1868 //printf("pBaseVel = %.4f %.4f %.4f\n", pBaseVel->x(), pBaseVel->y(), pBaseVel->z());
1869 //printf("baseQuat = %.4f %.4f %.4f %.4f\n", pBaseQuat->x(), pBaseQuat->y(), pBaseQuat->z(), pBaseQuat->w());
1877 // Finally we can update m_jointPos for each of the m_links
1878 for (int i = 0; i < num_links; ++i)
1880 if (!(m_links[i].m_collider && m_links[i].m_collider->isStaticOrKinematic()))
1882 btScalar *pJointPos;
1883 pJointPos= (pq ? pq : &m_links[i].m_jointPos[0]);
1885 btScalar *pJointVel = (pqd ? pqd : getJointVelMultiDof(i));
1887 switch (m_links[i].m_jointType)
1889 case btMultibodyLink::ePrismatic:
1890 case btMultibodyLink::eRevolute:
1892 //reset to current pos
1893 btScalar jointVel = pJointVel[0];
1894 pJointPos[0] += dt * jointVel;
1897 case btMultibodyLink::eSpherical:
1899 //reset to current pos
1901 jointVel.setValue(pJointVel[0], pJointVel[1], pJointVel[2]);
1902 btQuaternion jointOri;
1903 jointOri.setValue(pJointPos[0], pJointPos[1], pJointPos[2], pJointPos[3]);
1904 pQuatUpdateFun(jointVel, jointOri, false, dt);
1905 pJointPos[0] = jointOri.x();
1906 pJointPos[1] = jointOri.y();
1907 pJointPos[2] = jointOri.z();
1908 pJointPos[3] = jointOri.w();
1911 case btMultibodyLink::ePlanar:
1913 pJointPos[0] += dt * getJointVelMultiDof(i)[0];
1915 btVector3 q0_coors_qd1qd2 = getJointVelMultiDof(i)[1] * m_links[i].getAxisBottom(1) + getJointVelMultiDof(i)[2] * m_links[i].getAxisBottom(2);
1916 btVector3 no_q0_coors_qd1qd2 = quatRotate(btQuaternion(m_links[i].getAxisTop(0), pJointPos[0]), q0_coors_qd1qd2);
1917 pJointPos[1] += m_links[i].getAxisBottom(1).dot(no_q0_coors_qd1qd2) * dt;
1918 pJointPos[2] += m_links[i].getAxisBottom(2).dot(no_q0_coors_qd1qd2) * dt;
1928 m_links[i].updateCacheMultiDof(pq);
1931 pq += m_links[i].m_posVarCount;
1933 pqd += m_links[i].m_dofCount;
1937 void btMultiBody::fillConstraintJacobianMultiDof(int link,
1938 const btVector3 &contact_point,
1939 const btVector3 &normal_ang,
1940 const btVector3 &normal_lin,
1942 btAlignedObjectArray<btScalar> &scratch_r1,
1943 btAlignedObjectArray<btVector3> &scratch_v,
1944 btAlignedObjectArray<btMatrix3x3> &scratch_m) const
1947 int num_links = getNumLinks();
1948 int m_dofCount = getNumDofs();
1949 scratch_v.resize(3 * num_links + 3); //(num_links + base) offsets + (num_links + base) normals_lin + (num_links + base) normals_ang
1950 scratch_m.resize(num_links + 1);
1952 btVector3 *v_ptr = &scratch_v[0];
1953 btVector3 *p_minus_com_local = v_ptr;
1954 v_ptr += num_links + 1;
1955 btVector3 *n_local_lin = v_ptr;
1956 v_ptr += num_links + 1;
1957 btVector3 *n_local_ang = v_ptr;
1958 v_ptr += num_links + 1;
1959 btAssert(v_ptr - &scratch_v[0] == scratch_v.size());
1961 //scratch_r.resize(m_dofCount);
1962 //btScalar *results = m_dofCount > 0 ? &scratch_r[0] : 0;
1964 scratch_r1.resize(m_dofCount+num_links);
1965 btScalar * results = m_dofCount > 0 ? &scratch_r1[0] : 0;
1966 btScalar* links = num_links? &scratch_r1[m_dofCount] : 0;
1967 int numLinksChildToRoot=0;
1971 links[numLinksChildToRoot++]=l;
1972 l = m_links[l].m_parent;
1975 btMatrix3x3 *rot_from_world = &scratch_m[0];
1977 const btVector3 p_minus_com_world = contact_point - m_basePos;
1978 const btVector3 &normal_lin_world = normal_lin; //convenience
1979 const btVector3 &normal_ang_world = normal_ang;
1981 rot_from_world[0] = btMatrix3x3(m_baseQuat);
1983 // omega coeffients first.
1984 btVector3 omega_coeffs_world;
1985 omega_coeffs_world = p_minus_com_world.cross(normal_lin_world);
1986 jac[0] = omega_coeffs_world[0] + normal_ang_world[0];
1987 jac[1] = omega_coeffs_world[1] + normal_ang_world[1];
1988 jac[2] = omega_coeffs_world[2] + normal_ang_world[2];
1989 // then v coefficients
1990 jac[3] = normal_lin_world[0];
1991 jac[4] = normal_lin_world[1];
1992 jac[5] = normal_lin_world[2];
1994 //create link-local versions of p_minus_com and normal
1995 p_minus_com_local[0] = rot_from_world[0] * p_minus_com_world;
1996 n_local_lin[0] = rot_from_world[0] * normal_lin_world;
1997 n_local_ang[0] = rot_from_world[0] * normal_ang_world;
1999 // Set remaining jac values to zero for now.
2000 for (int i = 6; i < 6 + m_dofCount; ++i)
2005 // Qdot coefficients, if necessary.
2006 if (num_links > 0 && link > -1)
2008 // TODO: (Also, we are making 3 separate calls to this function, for the normal & the 2 friction directions,
2009 // which is resulting in repeated work being done...)
2011 // calculate required normals & positions in the local frames.
2012 for (int a = 0; a < numLinksChildToRoot; a++)
2014 int i = links[numLinksChildToRoot-1-a];
2015 // transform to local frame
2016 const int parent = m_links[i].m_parent;
2017 const btMatrix3x3 mtx(m_links[i].m_cachedRotParentToThis);
2018 rot_from_world[i + 1] = mtx * rot_from_world[parent + 1];
2020 n_local_lin[i + 1] = mtx * n_local_lin[parent + 1];
2021 n_local_ang[i + 1] = mtx * n_local_ang[parent + 1];
2022 p_minus_com_local[i + 1] = mtx * p_minus_com_local[parent + 1] - m_links[i].m_cachedRVector;
2024 // calculate the jacobian entry
2025 switch (m_links[i].m_jointType)
2027 case btMultibodyLink::eRevolute:
2029 results[m_links[i].m_dofOffset] = n_local_lin[i + 1].dot(m_links[i].getAxisTop(0).cross(p_minus_com_local[i + 1]) + m_links[i].getAxisBottom(0));
2030 results[m_links[i].m_dofOffset] += n_local_ang[i + 1].dot(m_links[i].getAxisTop(0));
2033 case btMultibodyLink::ePrismatic:
2035 results[m_links[i].m_dofOffset] = n_local_lin[i + 1].dot(m_links[i].getAxisBottom(0));
2038 case btMultibodyLink::eSpherical:
2040 results[m_links[i].m_dofOffset + 0] = n_local_lin[i + 1].dot(m_links[i].getAxisTop(0).cross(p_minus_com_local[i + 1]) + m_links[i].getAxisBottom(0));
2041 results[m_links[i].m_dofOffset + 1] = n_local_lin[i + 1].dot(m_links[i].getAxisTop(1).cross(p_minus_com_local[i + 1]) + m_links[i].getAxisBottom(1));
2042 results[m_links[i].m_dofOffset + 2] = n_local_lin[i + 1].dot(m_links[i].getAxisTop(2).cross(p_minus_com_local[i + 1]) + m_links[i].getAxisBottom(2));
2044 results[m_links[i].m_dofOffset + 0] += n_local_ang[i + 1].dot(m_links[i].getAxisTop(0));
2045 results[m_links[i].m_dofOffset + 1] += n_local_ang[i + 1].dot(m_links[i].getAxisTop(1));
2046 results[m_links[i].m_dofOffset + 2] += n_local_ang[i + 1].dot(m_links[i].getAxisTop(2));
2050 case btMultibodyLink::ePlanar:
2052 results[m_links[i].m_dofOffset + 0] = n_local_lin[i + 1].dot(m_links[i].getAxisTop(0).cross(p_minus_com_local[i + 1])); // + m_links[i].getAxisBottom(0));
2053 results[m_links[i].m_dofOffset + 1] = n_local_lin[i + 1].dot(m_links[i].getAxisBottom(1));
2054 results[m_links[i].m_dofOffset + 2] = n_local_lin[i + 1].dot(m_links[i].getAxisBottom(2));
2064 // Now copy through to output.
2065 //printf("jac[%d] = ", link);
2068 for (int dof = 0; dof < m_links[link].m_dofCount; ++dof)
2070 jac[6 + m_links[link].m_dofOffset + dof] = results[m_links[link].m_dofOffset + dof];
2071 //printf("%.2f\t", jac[6 + m_links[link].m_dofOffset + dof]);
2074 link = m_links[link].m_parent;
2080 void btMultiBody::wakeUp()
2086 void btMultiBody::goToSleep()
2091 void btMultiBody::checkMotionAndSleepIfRequired(btScalar timestep)
2093 extern bool gDisableDeactivation;
2094 if (!m_canSleep || gDisableDeactivation)
2103 // motion is computed as omega^2 + v^2 + (sum of squares of joint velocities)
2104 btScalar motion = 0;
2106 for (int i = 0; i < 6 + m_dofCount; ++i)
2107 motion += m_realBuf[i] * m_realBuf[i];
2110 if (motion < m_sleepEpsilon)
2112 m_sleepTimer += timestep;
2113 if (m_sleepTimer > m_sleepTimeout)
2129 void btMultiBody::forwardKinematics(btAlignedObjectArray<btQuaternion> &world_to_local, btAlignedObjectArray<btVector3> &local_origin)
2131 int num_links = getNumLinks();
2133 // Cached 3x3 rotation matrices from parent frame to this frame.
2134 btMatrix3x3 *rot_from_parent = (btMatrix3x3 *)&m_matrixBuf[0];
2136 rot_from_parent[0] = btMatrix3x3(m_baseQuat); //m_baseQuat assumed to be alias!?
2138 for (int i = 0; i < num_links; ++i)
2140 rot_from_parent[i + 1] = btMatrix3x3(m_links[i].m_cachedRotParentToThis);
2143 int nLinks = getNumLinks();
2144 ///base + num m_links
2145 world_to_local.resize(nLinks + 1);
2146 local_origin.resize(nLinks + 1);
2148 world_to_local[0] = getWorldToBaseRot();
2149 local_origin[0] = getBasePos();
2151 for (int k = 0; k < getNumLinks(); k++)
2153 const int parent = getParent(k);
2154 world_to_local[k + 1] = getParentToLocalRot(k) * world_to_local[parent + 1];
2155 local_origin[k + 1] = local_origin[parent + 1] + (quatRotate(world_to_local[k + 1].inverse(), getRVector(k)));
2158 for (int link = 0; link < getNumLinks(); link++)
2160 int index = link + 1;
2162 btVector3 posr = local_origin[index];
2163 btScalar quat[4] = {-world_to_local[index].x(), -world_to_local[index].y(), -world_to_local[index].z(), world_to_local[index].w()};
2167 tr.setRotation(btQuaternion(quat[0], quat[1], quat[2], quat[3]));
2168 getLink(link).m_cachedWorldTransform = tr;
2172 void btMultiBody::updateCollisionObjectWorldTransforms(btAlignedObjectArray<btQuaternion> &world_to_local, btAlignedObjectArray<btVector3> &local_origin)
2174 world_to_local.resize(getNumLinks() + 1);
2175 local_origin.resize(getNumLinks() + 1);
2177 world_to_local[0] = getWorldToBaseRot();
2178 local_origin[0] = getBasePos();
2180 if (getBaseCollider())
2182 btVector3 posr = local_origin[0];
2183 // float pos[4]={posr.x(),posr.y(),posr.z(),1};
2184 btScalar quat[4] = {-world_to_local[0].x(), -world_to_local[0].y(), -world_to_local[0].z(), world_to_local[0].w()};
2188 tr.setRotation(btQuaternion(quat[0], quat[1], quat[2], quat[3]));
2190 getBaseCollider()->setWorldTransform(tr);
2191 getBaseCollider()->setInterpolationWorldTransform(tr);
2194 for (int k = 0; k < getNumLinks(); k++)
2196 const int parent = getParent(k);
2197 world_to_local[k + 1] = getParentToLocalRot(k) * world_to_local[parent + 1];
2198 local_origin[k + 1] = local_origin[parent + 1] + (quatRotate(world_to_local[k + 1].inverse(), getRVector(k)));
2201 for (int m = 0; m < getNumLinks(); m++)
2203 btMultiBodyLinkCollider *col = getLink(m).m_collider;
2206 int link = col->m_link;
2207 btAssert(link == m);
2209 int index = link + 1;
2211 btVector3 posr = local_origin[index];
2212 // float pos[4]={posr.x(),posr.y(),posr.z(),1};
2213 btScalar quat[4] = {-world_to_local[index].x(), -world_to_local[index].y(), -world_to_local[index].z(), world_to_local[index].w()};
2217 tr.setRotation(btQuaternion(quat[0], quat[1], quat[2], quat[3]));
2219 col->setWorldTransform(tr);
2220 col->setInterpolationWorldTransform(tr);
2225 void btMultiBody::updateCollisionObjectInterpolationWorldTransforms(btAlignedObjectArray<btQuaternion> &world_to_local, btAlignedObjectArray<btVector3> &local_origin)
2227 world_to_local.resize(getNumLinks() + 1);
2228 local_origin.resize(getNumLinks() + 1);
2230 if(isBaseKinematic()){
2231 world_to_local[0] = getWorldToBaseRot();
2232 local_origin[0] = getBasePos();
2236 world_to_local[0] = getInterpolateWorldToBaseRot();
2237 local_origin[0] = getInterpolateBasePos();
2240 if (getBaseCollider())
2242 btVector3 posr = local_origin[0];
2243 // float pos[4]={posr.x(),posr.y(),posr.z(),1};
2244 btScalar quat[4] = {-world_to_local[0].x(), -world_to_local[0].y(), -world_to_local[0].z(), world_to_local[0].w()};
2248 tr.setRotation(btQuaternion(quat[0], quat[1], quat[2], quat[3]));
2250 getBaseCollider()->setInterpolationWorldTransform(tr);
2253 for (int k = 0; k < getNumLinks(); k++)
2255 const int parent = getParent(k);
2256 world_to_local[k + 1] = getInterpolateParentToLocalRot(k) * world_to_local[parent + 1];
2257 local_origin[k + 1] = local_origin[parent + 1] + (quatRotate(world_to_local[k + 1].inverse(), getInterpolateRVector(k)));
2260 for (int m = 0; m < getNumLinks(); m++)
2262 btMultiBodyLinkCollider *col = getLink(m).m_collider;
2265 int link = col->m_link;
2266 btAssert(link == m);
2268 int index = link + 1;
2270 btVector3 posr = local_origin[index];
2271 // float pos[4]={posr.x(),posr.y(),posr.z(),1};
2272 btScalar quat[4] = {-world_to_local[index].x(), -world_to_local[index].y(), -world_to_local[index].z(), world_to_local[index].w()};
2276 tr.setRotation(btQuaternion(quat[0], quat[1], quat[2], quat[3]));
2278 col->setInterpolationWorldTransform(tr);
2283 int btMultiBody::calculateSerializeBufferSize() const
2285 int sz = sizeof(btMultiBodyData);
2289 ///fills the dataBuffer and returns the struct name (and 0 on failure)
2290 const char *btMultiBody::serialize(void *dataBuffer, class btSerializer *serializer) const
2292 btMultiBodyData *mbd = (btMultiBodyData *)dataBuffer;
2293 getBasePos().serialize(mbd->m_baseWorldPosition);
2294 getWorldToBaseRot().inverse().serialize(mbd->m_baseWorldOrientation);
2295 getBaseVel().serialize(mbd->m_baseLinearVelocity);
2296 getBaseOmega().serialize(mbd->m_baseAngularVelocity);
2298 mbd->m_baseMass = this->getBaseMass();
2299 getBaseInertia().serialize(mbd->m_baseInertia);
2301 char *name = (char *)serializer->findNameForPointer(m_baseName);
2302 mbd->m_baseName = (char *)serializer->getUniquePointer(name);
2303 if (mbd->m_baseName)
2305 serializer->serializeName(name);
2308 mbd->m_numLinks = this->getNumLinks();
2309 if (mbd->m_numLinks)
2311 int sz = sizeof(btMultiBodyLinkData);
2312 int numElem = mbd->m_numLinks;
2313 btChunk *chunk = serializer->allocate(sz, numElem);
2314 btMultiBodyLinkData *memPtr = (btMultiBodyLinkData *)chunk->m_oldPtr;
2315 for (int i = 0; i < numElem; i++, memPtr++)
2317 memPtr->m_jointType = getLink(i).m_jointType;
2318 memPtr->m_dofCount = getLink(i).m_dofCount;
2319 memPtr->m_posVarCount = getLink(i).m_posVarCount;
2321 getLink(i).m_inertiaLocal.serialize(memPtr->m_linkInertia);
2323 getLink(i).m_absFrameTotVelocity.m_topVec.serialize(memPtr->m_absFrameTotVelocityTop);
2324 getLink(i).m_absFrameTotVelocity.m_bottomVec.serialize(memPtr->m_absFrameTotVelocityBottom);
2325 getLink(i).m_absFrameLocVelocity.m_topVec.serialize(memPtr->m_absFrameLocVelocityTop);
2326 getLink(i).m_absFrameLocVelocity.m_bottomVec.serialize(memPtr->m_absFrameLocVelocityBottom);
2328 memPtr->m_linkMass = getLink(i).m_mass;
2329 memPtr->m_parentIndex = getLink(i).m_parent;
2330 memPtr->m_jointDamping = getLink(i).m_jointDamping;
2331 memPtr->m_jointFriction = getLink(i).m_jointFriction;
2332 memPtr->m_jointLowerLimit = getLink(i).m_jointLowerLimit;
2333 memPtr->m_jointUpperLimit = getLink(i).m_jointUpperLimit;
2334 memPtr->m_jointMaxForce = getLink(i).m_jointMaxForce;
2335 memPtr->m_jointMaxVelocity = getLink(i).m_jointMaxVelocity;
2337 getLink(i).m_eVector.serialize(memPtr->m_parentComToThisPivotOffset);
2338 getLink(i).m_dVector.serialize(memPtr->m_thisPivotToThisComOffset);
2339 getLink(i).m_zeroRotParentToThis.serialize(memPtr->m_zeroRotParentToThis);
2340 btAssert(memPtr->m_dofCount <= 3);
2341 for (int dof = 0; dof < getLink(i).m_dofCount; dof++)
2343 getLink(i).getAxisBottom(dof).serialize(memPtr->m_jointAxisBottom[dof]);
2344 getLink(i).getAxisTop(dof).serialize(memPtr->m_jointAxisTop[dof]);
2346 memPtr->m_jointTorque[dof] = getLink(i).m_jointTorque[dof];
2347 memPtr->m_jointVel[dof] = getJointVelMultiDof(i)[dof];
2349 int numPosVar = getLink(i).m_posVarCount;
2350 for (int posvar = 0; posvar < numPosVar; posvar++)
2352 memPtr->m_jointPos[posvar] = getLink(i).m_jointPos[posvar];
2356 char *name = (char *)serializer->findNameForPointer(m_links[i].m_linkName);
2357 memPtr->m_linkName = (char *)serializer->getUniquePointer(name);
2358 if (memPtr->m_linkName)
2360 serializer->serializeName(name);
2364 char *name = (char *)serializer->findNameForPointer(m_links[i].m_jointName);
2365 memPtr->m_jointName = (char *)serializer->getUniquePointer(name);
2366 if (memPtr->m_jointName)
2368 serializer->serializeName(name);
2371 memPtr->m_linkCollider = (btCollisionObjectData *)serializer->getUniquePointer(getLink(i).m_collider);
2373 serializer->finalizeChunk(chunk, btMultiBodyLinkDataName, BT_ARRAY_CODE, (void *)&m_links[0]);
2375 mbd->m_links = mbd->m_numLinks ? (btMultiBodyLinkData *)serializer->getUniquePointer((void *)&m_links[0]) : 0;
2377 // Fill padding with zeros to appease msan.
2378 #ifdef BT_USE_DOUBLE_PRECISION
2379 memset(mbd->m_padding, 0, sizeof(mbd->m_padding));
2382 return btMultiBodyDataName;
2385 void btMultiBody::saveKinematicState(btScalar timeStep)
2387 //todo: clamp to some (user definable) safe minimum timestep, to limit maximum angular/linear velocities
2388 if (m_kinematic_calculate_velocity && timeStep != btScalar(0.))
2390 btVector3 linearVelocity, angularVelocity;
2391 btTransformUtil::calculateVelocity(getInterpolateBaseWorldTransform(), getBaseWorldTransform(), timeStep, linearVelocity, angularVelocity);
2392 setBaseVel(linearVelocity);
2393 setBaseOmega(angularVelocity);
2394 setInterpolateBaseWorldTransform(getBaseWorldTransform());
2398 void btMultiBody::setLinkDynamicType(const int i, int type)
2402 setBaseDynamicType(type);
2404 else if (i >= 0 && i < getNumLinks())
2406 if (m_links[i].m_collider)
2408 m_links[i].m_collider->setDynamicType(type);
2413 bool btMultiBody::isLinkStaticOrKinematic(const int i) const
2417 return isBaseStaticOrKinematic();
2421 if (m_links[i].m_collider)
2422 return m_links[i].m_collider->isStaticOrKinematic();
2427 bool btMultiBody::isLinkKinematic(const int i) const
2431 return isBaseKinematic();
2435 if (m_links[i].m_collider)
2436 return m_links[i].m_collider->isKinematic();
2441 bool btMultiBody::isLinkAndAllAncestorsStaticOrKinematic(const int i) const
2444 while (link != -1) {
2445 if (!isLinkStaticOrKinematic(link))
2447 link = m_links[link].m_parent;
2449 return isBaseStaticOrKinematic();
2452 bool btMultiBody::isLinkAndAllAncestorsKinematic(const int i) const
2455 while (link != -1) {
2456 if (!isLinkKinematic(link))
2458 link = m_links[link].m_parent;
2460 return isBaseKinematic();