Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/questsystem5/src/bullet/BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.cpp @ 2968

Last change on this file since 2968 was 2908, checked in by dafrick, 16 years ago

Reverted to revision 2906 (because I'm too stupid to merge correctly, 2nd try will follow shortly. ;))

  • Property svn:eol-style set to native
File size: 14.6 KB
RevLine 
[1963]1/*
2Bullet Continuous Collision Detection and Physics Library
3Copyright (c) 2003-2006 Erwin Coumans  http://continuousphysics.com/Bullet/
4
5This software is provided 'as-is', without any express or implied warranty.
6In no event will the authors be held liable for any damages arising from the use of this software.
7Permission is granted to anyone to use this software for any purpose,
8including commercial applications, and to alter it and redistribute it freely,
9subject to the following restrictions:
10
111. 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.
122. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
133. This notice may not be removed or altered from any source distribution.
14*/
15/*
162007-09-09
17Refactored by Francisco Le?n
18email: projectileman@yahoo.com
19http://gimpact.sf.net
20*/
21
[2908]22
[1963]23#include "btGeneric6DofConstraint.h"
24#include "BulletDynamics/Dynamics/btRigidBody.h"
25#include "LinearMath/btTransformUtil.h"
26#include <new>
27
28
29#define GENERIC_D6_DISABLE_WARMSTARTING 1
30
31btScalar btGetMatrixElem(const btMatrix3x3& mat, int index);
32btScalar btGetMatrixElem(const btMatrix3x3& mat, int index)
33{
34        int i = index%3;
35        int j = index/3;
36        return mat[i][j];
37}
38
39///MatrixToEulerXYZ from http://www.geometrictools.com/LibFoundation/Mathematics/Wm4Matrix3.inl.html
40bool    matrixToEulerXYZ(const btMatrix3x3& mat,btVector3& xyz);
41bool    matrixToEulerXYZ(const btMatrix3x3& mat,btVector3& xyz)
42{
[2908]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//
[1963]47
[2908]48                if (btGetMatrixElem(mat,2) < btScalar(1.0))
[1963]49                {
[2908]50                        if (btGetMatrixElem(mat,2) > btScalar(-1.0))
51                        {
52                                xyz[0] = btAtan2(-btGetMatrixElem(mat,5),btGetMatrixElem(mat,8));
53                                xyz[1] = btAsin(btGetMatrixElem(mat,2));
54                                xyz[2] = btAtan2(-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] = -btAtan2(btGetMatrixElem(mat,3),btGetMatrixElem(mat,4));
61                                xyz[1] = -SIMD_HALF_PI;
62                                xyz[2] = btScalar(0.0);
63                                return false;
64                        }
[1963]65                }
66                else
67                {
[2908]68                        // WARNING.  Not unique.  XAngle + ZAngle = atan2(r10,r11)
69                        xyz[0] = btAtan2(btGetMatrixElem(mat,3),btGetMatrixElem(mat,4));
70                        xyz[1] = SIMD_HALF_PI;
71                        xyz[2] = 0.0;
72
[1963]73                }
[2908]74
75
[1963]76        return false;
77}
78
[2908]79
80
[1963]81//////////////////////////// btRotationalLimitMotor ////////////////////////////////////
82
[2908]83
[1963]84int btRotationalLimitMotor::testLimitValue(btScalar test_value)
85{
86        if(m_loLimit>m_hiLimit)
87        {
88                m_currentLimit = 0;//Free from violation
89                return 0;
90        }
91
92        if (test_value < m_loLimit)
93        {
94                m_currentLimit = 1;//low limit violation
95                m_currentLimitError =  test_value - m_loLimit;
96                return 1;
97        }
98        else if (test_value> m_hiLimit)
99        {
100                m_currentLimit = 2;//High limit violation
101                m_currentLimitError = test_value - m_hiLimit;
102                return 2;
103        };
104
105        m_currentLimit = 0;//Free from violation
106        return 0;
[2908]107       
[1963]108}
109
110
111btScalar btRotationalLimitMotor::solveAngularLimits(
[2908]112                btScalar timeStep,btVector3& axis,btScalar jacDiagABInv,
113                btRigidBody * body0, btRigidBody * body1)
[1963]114{
[2908]115    if (needApplyTorques()==false) return 0.0f;
[1963]116
[2908]117    btScalar target_velocity = m_targetVelocity;
118    btScalar maxMotorForce = m_maxMotorForce;
[1963]119
120        //current error correction
[2908]121    if (m_currentLimit!=0)
122    {
123        target_velocity = -m_ERP*m_currentLimitError/(timeStep);
124        maxMotorForce = m_maxLimitForce;
125    }
[1963]126
[2908]127    maxMotorForce *= timeStep;
[1963]128
[2908]129    // current velocity difference
130    btVector3 vel_diff = body0->getAngularVelocity();
131    if (body1)
132    {
133        vel_diff -= body1->getAngularVelocity();
134    }
[1963]135
136
137
[2908]138    btScalar rel_vel = axis.dot(vel_diff);
[1963]139
140        // correction velocity
[2908]141    btScalar motor_relvel = m_limitSoftness*(target_velocity  - m_damping*rel_vel);
[1963]142
143
[2908]144    if ( motor_relvel < SIMD_EPSILON && motor_relvel > -SIMD_EPSILON  )
145    {
146        return 0.0f;//no need for applying force
147    }
[1963]148
149
150        // correction impulse
[2908]151    btScalar unclippedMotorImpulse = (1+m_bounce)*motor_relvel*jacDiagABInv;
[1963]152
153        // clip correction impulse
[2908]154    btScalar clippedMotorImpulse;
[1963]155
[2908]156    ///@todo: should clip against accumulated impulse
157    if (unclippedMotorImpulse>0.0f)
158    {
159        clippedMotorImpulse =  unclippedMotorImpulse > maxMotorForce? maxMotorForce: unclippedMotorImpulse;
160    }
161    else
162    {
163        clippedMotorImpulse =  unclippedMotorImpulse < -maxMotorForce ? -maxMotorForce: unclippedMotorImpulse;
164    }
[1963]165
166
167        // sort with accumulated impulses
[2908]168    btScalar    lo = btScalar(-1e30);
169    btScalar    hi = btScalar(1e30);
[1963]170
[2908]171    btScalar oldaccumImpulse = m_accumulatedImpulse;
172    btScalar sum = oldaccumImpulse + clippedMotorImpulse;
173    m_accumulatedImpulse = sum > hi ? btScalar(0.) : sum < lo ? btScalar(0.) : sum;
[1963]174
[2908]175    clippedMotorImpulse = m_accumulatedImpulse - oldaccumImpulse;
[1963]176
177
178
[2908]179    btVector3 motorImp = clippedMotorImpulse * axis;
[1963]180
181
[2908]182    body0->applyTorqueImpulse(motorImp);
183    if (body1) body1->applyTorqueImpulse(-motorImp);
[1963]184
[2908]185    return clippedMotorImpulse;
[1963]186
[2908]187
[1963]188}
189
190//////////////////////////// End btRotationalLimitMotor ////////////////////////////////////
191
192//////////////////////////// btTranslationalLimitMotor ////////////////////////////////////
[2908]193btScalar btTranslationalLimitMotor::solveLinearAxis(
194                btScalar timeStep,
195        btScalar jacDiagABInv,
196        btRigidBody& body1,const btVector3 &pointInA,
197        btRigidBody& body2,const btVector3 &pointInB,
198        int limit_index,
199        const btVector3 & axis_normal_on_a,
200                const btVector3 & anchorPos)
[1963]201{
202
[2908]203///find relative velocity
204//    btVector3 rel_pos1 = pointInA - body1.getCenterOfMassPosition();
205//    btVector3 rel_pos2 = pointInB - body2.getCenterOfMassPosition();
206    btVector3 rel_pos1 = anchorPos - body1.getCenterOfMassPosition();
207    btVector3 rel_pos2 = anchorPos - body2.getCenterOfMassPosition();
[1963]208
[2908]209    btVector3 vel1 = body1.getVelocityInLocalPoint(rel_pos1);
210    btVector3 vel2 = body2.getVelocityInLocalPoint(rel_pos2);
211    btVector3 vel = vel1 - vel2;
[1963]212
[2908]213    btScalar rel_vel = axis_normal_on_a.dot(vel);
[1963]214
215
216
[2908]217/// apply displacement correction
[1963]218
[2908]219//positional error (zeroth order error)
220    btScalar depth = -(pointInA - pointInB).dot(axis_normal_on_a);
221    btScalar    lo = btScalar(-1e30);
222    btScalar    hi = btScalar(1e30);
[1963]223
[2908]224    btScalar minLimit = m_lowerLimit[limit_index];
225    btScalar maxLimit = m_upperLimit[limit_index];
[1963]226
[2908]227    //handle the limits
228    if (minLimit < maxLimit)
229    {
230        {
231            if (depth > maxLimit)
232            {
233                depth -= maxLimit;
234                lo = btScalar(0.);
[1963]235
[2908]236            }
237            else
238            {
239                if (depth < minLimit)
240                {
241                    depth -= minLimit;
242                    hi = btScalar(0.);
243                }
244                else
245                {
246                    return 0.0f;
247                }
248            }
249        }
250    }
[1963]251
[2908]252    btScalar normalImpulse= m_limitSoftness*(m_restitution*depth/timeStep - m_damping*rel_vel) * jacDiagABInv;
[1963]253
254
255
256
[2908]257    btScalar oldNormalImpulse = m_accumulatedImpulse[limit_index];
258    btScalar sum = oldNormalImpulse + normalImpulse;
259    m_accumulatedImpulse[limit_index] = sum > hi ? btScalar(0.) : sum < lo ? btScalar(0.) : sum;
260    normalImpulse = m_accumulatedImpulse[limit_index] - oldNormalImpulse;
[1963]261
[2908]262    btVector3 impulse_vector = axis_normal_on_a * normalImpulse;
263    body1.applyImpulse( impulse_vector, rel_pos1);
264    body2.applyImpulse(-impulse_vector, rel_pos2);
265    return normalImpulse;
266}
[1963]267
[2908]268//////////////////////////// btTranslationalLimitMotor ////////////////////////////////////
[1963]269
270
[2908]271btGeneric6DofConstraint::btGeneric6DofConstraint()
272        :btTypedConstraint(D6_CONSTRAINT_TYPE),
273                m_useLinearReferenceFrameA(true)
274{
275}
[1963]276
[2908]277btGeneric6DofConstraint::btGeneric6DofConstraint(btRigidBody& rbA, btRigidBody& rbB, const btTransform& frameInA, const btTransform& frameInB, bool useLinearReferenceFrameA)
278        : btTypedConstraint(D6_CONSTRAINT_TYPE, rbA, rbB)
279        , m_frameInA(frameInA)
280        , m_frameInB(frameInB),
281                m_useLinearReferenceFrameA(useLinearReferenceFrameA)
282{
[1963]283
[2908]284}
[1963]285
286
287
288
289
290void btGeneric6DofConstraint::calculateAngleInfo()
291{
292        btMatrix3x3 relative_frame = m_calculatedTransformA.getBasis().inverse()*m_calculatedTransformB.getBasis();
[2908]293
[1963]294        matrixToEulerXYZ(relative_frame,m_calculatedAxisAngleDiff);
[2908]295
296
297
[1963]298        // in euler angle mode we do not actually constrain the angular velocity
[2908]299  // along the axes axis[0] and axis[2] (although we do use axis[1]) :
300  //
301  //    to get                  constrain w2-w1 along           ...not
302  //    ------                  ---------------------           ------
303  //    d(angle[0])/dt = 0      ax[1] x ax[2]                   ax[0]
304  //    d(angle[1])/dt = 0      ax[1]
305  //    d(angle[2])/dt = 0      ax[0] x ax[1]                   ax[2]
306  //
307  // constraining w2-w1 along an axis 'a' means that a'*(w2-w1)=0.
308  // to prove the result for angle[0], write the expression for angle[0] from
309  // GetInfo1 then take the derivative. to prove this for angle[2] it is
310  // easier to take the euler rate expression for d(angle[2])/dt with respect
311  // to the components of w and set that to 0.
312
[1963]313        btVector3 axis0 = m_calculatedTransformB.getBasis().getColumn(0);
314        btVector3 axis2 = m_calculatedTransformA.getBasis().getColumn(2);
315
316        m_calculatedAxis[1] = axis2.cross(axis0);
317        m_calculatedAxis[0] = m_calculatedAxis[1].cross(axis2);
318        m_calculatedAxis[2] = axis0.cross(m_calculatedAxis[1]);
319
320
[2908]321//    if(m_debugDrawer)
322//    {
323//
324//      char buff[300];
325//              sprintf(buff,"\n X: %.2f ; Y: %.2f ; Z: %.2f ",
326//              m_calculatedAxisAngleDiff[0],
327//              m_calculatedAxisAngleDiff[1],
328//              m_calculatedAxisAngleDiff[2]);
329//      m_debugDrawer->reportErrorWarning(buff);
330//    }
331
[1963]332}
333
334void btGeneric6DofConstraint::calculateTransforms()
335{
[2908]336    m_calculatedTransformA = m_rbA.getCenterOfMassTransform() * m_frameInA;
337    m_calculatedTransformB = m_rbB.getCenterOfMassTransform() * m_frameInB;
338
339    calculateAngleInfo();
[1963]340}
341
342
343void btGeneric6DofConstraint::buildLinearJacobian(
[2908]344    btJacobianEntry & jacLinear,const btVector3 & normalWorld,
345    const btVector3 & pivotAInW,const btVector3 & pivotBInW)
[1963]346{
[2908]347    new (&jacLinear) btJacobianEntry(
[1963]348        m_rbA.getCenterOfMassTransform().getBasis().transpose(),
349        m_rbB.getCenterOfMassTransform().getBasis().transpose(),
350        pivotAInW - m_rbA.getCenterOfMassPosition(),
351        pivotBInW - m_rbB.getCenterOfMassPosition(),
352        normalWorld,
353        m_rbA.getInvInertiaDiagLocal(),
354        m_rbA.getInvMass(),
355        m_rbB.getInvInertiaDiagLocal(),
356        m_rbB.getInvMass());
[2908]357
[1963]358}
359
360void btGeneric6DofConstraint::buildAngularJacobian(
[2908]361    btJacobianEntry & jacAngular,const btVector3 & jointAxisW)
[1963]362{
[2908]363    new (&jacAngular)   btJacobianEntry(jointAxisW,
[1963]364                                      m_rbA.getCenterOfMassTransform().getBasis().transpose(),
365                                      m_rbB.getCenterOfMassTransform().getBasis().transpose(),
366                                      m_rbA.getInvInertiaDiagLocal(),
367                                      m_rbB.getInvInertiaDiagLocal());
368
369}
370
371bool btGeneric6DofConstraint::testAngularLimitMotor(int axis_index)
372{
[2908]373    btScalar angle = m_calculatedAxisAngleDiff[axis_index];
374
375    //test limits
376    m_angularLimits[axis_index].testLimitValue(angle);
377    return m_angularLimits[axis_index].needApplyTorques();
[1963]378}
379
380void btGeneric6DofConstraint::buildJacobian()
381{
382
[2908]383        // Clear accumulated impulses for the next simulation step
384    m_linearLimits.m_accumulatedImpulse.setValue(btScalar(0.), btScalar(0.), btScalar(0.));
385    int i;
386    for(i = 0; i < 3; i++)
387    {
388        m_angularLimits[i].m_accumulatedImpulse = btScalar(0.);
389    }
390    //calculates transform
391    calculateTransforms();
[1963]392
[2908]393//  const btVector3& pivotAInW = m_calculatedTransformA.getOrigin();
394//  const btVector3& pivotBInW = m_calculatedTransformB.getOrigin();
395        calcAnchorPos();
396        btVector3 pivotAInW = m_AnchorPos;
397        btVector3 pivotBInW = m_AnchorPos;
[1963]398
[2908]399// not used here
400//    btVector3 rel_pos1 = pivotAInW - m_rbA.getCenterOfMassPosition();
401//    btVector3 rel_pos2 = pivotBInW - m_rbB.getCenterOfMassPosition();
[1963]402
[2908]403    btVector3 normalWorld;
404    //linear part
405    for (i=0;i<3;i++)
406    {
407        if (m_linearLimits.isLimited(i))
408        {
409                        if (m_useLinearReferenceFrameA)
410                    normalWorld = m_calculatedTransformA.getBasis().getColumn(i);
411                        else
412                    normalWorld = m_calculatedTransformB.getBasis().getColumn(i);
[1963]413
[2908]414            buildLinearJacobian(
415                m_jacLinear[i],normalWorld ,
416                pivotAInW,pivotBInW);
[1963]417
[2908]418        }
419    }
[1963]420
[2908]421    // angular part
422    for (i=0;i<3;i++)
423    {
424        //calculates error angle
425        if (testAngularLimitMotor(i))
426        {
427            normalWorld = this->getAxis(i);
428            // Create angular atom
429            buildAngularJacobian(m_jacAng[i],normalWorld);
430        }
431    }
[1963]432
433
434}
435
436
[2908]437void btGeneric6DofConstraint::solveConstraint(btScalar  timeStep)
[1963]438{
[2908]439    m_timeStep = timeStep;
[1963]440
[2908]441    //calculateTransforms();
[1963]442
[2908]443    int i;
[1963]444
[2908]445    // linear
[1963]446
[2908]447    btVector3 pointInA = m_calculatedTransformA.getOrigin();
448        btVector3 pointInB = m_calculatedTransformB.getOrigin();
[1963]449
[2908]450        btScalar jacDiagABInv;
451        btVector3 linear_axis;
452    for (i=0;i<3;i++)
453    {
454        if (m_linearLimits.isLimited(i))
455        {
456            jacDiagABInv = btScalar(1.) / m_jacLinear[i].getDiagonal();
[1963]457
[2908]458                        if (m_useLinearReferenceFrameA)
459                    linear_axis = m_calculatedTransformA.getBasis().getColumn(i);
460                        else
461                    linear_axis = m_calculatedTransformB.getBasis().getColumn(i);
[1963]462
[2908]463            m_linearLimits.solveLinearAxis(
464                m_timeStep,
465                jacDiagABInv,
466                m_rbA,pointInA,
467                m_rbB,pointInB,
468                i,linear_axis, m_AnchorPos);
[1963]469
[2908]470        }
471    }
[1963]472
[2908]473    // angular
474    btVector3 angular_axis;
475    btScalar angularJacDiagABInv;
476    for (i=0;i<3;i++)
477    {
478        if (m_angularLimits[i].needApplyTorques())
479        {
[1963]480
[2908]481                        // get axis
482                        angular_axis = getAxis(i);
[1963]483
[2908]484                        angularJacDiagABInv = btScalar(1.) / m_jacAng[i].getDiagonal();
[1963]485
[2908]486                        m_angularLimits[i].solveAngularLimits(m_timeStep,angular_axis,angularJacDiagABInv, &m_rbA,&m_rbB);
487        }
488    }
[1963]489}
490
491void    btGeneric6DofConstraint::updateRHS(btScalar     timeStep)
492{
[2908]493    (void)timeStep;
[1963]494
495}
496
497btVector3 btGeneric6DofConstraint::getAxis(int axis_index) const
498{
[2908]499    return m_calculatedAxis[axis_index];
[1963]500}
501
502btScalar btGeneric6DofConstraint::getAngle(int axis_index) const
503{
[2908]504    return m_calculatedAxisAngleDiff[axis_index];
[1963]505}
506
507void btGeneric6DofConstraint::calcAnchorPos(void)
508{
509        btScalar imA = m_rbA.getInvMass();
510        btScalar imB = m_rbB.getInvMass();
511        btScalar weight;
512        if(imB == btScalar(0.0))
513        {
514                weight = btScalar(1.0);
515        }
516        else
517        {
518                weight = imA / (imA + imB);
519        }
520        const btVector3& pA = m_calculatedTransformA.getOrigin();
521        const btVector3& pB = m_calculatedTransformB.getOrigin();
522        m_AnchorPos = pA * weight + pB * (btScalar(1.0) - weight);
523        return;
524} // btGeneric6DofConstraint::calcAnchorPos()
525
Note: See TracBrowser for help on using the repository browser.