Bullet Collision Detection & Physics Library
btConeTwistConstraint.cpp
Go to the documentation of this file.
1/*
2Bullet Continuous Collision Detection and Physics Library
3btConeTwistConstraint is Copyright (c) 2007 Starbreeze Studios
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
15Written by: Marcus Hennix
16*/
17
18
22#include "LinearMath/btMinMax.h"
23#include <new>
24
25
26
27//#define CONETWIST_USE_OBSOLETE_SOLVER true
28#define CONETWIST_USE_OBSOLETE_SOLVER false
29#define CONETWIST_DEF_FIX_THRESH btScalar(.05f)
30
31
33{
35 return axis.dot(vec);
36}
37
38
39
40
44 m_angularOnly(false),
45 m_useSolveConstraintObsolete(CONETWIST_USE_OBSOLETE_SOLVER)
46{
47 init();
48}
49
52 m_angularOnly(false),
53 m_useSolveConstraintObsolete(CONETWIST_USE_OBSOLETE_SOLVER)
54{
56 m_rbBFrame.setOrigin(btVector3(0., 0., 0.));
57 init();
58}
59
60
62{
63 m_angularOnly = false;
64 m_solveTwistLimit = false;
65 m_solveSwingLimit = false;
66 m_bMotorEnabled = false;
68
70 m_damping = btScalar(0.01);
72 m_flags = 0;
73 m_linCFM = btScalar(0.f);
74 m_linERP = btScalar(0.7f);
75 m_angCFM = btScalar(0.f);
76}
77
78
80{
82 {
83 info->m_numConstraintRows = 0;
84 info->nub = 0;
85 }
86 else
87 {
88 info->m_numConstraintRows = 3;
89 info->nub = 3;
92 {
93 info->m_numConstraintRows++;
94 info->nub--;
96 {
97 info->m_numConstraintRows++;
98 info->nub--;
99 }
100 }
102 {
103 info->m_numConstraintRows++;
104 info->nub--;
105 }
106 }
107}
108
110{
111 //always reserve 6 rows: object transform is not available on SPU
112 info->m_numConstraintRows = 6;
113 info->nub = 0;
114
115}
116
117
119{
121}
122
124{
126
128 // set jacobian
129 info->m_J1linearAxis[0] = 1;
130 info->m_J1linearAxis[info->rowskip+1] = 1;
131 info->m_J1linearAxis[2*info->rowskip+2] = 1;
132 btVector3 a1 = transA.getBasis() * m_rbAFrame.getOrigin();
133 {
137 btVector3 a1neg = -a1;
139 }
140 info->m_J2linearAxis[0] = -1;
141 info->m_J2linearAxis[info->rowskip+1] = -1;
142 info->m_J2linearAxis[2*info->rowskip+2] = -1;
143 btVector3 a2 = transB.getBasis() * m_rbBFrame.getOrigin();
144 {
149 }
150 // set right hand side
152 btScalar k = info->fps * linERP;
153 int j;
154 for (j=0; j<3; j++)
155 {
156 info->m_constraintError[j*info->rowskip] = k * (a2[j] + transB.getOrigin()[j] - a1[j] - transA.getOrigin()[j]);
157 info->m_lowerLimit[j*info->rowskip] = -SIMD_INFINITY;
158 info->m_upperLimit[j*info->rowskip] = SIMD_INFINITY;
160 {
161 info->cfm[j*info->rowskip] = m_linCFM;
162 }
163 }
164 int row = 3;
165 int srow = row * info->rowskip;
167 // angular limits
169 {
170 btScalar *J1 = info->m_J1angularAxis;
171 btScalar *J2 = info->m_J2angularAxis;
173 {
175 btVector3 p = trA.getBasis().getColumn(1);
176 btVector3 q = trA.getBasis().getColumn(2);
177 int srow1 = srow + info->rowskip;
178 J1[srow+0] = p[0];
179 J1[srow+1] = p[1];
180 J1[srow+2] = p[2];
181 J1[srow1+0] = q[0];
182 J1[srow1+1] = q[1];
183 J1[srow1+2] = q[2];
184 J2[srow+0] = -p[0];
185 J2[srow+1] = -p[1];
186 J2[srow+2] = -p[2];
187 J2[srow1+0] = -q[0];
188 J2[srow1+1] = -q[1];
189 J2[srow1+2] = -q[2];
197 srow = srow1 + info->rowskip;
198 }
199 else
200 {
202 J1[srow+0] = ax1[0];
203 J1[srow+1] = ax1[1];
204 J1[srow+2] = ax1[2];
205 J2[srow+0] = -ax1[0];
206 J2[srow+1] = -ax1[1];
207 J2[srow+2] = -ax1[2];
208 btScalar k = info->fps * m_biasFactor;
209
212 {
213 info->cfm[srow] = m_angCFM;
214 }
215 // m_swingCorrection is always positive or 0
216 info->m_lowerLimit[srow] = 0;
218 srow += info->rowskip;
219 }
220 }
222 {
224 btScalar *J1 = info->m_J1angularAxis;
225 btScalar *J2 = info->m_J2angularAxis;
226 J1[srow+0] = ax1[0];
227 J1[srow+1] = ax1[1];
228 J1[srow+2] = ax1[2];
229 J2[srow+0] = -ax1[0];
230 J2[srow+1] = -ax1[1];
231 J2[srow+2] = -ax1[2];
232 btScalar k = info->fps * m_biasFactor;
235 {
236 info->cfm[srow] = m_angCFM;
237 }
238 if(m_twistSpan > 0.0f)
239 {
240
241 if(m_twistCorrection > 0.0f)
242 {
243 info->m_lowerLimit[srow] = 0;
245 }
246 else
247 {
249 info->m_upperLimit[srow] = 0;
250 }
251 }
252 else
253 {
256 }
257 srow += info->rowskip;
258 }
259}
260
261
262
264{
266 {
270 m_accMotorImpulse = btVector3(0.,0.,0.);
271
272 if (!m_angularOnly)
273 {
277
278 btVector3 normal[3];
279 if (relPos.length2() > SIMD_EPSILON)
280 {
281 normal[0] = relPos.normalized();
282 }
283 else
284 {
285 normal[0].setValue(btScalar(1.0),0,0);
286 }
287
288 btPlaneSpace1(normal[0], normal[1], normal[2]);
289
290 for (int i=0;i<3;i++)
291 {
292 new (&m_jac[i]) btJacobianEntry(
297 normal[i],
301 m_rbB.getInvMass());
302 }
303 }
304
306 }
307}
308
309
310
312{
313 #ifndef __SPU__
315 {
318
319 btScalar tau = btScalar(0.3);
320
321 //linear part
322 if (!m_angularOnly)
323 {
326
328 bodyA.internalGetVelocityInLocalPointObsolete(rel_pos1,vel1);
330 bodyB.internalGetVelocityInLocalPointObsolete(rel_pos2,vel2);
332
333 for (int i=0;i<3;i++)
334 {
335 const btVector3& normal = m_jac[i].m_linearJointAxis;
337
339 rel_vel = normal.dot(vel);
340 //positional error (zeroth order error)
341 btScalar depth = -(pivotAInW - pivotBInW).dot(normal); //this is the error projected on the normal
344
347 bodyA.internalApplyImpulse(normal*m_rbA.getInvMass(), m_rbA.getInvInertiaTensorWorld()*ftorqueAxis1,impulse);
348 bodyB.internalApplyImpulse(normal*m_rbB.getInvMass(), m_rbB.getInvInertiaTensorWorld()*ftorqueAxis2,-impulse);
349
350 }
351 }
352
353 // apply motor
354 if (m_bMotorEnabled)
355 {
356 // compute current and predicted transforms
359 btVector3 omegaA; bodyA.internalGetAngularVelocity(omegaA);
360 btVector3 omegaB; bodyB.internalGetAngularVelocity(omegaB);
362 btVector3 zerovec(0,0,0);
364 trACur, zerovec, omegaA, timeStep, trAPred);
367 trBCur, zerovec, omegaB, timeStep, trBPred);
368
369 // compute desired transforms in world
374
375 // compute desired omegas in world
377
380
381 // compute delta omegas
384
385 // compute weighted avg axis of dOmega (weighting based on inertias)
388
389 if (dOmegaA.length2() > SIMD_EPSILON)
390 {
393 }
394
395 if (dOmegaB.length2() > SIMD_EPSILON)
396 {
397 axisB = dOmegaB.normalized();
399 }
400
402
403 static bool bDoTorque = true;
404 if (bDoTorque && avgAxis.length2() > SIMD_EPSILON)
405 {
410
413
414 if (m_maxMotorImpulse >= 0)
415 {
419
423 {
424 newUnclampedAccImpulse.normalize();
427 }
429 }
430
433
434 bodyA.internalApplyImpulse(btVector3(0,0,0), m_rbA.getInvInertiaTensorWorld()*impulseAxis, impulseMag);
435 bodyB.internalApplyImpulse(btVector3(0,0,0), m_rbB.getInvInertiaTensorWorld()*impulseAxis, -impulseMag);
436
437 }
438 }
439 else if (m_damping > SIMD_EPSILON) // no motor: do a little damping
440 {
441 btVector3 angVelA; bodyA.internalGetAngularVelocity(angVelA);
442 btVector3 angVelB; bodyB.internalGetAngularVelocity(angVelB);
444 if (relVel.length2() > SIMD_EPSILON)
445 {
451
454 bodyA.internalApplyImpulse(btVector3(0,0,0), m_rbA.getInvInertiaTensorWorld()*impulseAxis, impulseMag);
455 bodyB.internalApplyImpulse(btVector3(0,0,0), m_rbB.getInvInertiaTensorWorld()*impulseAxis, -impulseMag);
456 }
457 }
458
459 // joint limits
460 {
463 bodyA.internalGetAngularVelocity(angVelA);
465 bodyB.internalGetAngularVelocity(angVelB);
466
467 // solve swing limit
469 {
472 if (relSwingVel > 0)
475
476 // Clamp the accumulated impulse
480
482
483 // don't let cone response affect twist
484 // (this can happen since body A's twist doesn't match body B's AND we use an elliptical cone limit)
485 {
489 }
490
493
496 }
497
498
499 // solve twist limit
501 {
504 if (relTwistVel > 0) // only damp when moving towards limit (m_twistAxis flipping is important)
507
508 // Clamp the accumulated impulse
512
513 // btVector3 impulse = m_twistAxis * impulseMag;
514
515 bodyA.internalApplyImpulse(btVector3(0,0,0), m_rbA.getInvInertiaTensorWorld()*m_twistAxis,impulseMag);
516 bodyB.internalApplyImpulse(btVector3(0,0,0), m_rbB.getInvInertiaTensorWorld()*m_twistAxis,-impulseMag);
517 }
518 }
519 }
520#else
521btAssert(0);
522#endif //__SPU__
523}
524
525
526
527
529{
530 (void)timeStep;
531
532}
533
534
535#ifndef __SPU__
537{
540 m_solveTwistLimit = false;
541 m_solveSwingLimit = false;
542
543 btVector3 b1Axis1(0,0,0),b1Axis2(0,0,0),b1Axis3(0,0,0);
544 btVector3 b2Axis1(0,0,0),b2Axis2(0,0,0);
545
548
550
551 btScalar swx=btScalar(0.),swy = btScalar(0.);
552 btScalar thresh = btScalar(10.);
554
555 // Get Frame into world space
556 if (m_swingSpan1 >= btScalar(0.05f))
557 {
559 swx = b2Axis1.dot(b1Axis1);
560 swy = b2Axis1.dot(b1Axis2);
562 fact = (swy*swy + swx*swx) * thresh * thresh;
563 fact = fact / (fact + btScalar(1.0));
564 swing1 *= fact;
565 }
566
567 if (m_swingSpan2 >= btScalar(0.05f))
568 {
570 swx = b2Axis1.dot(b1Axis1);
571 swy = b2Axis1.dot(b1Axis3);
573 fact = (swy*swy + swx*swx) * thresh * thresh;
574 fact = fact / (fact + btScalar(1.0));
575 swing2 *= fact;
576 }
577
581
582 if (EllipseAngle > 1.0f)
583 {
585 m_solveSwingLimit = true;
586 // Calculate necessary axis & factors
589 btScalar swingAxisSign = (b2Axis1.dot(b1Axis1) >= 0.0f) ? 1.0f : -1.0f;
591 }
592
593 // Twist limits
594 if (m_twistSpan >= btScalar(0.))
595 {
601
602// btScalar lockedFreeFactor = (m_twistSpan > btScalar(0.05f)) ? m_limitSoftness : btScalar(0.);
605 {
607 m_solveTwistLimit = true;
608 m_twistAxis = (b2Axis1 + b1Axis1) * 0.5f;
610 m_twistAxis *= -1.0f;
611 }
613 {
615 m_solveTwistLimit = true;
616 m_twistAxis = (b2Axis1 + b1Axis1) * 0.5f;
618 }
619 }
620}
621#endif //__SPU__
622
623static btVector3 vTwist(1,0,0); // twist axis in constraint's space
624
625
626
628{
631 m_solveTwistLimit = false;
632 m_solveSwingLimit = false;
633 // compute rotation of A wrt B (in constraint space)
635 { // it is assumed that setMotorTarget() was alredy called
636 // and motor target m_qTarget is within constraint limits
637 // TODO : split rotation to pure swing and pure twist
638 // compute desired transforms in world
643 btQuaternion qDeltaAB = trDeltaAB.getRotation();
645 btScalar swingAxisLen2 = swingAxis.length2();
647 {
648 return;
649 }
652 m_swingCorrection = qDeltaAB.getAngle();
654 {
655 m_solveSwingLimit = true;
656 }
657 return;
658 }
659
660
661 {
662 // compute rotation of A wrt B (in constraint space)
663 btQuaternion qA = transA.getRotation() * m_rbAFrame.getRotation();
664 btQuaternion qB = transB.getRotation() * m_rbBFrame.getRotation();
666 // split rotation into cone and twist
667 // (all this is done from B's perspective. Maybe I should be averaging axes...)
671
673 {
676
678 {
679 m_solveSwingLimit = true;
680
681 // compute limit ratio: 0->1, where
682 // 0 == beginning of soft limit
683 // 1 == hard/real limit
684 m_swingLimitRatio = 1.f;
686 {
689 }
690
691 // swing correction tries to get back to soft limit
693
694 // adjustment of swing axis (based on ellipse normal)
696
697 // Calculate necessary axis & factors
699
700 m_twistAxisA.setValue(0,0,0);
701
702 m_kSwing = btScalar(1.) /
705 }
706 }
707 else
708 {
709 // you haven't set any limits;
710 // or you're trying to set at least one of the swing limits too small. (if so, do you really want a conetwist constraint?)
711 // anyway, we have either hinge or fixed joint
712 btVector3 ivA = transA.getBasis() * m_rbAFrame.getBasis().getColumn(0);
713 btVector3 jvA = transA.getBasis() * m_rbAFrame.getBasis().getColumn(1);
714 btVector3 kvA = transA.getBasis() * m_rbAFrame.getBasis().getColumn(2);
715 btVector3 ivB = transB.getBasis() * m_rbBFrame.getBasis().getColumn(0);
716 btVector3 target;
717 btScalar x = ivB.dot(ivA);
718 btScalar y = ivB.dot(jvA);
719 btScalar z = ivB.dot(kvA);
721 { // fixed. We'll need to add one more row to constraint
722 if((!btFuzzyZero(y)) || (!(btFuzzyZero(z))))
723 {
724 m_solveSwingLimit = true;
726 }
727 }
728 else
729 {
731 { // hinge around Y axis
732// if(!(btFuzzyZero(y)))
733 if((!(btFuzzyZero(x))) || (!(btFuzzyZero(z))))
734 {
735 m_solveSwingLimit = true;
737 {
738 y = btScalar(0.f);
739 btScalar span2 = btAtan2(z, x);
740 if(span2 > m_swingSpan2)
741 {
742 x = btCos(m_swingSpan2);
743 z = btSin(m_swingSpan2);
744 }
745 else if(span2 < -m_swingSpan2)
746 {
747 x = btCos(m_swingSpan2);
748 z = -btSin(m_swingSpan2);
749 }
750 }
751 }
752 }
753 else
754 { // hinge around Z axis
755// if(!btFuzzyZero(z))
756 if((!(btFuzzyZero(x))) || (!(btFuzzyZero(y))))
757 {
758 m_solveSwingLimit = true;
760 {
761 z = btScalar(0.f);
762 btScalar span1 = btAtan2(y, x);
763 if(span1 > m_swingSpan1)
764 {
765 x = btCos(m_swingSpan1);
766 y = btSin(m_swingSpan1);
767 }
768 else if(span1 < -m_swingSpan1)
769 {
770 x = btCos(m_swingSpan1);
771 y = -btSin(m_swingSpan1);
772 }
773 }
774 }
775 }
776 target[0] = x * ivA[0] + y * jvA[0] + z * kvA[0];
777 target[1] = x * ivA[1] + y * jvA[1] + z * kvA[1];
778 target[2] = x * ivA[2] + y * jvA[2] + z * kvA[2];
779 target.normalize();
780 m_swingAxis = -ivB.cross(target);
782
785 }
786 }
787
788 if (m_twistSpan >= btScalar(0.f))
789 {
792
794 {
795 m_solveTwistLimit = true;
796
797 m_twistLimitRatio = 1.f;
799 {
802 }
803
804 // twist correction tries to get back to soft limit
806
808
809 m_kTwist = btScalar(1.) /
812 }
813
816 }
817 else
818 {
819 m_twistAngle = btScalar(0.f);
820 }
821 }
822}
823
824
825
826// given a cone rotation in constraint space, (pre: twist must already be removed)
827// this method computes its corresponding swing angle and axis.
828// more interestingly, it computes the cone/swing limit (angle) for this cone "pose".
830 btScalar& swingAngle, // out
831 btVector3& vSwingAxis, // out
832 btScalar& swingLimit) // out
833{
834 swingAngle = qCone.getAngle();
836 {
837 vSwingAxis = btVector3(qCone.x(), qCone.y(), qCone.z());
838 vSwingAxis.normalize();
839#if 0
840 // non-zero twist?! this should never happen.
842#endif
843
844 // Compute limit for given swing. tricky:
845 // Given a swing axis, we're looking for the intersection with the bounding cone ellipse.
846 // (Since we're dealing with angles, this ellipse is embedded on the surface of a sphere.)
847
848 // For starters, compute the direction from center to surface of ellipse.
849 // This is just the perpendicular (ie. rotate 2D vector by PI/2) of the swing axis.
850 // (vSwingAxis is the cone rotation (in z,y); change vars and rotate to (x,y) coords.)
853
854 // Now, we use the slope of the vector (using x/yEllipse) and find the length
855 // of the line that intersects the ellipse:
856 // x^2 y^2
857 // --- + --- = 1, where a and b are semi-major axes 2 and 1 respectively (ie. the limits)
858 // a^2 b^2
859 // Do the math and it should be clear.
860
861 swingLimit = m_swingSpan1; // if xEllipse == 0, we have a pure vSwingAxis.z rotation: just use swingspan1
863 {
865 btScalar norm = 1 / (m_swingSpan2 * m_swingSpan2);
867 btScalar swingLimit2 = (1 + surfaceSlope2) / norm;
869 }
870
871 // test!
872 /*swingLimit = m_swingSpan2;
873 if (fabs(vSwingAxis.z()) > SIMD_EPSILON)
874 {
875 btScalar mag_2 = m_swingSpan1*m_swingSpan1 + m_swingSpan2*m_swingSpan2;
876 btScalar sinphi = m_swingSpan2 / sqrt(mag_2);
877 btScalar phi = asin(sinphi);
878 btScalar theta = atan2(fabs(vSwingAxis.y()),fabs(vSwingAxis.z()));
879 btScalar alpha = 3.14159f - theta - phi;
880 btScalar sinalpha = sin(alpha);
881 swingLimit = m_swingSpan1 * sinphi/sinalpha;
882 }*/
883 }
884 else if (swingAngle < 0)
885 {
886 // this should never happen!
887#if 0
888 btAssert(0);
889#endif
890 }
891}
892
894{
895 // compute x/y in ellipse using cone angle (0 -> 2*PI along surface of cone)
898
899 // Use the slope of the vector (using x/yEllipse) and find the length
900 // of the line that intersects the ellipse:
901 // x^2 y^2
902 // --- + --- = 1, where a and b are semi-major axes 2 and 1 respectively (ie. the limits)
903 // a^2 b^2
904 // Do the math and it should be clear.
905
906 btScalar swingLimit = m_swingSpan1; // if xEllipse == 0, just use axis b (1)
908 {
910 btScalar norm = 1 / (m_swingSpan2 * m_swingSpan2);
912 btScalar swingLimit2 = (1 + surfaceSlope2) / norm;
914 }
915
916 // convert into point in constraint space:
917 // note: twist is x-axis, swing 1 and 2 are along the z and y axes respectively
922}
923
924// given a twist rotation in constraint space, (pre: cone must already be removed)
925// this method computes its corresponding angle and axis.
927 btScalar& twistAngle, // out
928 btVector3& vTwistAxis) // out
929{
932
933 if (twistAngle > SIMD_PI) // long way around. flip quat and recalculate.
934 {
935 qMinTwist = -(qTwist);
936 twistAngle = qMinTwist.getAngle();
937 }
938 if (twistAngle < 0)
939 {
940 // this should never happen
941#if 0
942 btAssert(0);
943#endif
944 }
945
948 vTwistAxis.normalize();
949}
950
951
953{
954 // the swing axis is computed as the "twist-free" cone rotation,
955 // but the cone limit is not circular, but elliptical (if swingspan1 != swingspan2).
956 // so, if we're outside the limits, the closest way back inside the cone isn't
957 // along the vector back to the center. better (and more stable) to use the ellipse normal.
958
959 // convert swing axis to direction from center to surface of ellipse
960 // (ie. rotate 2D vector by PI/2)
961 btScalar y = -vSwingAxis.z();
962 btScalar z = vSwingAxis.y();
963
964 // do the math...
965 if (fabs(z) > SIMD_EPSILON) // avoid division by 0. and we don't need an update if z == 0.
966 {
967 // compute gradient/normal of ellipse surface at current "point"
968 btScalar grad = y/z;
970
971 // adjust y/z to represent normal at point (instead of vector to point)
972 if (y > 0)
973 y = fabs(grad * z);
974 else
975 y = -fabs(grad * z);
976
977 // convert ellipse direction back to swing axis
978 vSwingAxis.setZ(-y);
979 vSwingAxis.setY( z);
980 vSwingAxis.normalize();
981 }
982}
983
984
985
987{
988 //btTransform trACur = m_rbA.getCenterOfMassTransform();
989 //btTransform trBCur = m_rbB.getCenterOfMassTransform();
990// btTransform trABCur = trBCur.inverse() * trACur;
991// btQuaternion qABCur = trABCur.getRotation();
992// btTransform trConstraintCur = (trBCur * m_rbBFrame).inverse() * (trACur * m_rbAFrame);
993 //btQuaternion qConstraintCur = trConstraintCur.getRotation();
994
997}
998
999
1001{
1002 m_qTarget = q;
1003
1004 // clamp motor target to within limits
1005 {
1006 btScalar softness = 1.f;//m_limitSoftness;
1007
1008 // split into twist and cone
1012
1013 // clamp cone
1014 if (m_swingSpan1 >= btScalar(0.05f) && m_swingSpan2 >= btScalar(0.05f))
1015 {
1018
1020 {
1023 else if (swingAngle < -swingLimit*softness)
1026 }
1027 }
1028
1029 // clamp twist
1030 if (m_twistSpan >= btScalar(0.05f))
1031 {
1034
1036 {
1037 // eddy todo: limitSoftness used here???
1040 else if (twistAngle < -m_twistSpan*softness)
1043 }
1044 }
1045
1047 }
1048}
1049
1053{
1054 switch(num)
1055 {
1056 case BT_CONSTRAINT_ERP :
1058 if((axis >= 0) && (axis < 3))
1059 {
1060 m_linERP = value;
1062 }
1063 else
1064 {
1065 m_biasFactor = value;
1066 }
1067 break;
1068 case BT_CONSTRAINT_CFM :
1070 if((axis >= 0) && (axis < 3))
1071 {
1072 m_linCFM = value;
1074 }
1075 else
1076 {
1077 m_angCFM = value;
1079 }
1080 break;
1081 default:
1083 break;
1084 }
1085}
1086
1089{
1090 btScalar retVal = 0;
1091 switch(num)
1092 {
1093 case BT_CONSTRAINT_ERP :
1095 if((axis >= 0) && (axis < 3))
1096 {
1098 retVal = m_linERP;
1099 }
1100 else if((axis >= 3) && (axis < 6))
1101 {
1103 }
1104 else
1105 {
1107 }
1108 break;
1109 case BT_CONSTRAINT_CFM :
1111 if((axis >= 0) && (axis < 3))
1112 {
1114 retVal = m_linCFM;
1115 }
1116 else if((axis >= 3) && (axis < 6))
1117 {
1119 retVal = m_angCFM;
1120 }
1121 else
1122 {
1124 }
1125 break;
1126 default :
1128 }
1129 return retVal;
1130}
1131
1132
1134{
1137 buildJacobian();
1138 //calculateTransforms();
1139}
1140
1141
1142
1143
static btVector3 vTwist(1, 0, 0)
#define CONETWIST_USE_OBSOLETE_SOLVER
#define CONETWIST_DEF_FIX_THRESH
btScalar computeAngularImpulseDenominator(const btVector3 &axis, const btMatrix3x3 &invInertiaWorld)
@ BT_CONETWIST_FLAGS_LIN_CFM
@ BT_CONETWIST_FLAGS_LIN_ERP
@ BT_CONETWIST_FLAGS_ANG_CFM
const T & btMax(const T &a, const T &b)
Definition btMinMax.h:29
btScalar dot(const btQuaternion &q1, const btQuaternion &q2)
Calculate the dot product between two quaternions.
btQuaternion shortestArcQuat(const btVector3 &v0, const btVector3 &v1)
btVector3 quatRotate(const btQuaternion &rotation, const btVector3 &v)
#define SIMD_PI
Definition btScalar.h:504
float btScalar
The btScalar type abstracts floating point numbers, to easily switch between double and single floati...
Definition btScalar.h:292
#define BT_LARGE_FLOAT
Definition btScalar.h:294
btScalar btAtan2(btScalar x, btScalar y)
Definition btScalar.h:496
btScalar btSin(btScalar x)
Definition btScalar.h:477
btScalar btFabs(btScalar x)
Definition btScalar.h:475
#define SIMD_INFINITY
Definition btScalar.h:522
#define SIMD_FORCE_INLINE
Definition btScalar.h:81
btScalar btCos(btScalar x)
Definition btScalar.h:476
btScalar btAtan2Fast(btScalar y, btScalar x)
Definition btScalar.h:531
#define SIMD_EPSILON
Definition btScalar.h:521
bool btFuzzyZero(btScalar x)
Definition btScalar.h:550
#define btAssert(x)
Definition btScalar.h:131
#define btAssertConstrParams(_par)
@ BT_CONSTRAINT_CFM
@ BT_CONSTRAINT_ERP
@ BT_CONSTRAINT_STOP_CFM
@ BT_CONSTRAINT_STOP_ERP
@ CONETWIST_CONSTRAINT_TYPE
void btPlaneSpace1(const T &n, T &p, T &q)
Definition btVector3.h:1283
const btRigidBody & getRigidBodyB() const
virtual void buildJacobian()
internal method used by the constraint solver, don't use them directly
virtual void getInfo1(btConstraintInfo1 *info)
internal method used by the constraint solver, don't use them directly
virtual void solveConstraintObsolete(btSolverBody &bodyA, btSolverBody &bodyB, btScalar timeStep)
internal method used by the constraint solver, don't use them directly
btConeTwistConstraint(btRigidBody &rbA, btRigidBody &rbB, const btTransform &rbAFrame, const btTransform &rbBFrame)
void getInfo2NonVirtual(btConstraintInfo2 *info, const btTransform &transA, const btTransform &transB, const btMatrix3x3 &invInertiaWorldA, const btMatrix3x3 &invInertiaWorldB)
void computeTwistLimitInfo(const btQuaternion &qTwist, btScalar &twistAngle, btVector3 &vTwistAxis)
void setLimit(int limitIndex, btScalar limitValue)
void setMotorTargetInConstraintSpace(const btQuaternion &q)
const btRigidBody & getRigidBodyA() const
btVector3 GetPointForAngle(btScalar fAngleInRadians, btScalar fLength) const
void computeConeLimitInfo(const btQuaternion &qCone, btScalar &swingAngle, btVector3 &vSwingAxis, btScalar &swingLimit)
virtual void setParam(int num, btScalar value, int axis=-1)
override the default global value of a parameter (such as ERP or CFM), optionally provide the axis (0...
void getInfo1NonVirtual(btConstraintInfo1 *info)
virtual btScalar getParam(int num, int axis=-1) const
return the local value of parameter
void calcAngleInfo2(const btTransform &transA, const btTransform &transB, const btMatrix3x3 &invInertiaWorldA, const btMatrix3x3 &invInertiaWorldB)
virtual void getInfo2(btConstraintInfo2 *info)
internal method used by the constraint solver, don't use them directly
void adjustSwingAxisToUseEllipseNormal(btVector3 &vSwingAxis) const
virtual void setFrames(const btTransform &frameA, const btTransform &frameB)
void updateRHS(btScalar timeStep)
void setMotorTarget(const btQuaternion &q)
Jacobian entry is an abstraction that allows to describe constraints it can be used in combination wi...
btScalar getDiagonal() const
btVector3 m_linearJointAxis
The btMatrix3x3 class implements a 3x3 rotation matrix, to perform linear algebra in combination with...
Definition btMatrix3x3.h:48
btMatrix3x3 transpose() const
Return the transpose of the matrix.
btVector3 getColumn(int i) const
Get a column of the matrix as a vector.
The btQuaternion implements quaternion to perform linear algebra rotations in combination with btMatr...
btScalar getAngle() const
Return the angle [0, 2Pi] of rotation represented by this quaternion.
btQuaternion inverse() const
Return the inverse of this quaternion.
btQuaternion & normalize()
Normalize the quaternion Such that x^2 + y^2 + z^2 +w^2 = 1.
The btRigidBody is the main class for rigid body objects.
Definition btRigidBody.h:63
btScalar computeAngularImpulseDenominator(const btVector3 &axis) const
btScalar getInvMass() const
const btVector3 & getInvInertiaDiagLocal() const
const btTransform & getCenterOfMassTransform() const
const btVector3 & getCenterOfMassPosition() const
const btMatrix3x3 & getInvInertiaTensorWorld() const
static void integrateTransform(const btTransform &curTrans, const btVector3 &linvel, const btVector3 &angvel, btScalar timeStep, btTransform &predictedTransform)
static void calculateVelocity(const btTransform &transform0, const btTransform &transform1, btScalar timeStep, btVector3 &linVel, btVector3 &angVel)
The btTransform class supports rigid transforms with only translation and rotation and no scaling/she...
Definition btTransform.h:34
btTransform inverse() const
Return the inverse of this transform.
btMatrix3x3 & getBasis()
Return the basis matrix for the rotation.
void setIdentity()
Set this transformation to the identity.
btQuaternion getRotation() const
Return a quaternion representing the rotation.
btVector3 & getOrigin()
Return the origin vector translation.
void setOrigin(const btVector3 &origin)
Set the translational element.
TypedConstraint is the baseclass for Bullet constraints and vehicles.
btVector3 can be used to represent 3D points and vectors.
Definition btVector3.h:84
btScalar length() const
Return the length of the vector.
Definition btVector3.h:263
btVector3 cross(const btVector3 &v) const
Return the cross product between this and another vector.
Definition btVector3.h:389
btScalar dot(const btVector3 &v) const
Return the dot product.
Definition btVector3.h:235
void getSkewSymmetricMatrix(btVector3 *v0, btVector3 *v1, btVector3 *v2) const
Definition btVector3.h:660
void setValue(const btScalar &_x, const btScalar &_y, const btScalar &_z)
Definition btVector3.h:652
btVector3 normalized() const
Return a normalized version of this vector.
Definition btVector3.h:964
btVector3 & normalize()
Normalize this vector x^2 + y^2 + z^2 = 1.
Definition btVector3.h:309
The btSolverBody is an internal datastructure for the constraint solver. Only necessary data is packe...