Applied patch/contribution to improve btGeneric6DofConstraint. See also GenericJointDemo/Ragdoll.cpp
Thanks Francisco Leon/projectileman.
This commit is contained in:
@@ -15,6 +15,7 @@ subject to the following restrictions:
|
||||
|
||||
|
||||
|
||||
|
||||
#include "btBulletDynamicsCommon.h"
|
||||
#include "LinearMath/btIDebugDraw.h"
|
||||
|
||||
@@ -25,7 +26,6 @@ subject to the following restrictions:
|
||||
|
||||
#include "ConstraintDemo.h"
|
||||
#include "GL_ShapeDrawer.h"
|
||||
|
||||
#include "GlutStuff.h"
|
||||
|
||||
const int numObjects = 3;
|
||||
@@ -150,8 +150,9 @@ void ConstraintDemo::initPhysics()
|
||||
btTransform frameInA, frameInB;
|
||||
frameInA = btTransform::getIdentity();
|
||||
frameInB = btTransform::getIdentity();
|
||||
|
||||
btGeneric6DofConstraint* slider = new btGeneric6DofConstraint(*d6body0,*fixedBody1,frameInA,frameInB);
|
||||
|
||||
bool useLinearReferenceFrameA = false;//use fixed frame B for linear limits
|
||||
btGeneric6DofConstraint* slider = new btGeneric6DofConstraint(*d6body0,*fixedBody1,frameInA,frameInB,useLinearReferenceFrameA);
|
||||
slider->setLinearLowerLimit(lowerSliderLimit);
|
||||
slider->setLinearUpperLimit(hiSliderLimit);
|
||||
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
/*
|
||||
Bullet Continuous Collision Detection and Physics Library
|
||||
Ragdoll Demo
|
||||
Copyright (c) 2007 Starbreeze Studios
|
||||
|
||||
This software is provided 'as-is', without any express or implied warranty.
|
||||
In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it freely,
|
||||
subject to the following restrictions:
|
||||
|
||||
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.
|
||||
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
Written by: Marten Svanfeldt
|
||||
*/
|
||||
|
||||
/*
|
||||
Bullet Continuous Collision Detection and Physics Library
|
||||
Ragdoll Demo
|
||||
Copyright (c) 2007 Starbreeze Studios
|
||||
|
||||
This software is provided 'as-is', without any express or implied warranty.
|
||||
In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it freely,
|
||||
subject to the following restrictions:
|
||||
|
||||
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.
|
||||
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
Written by: Marten Svanfeldt
|
||||
*/
|
||||
|
||||
#include "Ragdoll.h"
|
||||
|
||||
//#define RIGID 1
|
||||
@@ -106,7 +106,7 @@ btScalar(0.)));
|
||||
// Now setup the constraints
|
||||
btGeneric6DofConstraint * joint6DOF;
|
||||
btTransform localA, localB;
|
||||
|
||||
bool useLinearReferenceFrameA = true;
|
||||
/// ******* SPINE HEAD ******** ///
|
||||
{
|
||||
localA.setIdentity(); localB.setIdentity();
|
||||
@@ -115,7 +115,7 @@ btScalar(0.)));
|
||||
|
||||
localB.setOrigin(btVector3(btScalar(0.), btScalar(-0.14*scale_ragdoll), btScalar(0.)));
|
||||
|
||||
joint6DOF = new btGeneric6DofConstraint(*m_bodies[BODYPART_SPINE], *m_bodies[BODYPART_HEAD], localA, localB);
|
||||
joint6DOF = new btGeneric6DofConstraint(*m_bodies[BODYPART_SPINE], *m_bodies[BODYPART_HEAD], localA, localB,useLinearReferenceFrameA);
|
||||
|
||||
#ifdef RIGID
|
||||
joint6DOF->setAngularLowerLimit(btVector3(-SIMD_EPSILON,-SIMD_EPSILON,-SIMD_EPSILON));
|
||||
@@ -141,7 +141,7 @@ btScalar(0.)));
|
||||
localB.getBasis().setEulerZYX(SIMD_HALF_PI,0,-SIMD_HALF_PI);
|
||||
localB.setOrigin(btVector3(btScalar(0.), btScalar(-0.18*scale_ragdoll), btScalar(0.)));
|
||||
|
||||
joint6DOF = new btGeneric6DofConstraint(*m_bodies[BODYPART_SPINE], *m_bodies[BODYPART_LEFT_UPPER_ARM], localA, localB);
|
||||
joint6DOF = new btGeneric6DofConstraint(*m_bodies[BODYPART_SPINE], *m_bodies[BODYPART_LEFT_UPPER_ARM], localA, localB,useLinearReferenceFrameA);
|
||||
|
||||
#ifdef RIGID
|
||||
joint6DOF->setAngularLowerLimit(btVector3(-SIMD_EPSILON,-SIMD_EPSILON,-SIMD_EPSILON));
|
||||
@@ -163,7 +163,7 @@ btScalar(0.)));
|
||||
localA.setOrigin(btVector3(btScalar(0.2*scale_ragdoll), btScalar(0.15*scale_ragdoll), btScalar(0.)));
|
||||
localB.getBasis().setEulerZYX(0,0,SIMD_HALF_PI);
|
||||
localB.setOrigin(btVector3(btScalar(0.), btScalar(-0.18*scale_ragdoll), btScalar(0.)));
|
||||
joint6DOF = new btGeneric6DofConstraint(*m_bodies[BODYPART_SPINE], *m_bodies[BODYPART_RIGHT_UPPER_ARM], localA, localB);
|
||||
joint6DOF = new btGeneric6DofConstraint(*m_bodies[BODYPART_SPINE], *m_bodies[BODYPART_RIGHT_UPPER_ARM], localA, localB,useLinearReferenceFrameA);
|
||||
|
||||
#ifdef RIGID
|
||||
joint6DOF->setAngularLowerLimit(btVector3(-SIMD_EPSILON,-SIMD_EPSILON,-SIMD_EPSILON));
|
||||
@@ -184,7 +184,7 @@ btScalar(0.)));
|
||||
|
||||
localA.setOrigin(btVector3(btScalar(0.), btScalar(0.18*scale_ragdoll), btScalar(0.)));
|
||||
localB.setOrigin(btVector3(btScalar(0.), btScalar(-0.14*scale_ragdoll), btScalar(0.)));
|
||||
joint6DOF = new btGeneric6DofConstraint (*m_bodies[BODYPART_LEFT_UPPER_ARM], *m_bodies[BODYPART_LEFT_LOWER_ARM], localA, localB);
|
||||
joint6DOF = new btGeneric6DofConstraint (*m_bodies[BODYPART_LEFT_UPPER_ARM], *m_bodies[BODYPART_LEFT_LOWER_ARM], localA, localB,useLinearReferenceFrameA);
|
||||
|
||||
#ifdef RIGID
|
||||
joint6DOF->setAngularLowerLimit(btVector3(-SIMD_EPSILON,-SIMD_EPSILON,-SIMD_EPSILON));
|
||||
@@ -204,7 +204,7 @@ btScalar(0.)));
|
||||
|
||||
localA.setOrigin(btVector3(btScalar(0.), btScalar(0.18*scale_ragdoll), btScalar(0.)));
|
||||
localB.setOrigin(btVector3(btScalar(0.), btScalar(-0.14*scale_ragdoll), btScalar(0.)));
|
||||
joint6DOF = new btGeneric6DofConstraint (*m_bodies[BODYPART_RIGHT_UPPER_ARM], *m_bodies[BODYPART_RIGHT_LOWER_ARM], localA, localB);
|
||||
joint6DOF = new btGeneric6DofConstraint (*m_bodies[BODYPART_RIGHT_UPPER_ARM], *m_bodies[BODYPART_RIGHT_LOWER_ARM], localA, localB,useLinearReferenceFrameA);
|
||||
|
||||
#ifdef RIGID
|
||||
joint6DOF->setAngularLowerLimit(btVector3(-SIMD_EPSILON,-SIMD_EPSILON,-SIMD_EPSILON));
|
||||
@@ -228,7 +228,7 @@ btScalar(0.)));
|
||||
localA.setOrigin(btVector3(btScalar(0.), btScalar(0.15*scale_ragdoll), btScalar(0.)));
|
||||
localB.getBasis().setEulerZYX(0,M_PI_2,0);
|
||||
localB.setOrigin(btVector3(btScalar(0.), btScalar(-0.15*scale_ragdoll), btScalar(0.)));
|
||||
joint6DOF = new btGeneric6DofConstraint (*m_bodies[BODYPART_PELVIS], *m_bodies[BODYPART_SPINE], localA, localB);
|
||||
joint6DOF = new btGeneric6DofConstraint (*m_bodies[BODYPART_PELVIS], *m_bodies[BODYPART_SPINE], localA, localB,useLinearReferenceFrameA);
|
||||
|
||||
#ifdef RIGID
|
||||
joint6DOF->setAngularLowerLimit(btVector3(-SIMD_EPSILON,-SIMD_EPSILON,-SIMD_EPSILON));
|
||||
@@ -250,7 +250,7 @@ btScalar(0.)));
|
||||
|
||||
localB.setOrigin(btVector3(btScalar(0.), btScalar(0.225*scale_ragdoll), btScalar(0.)));
|
||||
|
||||
joint6DOF = new btGeneric6DofConstraint(*m_bodies[BODYPART_PELVIS], *m_bodies[BODYPART_LEFT_UPPER_LEG], localA, localB);
|
||||
joint6DOF = new btGeneric6DofConstraint(*m_bodies[BODYPART_PELVIS], *m_bodies[BODYPART_LEFT_UPPER_LEG], localA, localB,useLinearReferenceFrameA);
|
||||
|
||||
#ifdef RIGID
|
||||
joint6DOF->setAngularLowerLimit(btVector3(-SIMD_EPSILON,-SIMD_EPSILON,-SIMD_EPSILON));
|
||||
@@ -272,7 +272,7 @@ btScalar(0.)));
|
||||
localA.setOrigin(btVector3(btScalar(0.18*scale_ragdoll), btScalar(-0.10*scale_ragdoll), btScalar(0.)));
|
||||
localB.setOrigin(btVector3(btScalar(0.), btScalar(0.225*scale_ragdoll), btScalar(0.)));
|
||||
|
||||
joint6DOF = new btGeneric6DofConstraint(*m_bodies[BODYPART_PELVIS], *m_bodies[BODYPART_RIGHT_UPPER_LEG], localA, localB);
|
||||
joint6DOF = new btGeneric6DofConstraint(*m_bodies[BODYPART_PELVIS], *m_bodies[BODYPART_RIGHT_UPPER_LEG], localA, localB,useLinearReferenceFrameA);
|
||||
|
||||
#ifdef RIGID
|
||||
joint6DOF->setAngularLowerLimit(btVector3(-SIMD_EPSILON,-SIMD_EPSILON,-SIMD_EPSILON));
|
||||
@@ -293,7 +293,7 @@ btScalar(0.)));
|
||||
|
||||
localA.setOrigin(btVector3(btScalar(0.), btScalar(-0.225*scale_ragdoll), btScalar(0.)));
|
||||
localB.setOrigin(btVector3(btScalar(0.), btScalar(0.185*scale_ragdoll), btScalar(0.)));
|
||||
joint6DOF = new btGeneric6DofConstraint (*m_bodies[BODYPART_LEFT_UPPER_LEG], *m_bodies[BODYPART_LEFT_LOWER_LEG], localA, localB);
|
||||
joint6DOF = new btGeneric6DofConstraint (*m_bodies[BODYPART_LEFT_UPPER_LEG], *m_bodies[BODYPART_LEFT_LOWER_LEG], localA, localB,useLinearReferenceFrameA);
|
||||
//
|
||||
#ifdef RIGID
|
||||
joint6DOF->setAngularLowerLimit(btVector3(-SIMD_EPSILON,-SIMD_EPSILON,-SIMD_EPSILON));
|
||||
@@ -313,7 +313,7 @@ btScalar(0.)));
|
||||
|
||||
localA.setOrigin(btVector3(btScalar(0.), btScalar(-0.225*scale_ragdoll), btScalar(0.)));
|
||||
localB.setOrigin(btVector3(btScalar(0.), btScalar(0.185*scale_ragdoll), btScalar(0.)));
|
||||
joint6DOF = new btGeneric6DofConstraint (*m_bodies[BODYPART_RIGHT_UPPER_LEG], *m_bodies[BODYPART_RIGHT_LOWER_LEG], localA, localB);
|
||||
joint6DOF = new btGeneric6DofConstraint (*m_bodies[BODYPART_RIGHT_UPPER_LEG], *m_bodies[BODYPART_RIGHT_LOWER_LEG], localA, localB,useLinearReferenceFrameA);
|
||||
|
||||
#ifdef RIGID
|
||||
joint6DOF->setAngularLowerLimit(btVector3(-SIMD_EPSILON,-SIMD_EPSILON,-SIMD_EPSILON));
|
||||
@@ -349,8 +349,8 @@ RagDoll::~RagDoll()
|
||||
delete m_bodies[i]; m_bodies[i] = 0;
|
||||
delete m_shapes[i]; m_shapes[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
btRigidBody* RagDoll::localCreateRigidBody (btScalar mass, const btTransform& startTransform, btCollisionShape* shape)
|
||||
{
|
||||
|
||||
@@ -4,14 +4,20 @@ Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
|
||||
|
||||
This software is provided 'as-is', without any express or implied warranty.
|
||||
In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it freely,
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it freely,
|
||||
subject to the following restrictions:
|
||||
|
||||
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.
|
||||
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
/*
|
||||
2007-09-09
|
||||
Refactored by Francisco Le<4C>n
|
||||
email: projectileman@yahoo.com
|
||||
http://gimpact.sf.net
|
||||
*/
|
||||
|
||||
|
||||
#include "btGeneric6DofConstraint.h"
|
||||
@@ -19,372 +25,473 @@ subject to the following restrictions:
|
||||
#include "LinearMath/btTransformUtil.h"
|
||||
#include <new>
|
||||
|
||||
|
||||
static const btScalar kSign[] = { btScalar(1.0), btScalar(-1.0), btScalar(1.0) };
|
||||
static const int kAxisA[] = { 1, 0, 0 };
|
||||
static const int kAxisB[] = { 2, 2, 1 };
|
||||
#define GENERIC_D6_DISABLE_WARMSTARTING 1
|
||||
|
||||
btGeneric6DofConstraint::btGeneric6DofConstraint()
|
||||
:btTypedConstraint(D6_CONSTRAINT_TYPE)
|
||||
btScalar btGetMatrixElem(const btMatrix3x3& mat, int index)
|
||||
{
|
||||
}
|
||||
|
||||
btGeneric6DofConstraint::btGeneric6DofConstraint(btRigidBody& rbA, btRigidBody& rbB, const btTransform& frameInA, const btTransform& frameInB)
|
||||
: btTypedConstraint(D6_CONSTRAINT_TYPE, rbA, rbB)
|
||||
, m_frameInA(frameInA)
|
||||
, m_frameInB(frameInB)
|
||||
{
|
||||
//free means upper < lower,
|
||||
//locked means upper == lower
|
||||
//limited means upper > lower
|
||||
//so start all locked
|
||||
for (int i=0; i<6;++i)
|
||||
{
|
||||
m_lowerLimit[i] = btScalar(0.0);
|
||||
m_upperLimit[i] = btScalar(0.0);
|
||||
m_accumulatedImpulse[i] = btScalar(0.0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void btGeneric6DofConstraint::buildJacobian()
|
||||
{
|
||||
btVector3 localNormalInA(0,0,0);
|
||||
|
||||
const btVector3& pivotInA = m_frameInA.getOrigin();
|
||||
const btVector3& pivotInB = m_frameInB.getOrigin();
|
||||
|
||||
btVector3 pivotAInW = m_rbA.getCenterOfMassTransform() * m_frameInA.getOrigin();
|
||||
btVector3 pivotBInW = m_rbB.getCenterOfMassTransform() * m_frameInB.getOrigin();
|
||||
|
||||
btVector3 rel_pos1 = pivotAInW - m_rbA.getCenterOfMassPosition();
|
||||
btVector3 rel_pos2 = pivotBInW - m_rbB.getCenterOfMassPosition();
|
||||
|
||||
int i;
|
||||
//linear part
|
||||
for (i=0;i<3;i++)
|
||||
{
|
||||
if (isLimited(i))
|
||||
{
|
||||
localNormalInA[i] = 1;
|
||||
btVector3 normalWorld = m_rbA.getCenterOfMassTransform().getBasis() * localNormalInA;
|
||||
|
||||
|
||||
// Create linear atom
|
||||
new (&m_jacLinear[i]) btJacobianEntry(
|
||||
m_rbA.getCenterOfMassTransform().getBasis().transpose(),
|
||||
m_rbB.getCenterOfMassTransform().getBasis().transpose(),
|
||||
m_rbA.getCenterOfMassTransform()*pivotInA - m_rbA.getCenterOfMassPosition(),
|
||||
m_rbB.getCenterOfMassTransform()*pivotInB - m_rbB.getCenterOfMassPosition(),
|
||||
normalWorld,
|
||||
m_rbA.getInvInertiaDiagLocal(),
|
||||
m_rbA.getInvMass(),
|
||||
m_rbB.getInvInertiaDiagLocal(),
|
||||
m_rbB.getInvMass());
|
||||
|
||||
//optionally disable warmstarting
|
||||
#ifdef GENERIC_D6_DISABLE_WARMSTARTING
|
||||
m_accumulatedImpulse[i] = btScalar(0.);
|
||||
#endif //GENERIC_D6_DISABLE_WARMSTARTING
|
||||
|
||||
// Apply accumulated impulse
|
||||
btVector3 impulse_vector = m_accumulatedImpulse[i] * normalWorld;
|
||||
|
||||
m_rbA.applyImpulse( impulse_vector, rel_pos1);
|
||||
m_rbB.applyImpulse(-impulse_vector, rel_pos2);
|
||||
|
||||
localNormalInA[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// angular part
|
||||
for (i=0;i<3;i++)
|
||||
{
|
||||
if (isLimited(i+3))
|
||||
{
|
||||
btVector3 axisA = m_rbA.getCenterOfMassTransform().getBasis() * m_frameInA.getBasis().getColumn( kAxisA[i] );
|
||||
btVector3 axisB = m_rbB.getCenterOfMassTransform().getBasis() * m_frameInB.getBasis().getColumn( kAxisB[i] );
|
||||
|
||||
// Dirk: This is IMO mathematically the correct way, but we should consider axisA and axisB being near parallel maybe
|
||||
btVector3 axis = kSign[i] * axisA.cross(axisB);
|
||||
|
||||
// Create angular atom
|
||||
new (&m_jacAng[i]) btJacobianEntry(axis,
|
||||
m_rbA.getCenterOfMassTransform().getBasis().transpose(),
|
||||
m_rbB.getCenterOfMassTransform().getBasis().transpose(),
|
||||
m_rbA.getInvInertiaDiagLocal(),
|
||||
m_rbB.getInvInertiaDiagLocal());
|
||||
|
||||
#ifdef GENERIC_D6_DISABLE_WARMSTARTING
|
||||
m_accumulatedImpulse[i + 3] = btScalar(0.);
|
||||
#endif //GENERIC_D6_DISABLE_WARMSTARTING
|
||||
|
||||
// Apply accumulated impulse
|
||||
btVector3 impulse_vector = m_accumulatedImpulse[i + 3] * axis;
|
||||
|
||||
m_rbA.applyTorqueImpulse( impulse_vector);
|
||||
m_rbB.applyTorqueImpulse(-impulse_vector);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
btScalar getMatrixElem(const btMatrix3x3& mat,int index)
|
||||
{
|
||||
int row = index%3;
|
||||
int col = index / 3;
|
||||
return mat[row][col];
|
||||
int i = index%3;
|
||||
int j = index/3;
|
||||
return mat[i][j];
|
||||
}
|
||||
|
||||
///MatrixToEulerXYZ from http://www.geometrictools.com/LibFoundation/Mathematics/Wm4Matrix3.inl.html
|
||||
bool MatrixToEulerXYZ(const btMatrix3x3& mat,btVector3& xyz)
|
||||
bool matrixToEulerXYZ(const btMatrix3x3& mat,btVector3& xyz)
|
||||
{
|
||||
// rot = cy*cz -cy*sz sy
|
||||
// cz*sx*sy+cx*sz cx*cz-sx*sy*sz -cy*sx
|
||||
// -cx*cz*sy+sx*sz cz*sx+cx*sy*sz cx*cy
|
||||
// // rot = cy*cz -cy*sz sy
|
||||
// // cz*sx*sy+cx*sz cx*cz-sx*sy*sz -cy*sx
|
||||
// // -cx*cz*sy+sx*sz cz*sx+cx*sy*sz cx*cy
|
||||
//
|
||||
|
||||
if (btGetMatrixElem(mat,2) < btScalar(1.0))
|
||||
{
|
||||
if (btGetMatrixElem(mat,2) > btScalar(-1.0))
|
||||
{
|
||||
xyz[0] = btAtan2(-btGetMatrixElem(mat,5),btGetMatrixElem(mat,8));
|
||||
xyz[1] = btAsin(btGetMatrixElem(mat,2));
|
||||
xyz[2] = btAtan2(-btGetMatrixElem(mat,1),btGetMatrixElem(mat,0));
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// WARNING. Not unique. XA - ZA = -atan2(r10,r11)
|
||||
xyz[0] = -btAtan2(btGetMatrixElem(mat,3),btGetMatrixElem(mat,4));
|
||||
xyz[1] = -SIMD_HALF_PI;
|
||||
xyz[2] = btScalar(0.0);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// WARNING. Not unique. XAngle + ZAngle = atan2(r10,r11)
|
||||
xyz[0] = btAtan2(btGetMatrixElem(mat,3),btGetMatrixElem(mat,4));
|
||||
xyz[1] = SIMD_HALF_PI;
|
||||
xyz[2] = 0.0;
|
||||
|
||||
}
|
||||
|
||||
/// 0..8
|
||||
|
||||
if (getMatrixElem(mat,2) < btScalar(1.0))
|
||||
{
|
||||
if (getMatrixElem(mat,2) > btScalar(-1.0))
|
||||
{
|
||||
xyz[0] = btAtan2(-getMatrixElem(mat,5),getMatrixElem(mat,8));
|
||||
xyz[1] = btAsin(getMatrixElem(mat,2));
|
||||
xyz[2] = btAtan2(-getMatrixElem(mat,1),getMatrixElem(mat,0));
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// WARNING. Not unique. XA - ZA = -atan2(r10,r11)
|
||||
xyz[0] = -btAtan2(getMatrixElem(mat,3),getMatrixElem(mat,4));
|
||||
xyz[1] = -SIMD_HALF_PI;
|
||||
xyz[2] = btScalar(0.0);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// WARNING. Not unique. XAngle + ZAngle = atan2(r10,r11)
|
||||
xyz[0] = btAtan2(getMatrixElem(mat,3),getMatrixElem(mat,4));
|
||||
xyz[1] = SIMD_HALF_PI;
|
||||
xyz[2] = 0.0;
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void btGeneric6DofConstraint::solveConstraint(btScalar timeStep)
|
||||
|
||||
//////////////////////////// btRotationalLimitMotor ////////////////////////////////////
|
||||
|
||||
|
||||
int btRotationalLimitMotor::testLimitValue(btScalar test_value)
|
||||
{
|
||||
btScalar tau = btScalar(0.1);
|
||||
btScalar damping = btScalar(1.0);
|
||||
|
||||
btVector3 pivotAInW = m_rbA.getCenterOfMassTransform() * m_frameInA.getOrigin();
|
||||
btVector3 pivotBInW = m_rbB.getCenterOfMassTransform() * m_frameInB.getOrigin();
|
||||
|
||||
btVector3 rel_pos1 = pivotAInW - m_rbA.getCenterOfMassPosition();
|
||||
btVector3 rel_pos2 = pivotBInW - m_rbB.getCenterOfMassPosition();
|
||||
|
||||
btVector3 localNormalInA(0,0,0);
|
||||
int i;
|
||||
|
||||
// linear
|
||||
for (i=0;i<3;i++)
|
||||
{
|
||||
if (isLimited(i))
|
||||
{
|
||||
btVector3 angvelA = m_rbA.getCenterOfMassTransform().getBasis().transpose() * m_rbA.getAngularVelocity();
|
||||
btVector3 angvelB = m_rbB.getCenterOfMassTransform().getBasis().transpose() * m_rbB.getAngularVelocity();
|
||||
|
||||
localNormalInA.setValue(0,0,0);
|
||||
localNormalInA[i] = 1;
|
||||
btVector3 normalWorld = m_rbA.getCenterOfMassTransform().getBasis() * localNormalInA;
|
||||
|
||||
btScalar jacDiagABInv = btScalar(1.) / m_jacLinear[i].getDiagonal();
|
||||
|
||||
//velocity error (first order error)
|
||||
btScalar rel_vel = m_jacLinear[i].getRelativeVelocity(m_rbA.getLinearVelocity(),angvelA,
|
||||
m_rbB.getLinearVelocity(),angvelB);
|
||||
|
||||
//positional error (zeroth order error)
|
||||
btScalar depth = -(pivotAInW - pivotBInW).dot(normalWorld);
|
||||
btScalar lo = btScalar(-1e30);
|
||||
btScalar hi = btScalar(1e30);
|
||||
|
||||
//handle the limits
|
||||
if (m_lowerLimit[i] < m_upperLimit[i])
|
||||
{
|
||||
{
|
||||
if (depth > m_upperLimit[i])
|
||||
{
|
||||
depth -= m_upperLimit[i];
|
||||
lo = btScalar(0.);
|
||||
|
||||
} else
|
||||
{
|
||||
if (depth < m_lowerLimit[i])
|
||||
{
|
||||
depth -= m_lowerLimit[i];
|
||||
hi = btScalar(0.);
|
||||
} else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
btScalar normalImpulse= (tau*depth/timeStep - damping*rel_vel) * jacDiagABInv;
|
||||
btScalar oldNormalImpulse = m_accumulatedImpulse[i];
|
||||
btScalar sum = oldNormalImpulse + normalImpulse;
|
||||
m_accumulatedImpulse[i] = sum > hi ? btScalar(0.) : sum < lo ? btScalar(0.) : sum;
|
||||
normalImpulse = m_accumulatedImpulse[i] - oldNormalImpulse;
|
||||
|
||||
btVector3 impulse_vector = normalWorld * normalImpulse;
|
||||
m_rbA.applyImpulse( impulse_vector, rel_pos1);
|
||||
m_rbB.applyImpulse(-impulse_vector, rel_pos2);
|
||||
|
||||
localNormalInA[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
btVector3 axis;
|
||||
btScalar angle;
|
||||
btTransform frameAWorld = m_rbA.getCenterOfMassTransform() * m_frameInA;
|
||||
btTransform frameBWorld = m_rbB.getCenterOfMassTransform() * m_frameInB;
|
||||
|
||||
btTransformUtil::calculateDiffAxisAngle(frameAWorld,frameBWorld,axis,angle);
|
||||
btQuaternion diff(axis,angle);
|
||||
btMatrix3x3 diffMat (diff);
|
||||
btVector3 xyz;
|
||||
///this is not perfect, we can first check which axis are limited, and choose a more appropriate order
|
||||
MatrixToEulerXYZ(diffMat,xyz);
|
||||
|
||||
// angular
|
||||
for (i=0;i<3;i++)
|
||||
if(m_loLimit>m_hiLimit)
|
||||
{
|
||||
if (isLimited(i+3))
|
||||
{
|
||||
btVector3 angvelA = m_rbA.getCenterOfMassTransform().getBasis().transpose() * m_rbA.getAngularVelocity();
|
||||
btVector3 angvelB = m_rbB.getCenterOfMassTransform().getBasis().transpose() * m_rbB.getAngularVelocity();
|
||||
|
||||
btScalar jacDiagABInv = btScalar(1.) / m_jacAng[i].getDiagonal();
|
||||
|
||||
//velocity error (first order error)
|
||||
btScalar rel_vel = m_jacAng[i].getRelativeVelocity(m_rbA.getLinearVelocity(),angvelA,
|
||||
m_rbB.getLinearVelocity(),angvelB);
|
||||
|
||||
//positional error (zeroth order error)
|
||||
btVector3 axisA = m_rbA.getCenterOfMassTransform().getBasis() * m_frameInA.getBasis().getColumn( kAxisA[i] );
|
||||
btVector3 axisB = m_rbB.getCenterOfMassTransform().getBasis() * m_frameInB.getBasis().getColumn( kAxisB[i] );
|
||||
|
||||
btScalar rel_pos = kSign[i] * axisA.dot(axisB);
|
||||
|
||||
btScalar lo = btScalar(-1e30);
|
||||
btScalar hi = btScalar(1e30);
|
||||
|
||||
//handle the twist limit
|
||||
if (m_lowerLimit[i+3] < m_upperLimit[i+3])
|
||||
{
|
||||
//clamp the values
|
||||
btScalar loLimit = m_lowerLimit[i+3] > -3.1415 ? m_lowerLimit[i+3] : btScalar(-1e30);
|
||||
btScalar hiLimit = m_upperLimit[i+3] < 3.1415 ? m_upperLimit[i+3] : btScalar(1e30);
|
||||
|
||||
btScalar projAngle = btScalar(-1.)*xyz[i];
|
||||
|
||||
if (projAngle < loLimit)
|
||||
{
|
||||
hi = btScalar(0.);
|
||||
rel_pos = (loLimit - projAngle);
|
||||
} else
|
||||
{
|
||||
if (projAngle > hiLimit)
|
||||
{
|
||||
lo = btScalar(0.);
|
||||
rel_pos = (hiLimit - projAngle);
|
||||
} else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//impulse
|
||||
|
||||
btScalar normalImpulse= -(tau*rel_pos/timeStep + damping*rel_vel) * jacDiagABInv;
|
||||
btScalar oldNormalImpulse = m_accumulatedImpulse[i+3];
|
||||
btScalar sum = oldNormalImpulse + normalImpulse;
|
||||
m_accumulatedImpulse[i+3] = sum > hi ? btScalar(0.) : sum < lo ? btScalar(0.) : sum;
|
||||
normalImpulse = m_accumulatedImpulse[i+3] - oldNormalImpulse;
|
||||
|
||||
// Dirk: Not needed - we could actually project onto Jacobian entry here (same as above)
|
||||
btVector3 axis = kSign[i] * axisA.cross(axisB);
|
||||
btVector3 impulse_vector = axis * normalImpulse;
|
||||
|
||||
m_rbA.applyTorqueImpulse( impulse_vector);
|
||||
m_rbB.applyTorqueImpulse(-impulse_vector);
|
||||
}
|
||||
m_currentLimit = 0;//Free from violation
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (test_value < m_loLimit)
|
||||
{
|
||||
m_currentLimit = 1;//low limit violation
|
||||
m_currentLimitError = test_value - m_loLimit;
|
||||
return 1;
|
||||
}
|
||||
else if (test_value> m_hiLimit)
|
||||
{
|
||||
m_currentLimit = 2;//High limit violation
|
||||
m_currentLimitError = test_value - m_hiLimit;
|
||||
return 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_currentLimit = 0;//Free from violation
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
btScalar btRotationalLimitMotor::solveAngularLimits(
|
||||
btScalar timeStep,btVector3 axis,btScalar jacDiagABInv,
|
||||
btRigidBody * body0, btRigidBody * body1)
|
||||
{
|
||||
if (needApplyTorques()==false) return 0.0f;
|
||||
|
||||
btScalar target_velocity = m_targetVelocity;
|
||||
btScalar maxMotorForce = m_maxMotorForce;
|
||||
|
||||
//current error correction
|
||||
if (m_currentLimit!=0)
|
||||
{
|
||||
target_velocity = -m_ERP*m_currentLimitError/(timeStep);
|
||||
maxMotorForce = m_maxLimitForce;
|
||||
}
|
||||
|
||||
maxMotorForce *= timeStep;
|
||||
|
||||
// current velocity difference
|
||||
btVector3 vel_diff = body0->getAngularVelocity();
|
||||
if (body1)
|
||||
{
|
||||
vel_diff -= body1->getAngularVelocity();
|
||||
}
|
||||
|
||||
|
||||
|
||||
btScalar rel_vel = axis.dot(vel_diff);
|
||||
|
||||
// correction velocity
|
||||
btScalar motor_relvel = m_limitSoftness*(target_velocity - m_damping*rel_vel);
|
||||
|
||||
|
||||
if ( motor_relvel < SIMD_EPSILON && motor_relvel > -SIMD_EPSILON )
|
||||
{
|
||||
return 0.0f;//no need for applying force
|
||||
}
|
||||
|
||||
|
||||
// correction impulse
|
||||
btScalar unclippedMotorImpulse = (1+m_bounce)*motor_relvel*jacDiagABInv;
|
||||
|
||||
// clip correction impulse
|
||||
btScalar clippedMotorImpulse;
|
||||
|
||||
//todo: should clip against accumulated impulse
|
||||
if (unclippedMotorImpulse>0.0f)
|
||||
{
|
||||
clippedMotorImpulse = unclippedMotorImpulse > maxMotorForce? maxMotorForce: unclippedMotorImpulse;
|
||||
}
|
||||
else
|
||||
{
|
||||
clippedMotorImpulse = unclippedMotorImpulse < -maxMotorForce ? -maxMotorForce: unclippedMotorImpulse;
|
||||
}
|
||||
|
||||
|
||||
// sort with accumulated impulses
|
||||
btScalar lo = btScalar(-1e30);
|
||||
btScalar hi = btScalar(1e30);
|
||||
|
||||
btScalar oldaccumImpulse = m_accumulatedImpulse;
|
||||
btScalar sum = oldaccumImpulse + clippedMotorImpulse;
|
||||
m_accumulatedImpulse = sum > hi ? btScalar(0.) : sum < lo ? btScalar(0.) : sum;
|
||||
|
||||
clippedMotorImpulse = m_accumulatedImpulse - oldaccumImpulse;
|
||||
|
||||
|
||||
|
||||
btVector3 motorImp = clippedMotorImpulse * axis;
|
||||
|
||||
|
||||
body0->applyTorqueImpulse(motorImp);
|
||||
if (body1) body1->applyTorqueImpulse(-motorImp);
|
||||
|
||||
return clippedMotorImpulse;
|
||||
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////// End btRotationalLimitMotor ////////////////////////////////////
|
||||
|
||||
//////////////////////////// btTranslationalLimitMotor ////////////////////////////////////
|
||||
btScalar btTranslationalLimitMotor::solveLinearAxis(
|
||||
btScalar timeStep,
|
||||
btScalar jacDiagABInv,
|
||||
btRigidBody& body1,const btVector3 &pointInA,
|
||||
btRigidBody& body2,const btVector3 &pointInB,
|
||||
int limit_index,
|
||||
const btVector3 & axis_normal_on_a)
|
||||
{
|
||||
|
||||
///find relative velocity
|
||||
btVector3 rel_pos1 = pointInA - body1.getCenterOfMassPosition();
|
||||
btVector3 rel_pos2 = pointInB - body2.getCenterOfMassPosition();
|
||||
|
||||
btVector3 vel1 = body1.getVelocityInLocalPoint(rel_pos1);
|
||||
btVector3 vel2 = body2.getVelocityInLocalPoint(rel_pos2);
|
||||
btVector3 vel = vel1 - vel2;
|
||||
|
||||
btScalar rel_vel = axis_normal_on_a.dot(vel);
|
||||
|
||||
|
||||
|
||||
/// apply displacement correction
|
||||
|
||||
//positional error (zeroth order error)
|
||||
btScalar depth = -(pointInA - pointInB).dot(axis_normal_on_a);
|
||||
btScalar lo = btScalar(-1e30);
|
||||
btScalar hi = btScalar(1e30);
|
||||
|
||||
btScalar minLimit = m_lowerLimit[limit_index];
|
||||
btScalar maxLimit = m_upperLimit[limit_index];
|
||||
|
||||
//handle the limits
|
||||
if (minLimit < maxLimit)
|
||||
{
|
||||
{
|
||||
if (depth > maxLimit)
|
||||
{
|
||||
depth -= maxLimit;
|
||||
lo = btScalar(0.);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if (depth < minLimit)
|
||||
{
|
||||
depth -= minLimit;
|
||||
hi = btScalar(0.);
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
btScalar normalImpulse= m_limitSoftness*(m_restitution*depth/timeStep - m_damping*rel_vel) * jacDiagABInv;
|
||||
|
||||
|
||||
|
||||
|
||||
btScalar oldNormalImpulse = m_accumulatedImpulse[limit_index];
|
||||
btScalar sum = oldNormalImpulse + normalImpulse;
|
||||
m_accumulatedImpulse[limit_index] = sum > hi ? btScalar(0.) : sum < lo ? btScalar(0.) : sum;
|
||||
normalImpulse = m_accumulatedImpulse[limit_index] - oldNormalImpulse;
|
||||
|
||||
btVector3 impulse_vector = axis_normal_on_a * normalImpulse;
|
||||
body1.applyImpulse( impulse_vector, rel_pos1);
|
||||
body2.applyImpulse(-impulse_vector, rel_pos2);
|
||||
return normalImpulse;
|
||||
}
|
||||
|
||||
//////////////////////////// btTranslationalLimitMotor ////////////////////////////////////
|
||||
|
||||
|
||||
btGeneric6DofConstraint::btGeneric6DofConstraint()
|
||||
:btTypedConstraint(D6_CONSTRAINT_TYPE),
|
||||
m_useLinearReferenceFrameA(true)
|
||||
{
|
||||
}
|
||||
|
||||
btGeneric6DofConstraint::btGeneric6DofConstraint(btRigidBody& rbA, btRigidBody& rbB, const btTransform& frameInA, const btTransform& frameInB, bool useLinearReferenceFrameA)
|
||||
: btTypedConstraint(D6_CONSTRAINT_TYPE, rbA, rbB)
|
||||
, m_frameInA(frameInA)
|
||||
, m_frameInB(frameInB),
|
||||
m_useLinearReferenceFrameA(useLinearReferenceFrameA)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void btGeneric6DofConstraint::calculateAngleInfo()
|
||||
{
|
||||
btMatrix3x3 relative_frame = m_calculatedTransformA.getBasis().inverse()*m_calculatedTransformB.getBasis();
|
||||
|
||||
matrixToEulerXYZ(relative_frame,m_calculatedAxisAngleDiff);
|
||||
|
||||
|
||||
|
||||
// in euler angle mode we do not actually constrain the angular velocity
|
||||
// along the axes axis[0] and axis[2] (although we do use axis[1]) :
|
||||
//
|
||||
// to get constrain w2-w1 along ...not
|
||||
// ------ --------------------- ------
|
||||
// d(angle[0])/dt = 0 ax[1] x ax[2] ax[0]
|
||||
// d(angle[1])/dt = 0 ax[1]
|
||||
// d(angle[2])/dt = 0 ax[0] x ax[1] ax[2]
|
||||
//
|
||||
// constraining w2-w1 along an axis 'a' means that a'*(w2-w1)=0.
|
||||
// to prove the result for angle[0], write the expression for angle[0] from
|
||||
// GetInfo1 then take the derivative. to prove this for angle[2] it is
|
||||
// easier to take the euler rate expression for d(angle[2])/dt with respect
|
||||
// to the components of w and set that to 0.
|
||||
|
||||
btVector3 axis0 = m_calculatedTransformB.getBasis().getColumn(0);
|
||||
btVector3 axis2 = m_calculatedTransformA.getBasis().getColumn(2);
|
||||
|
||||
m_calculatedAxis[1] = axis2.cross(axis0);
|
||||
m_calculatedAxis[0] = m_calculatedAxis[1].cross(axis2);
|
||||
m_calculatedAxis[2] = axis0.cross(m_calculatedAxis[1]);
|
||||
|
||||
|
||||
// if(m_debugDrawer)
|
||||
// {
|
||||
//
|
||||
// char buff[300];
|
||||
// sprintf(buff,"\n X: %.2f ; Y: %.2f ; Z: %.2f ",
|
||||
// m_calculatedAxisAngleDiff[0],
|
||||
// m_calculatedAxisAngleDiff[1],
|
||||
// m_calculatedAxisAngleDiff[2]);
|
||||
// m_debugDrawer->reportErrorWarning(buff);
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
void btGeneric6DofConstraint::calculateTransforms()
|
||||
{
|
||||
m_calculatedTransformA = m_rbA.getCenterOfMassTransform() * m_frameInA;
|
||||
m_calculatedTransformB = m_rbB.getCenterOfMassTransform() * m_frameInB;
|
||||
|
||||
calculateAngleInfo();
|
||||
}
|
||||
|
||||
|
||||
void btGeneric6DofConstraint::buildLinearJacobian(
|
||||
btJacobianEntry & jacLinear,const btVector3 & normalWorld,
|
||||
const btVector3 & pivotAInW,const btVector3 & pivotBInW)
|
||||
{
|
||||
new (&jacLinear) btJacobianEntry(
|
||||
m_rbA.getCenterOfMassTransform().getBasis().transpose(),
|
||||
m_rbB.getCenterOfMassTransform().getBasis().transpose(),
|
||||
pivotAInW - m_rbA.getCenterOfMassPosition(),
|
||||
pivotBInW - m_rbB.getCenterOfMassPosition(),
|
||||
normalWorld,
|
||||
m_rbA.getInvInertiaDiagLocal(),
|
||||
m_rbA.getInvMass(),
|
||||
m_rbB.getInvInertiaDiagLocal(),
|
||||
m_rbB.getInvMass());
|
||||
|
||||
}
|
||||
|
||||
void btGeneric6DofConstraint::buildAngularJacobian(
|
||||
btJacobianEntry & jacAngular,const btVector3 & jointAxisW)
|
||||
{
|
||||
new (&jacAngular) btJacobianEntry(jointAxisW,
|
||||
m_rbA.getCenterOfMassTransform().getBasis().transpose(),
|
||||
m_rbB.getCenterOfMassTransform().getBasis().transpose(),
|
||||
m_rbA.getInvInertiaDiagLocal(),
|
||||
m_rbB.getInvInertiaDiagLocal());
|
||||
|
||||
}
|
||||
|
||||
bool btGeneric6DofConstraint::testAngularLimitMotor(int axis_index)
|
||||
{
|
||||
btScalar angle = m_calculatedAxisAngleDiff[axis_index];
|
||||
|
||||
//test limits
|
||||
m_angularLimits[axis_index].testLimitValue(angle);
|
||||
return m_angularLimits[axis_index].needApplyTorques();
|
||||
}
|
||||
|
||||
void btGeneric6DofConstraint::buildJacobian()
|
||||
{
|
||||
//calculates transform
|
||||
calculateTransforms();
|
||||
|
||||
const btVector3& pivotAInW = m_calculatedTransformA.getOrigin();
|
||||
const btVector3& pivotBInW = m_calculatedTransformB.getOrigin();
|
||||
|
||||
|
||||
btVector3 rel_pos1 = pivotAInW - m_rbA.getCenterOfMassPosition();
|
||||
btVector3 rel_pos2 = pivotBInW - m_rbB.getCenterOfMassPosition();
|
||||
|
||||
btVector3 normalWorld;
|
||||
int i;
|
||||
//linear part
|
||||
for (i=0;i<3;i++)
|
||||
{
|
||||
if (m_linearLimits.isLimited(i))
|
||||
{
|
||||
if (m_useLinearReferenceFrameA)
|
||||
normalWorld = m_calculatedTransformA.getBasis().getColumn(i);
|
||||
else
|
||||
normalWorld = m_calculatedTransformB.getBasis().getColumn(i);
|
||||
|
||||
buildLinearJacobian(
|
||||
m_jacLinear[i],normalWorld ,
|
||||
pivotAInW,pivotBInW);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// angular part
|
||||
for (i=0;i<3;i++)
|
||||
{
|
||||
//calculates error angle
|
||||
if (testAngularLimitMotor(i))
|
||||
{
|
||||
normalWorld = this->getAxis(i);
|
||||
// Create angular atom
|
||||
buildAngularJacobian(m_jacAng[i],normalWorld);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
void btGeneric6DofConstraint::solveConstraint(btScalar timeStep)
|
||||
{
|
||||
m_timeStep = timeStep;
|
||||
|
||||
//calculateTransforms();
|
||||
|
||||
int i;
|
||||
|
||||
// linear
|
||||
|
||||
btVector3 pointInA = m_calculatedTransformA.getOrigin();
|
||||
btVector3 pointInB = m_calculatedTransformB.getOrigin();
|
||||
|
||||
btScalar jacDiagABInv;
|
||||
btVector3 linear_axis;
|
||||
for (i=0;i<3;i++)
|
||||
{
|
||||
if (m_linearLimits.isLimited(i))
|
||||
{
|
||||
jacDiagABInv = btScalar(1.) / m_jacLinear[i].getDiagonal();
|
||||
|
||||
if (m_useLinearReferenceFrameA)
|
||||
linear_axis = m_calculatedTransformA.getBasis().getColumn(i);
|
||||
else
|
||||
linear_axis = m_calculatedTransformB.getBasis().getColumn(i);
|
||||
|
||||
m_linearLimits.solveLinearAxis(
|
||||
m_timeStep,
|
||||
jacDiagABInv,
|
||||
m_rbA,pointInA,
|
||||
m_rbB,pointInB,
|
||||
i,linear_axis);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// angular
|
||||
btVector3 angular_axis;
|
||||
btScalar angularJacDiagABInv;
|
||||
for (i=0;i<3;i++)
|
||||
{
|
||||
if (m_angularLimits[i].needApplyTorques())
|
||||
{
|
||||
|
||||
// get axis
|
||||
angular_axis = getAxis(i);
|
||||
|
||||
angularJacDiagABInv = btScalar(1.) / m_jacAng[i].getDiagonal();
|
||||
|
||||
m_angularLimits[i].solveAngularLimits(m_timeStep,angular_axis,angularJacDiagABInv, &m_rbA,&m_rbB);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void btGeneric6DofConstraint::updateRHS(btScalar timeStep)
|
||||
{
|
||||
(void)timeStep;
|
||||
(void)timeStep;
|
||||
|
||||
}
|
||||
|
||||
btScalar btGeneric6DofConstraint::computeAngle(int axis) const
|
||||
{
|
||||
btScalar angle = btScalar(0.f);
|
||||
btVector3 btGeneric6DofConstraint::getAxis(int axis_index) const
|
||||
{
|
||||
return m_calculatedAxis[axis_index];
|
||||
}
|
||||
|
||||
switch (axis)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
btVector3 v1 = m_rbA.getCenterOfMassTransform().getBasis() * m_frameInA.getBasis().getColumn(1);
|
||||
btVector3 v2 = m_rbB.getCenterOfMassTransform().getBasis() * m_frameInB.getBasis().getColumn(1);
|
||||
btVector3 w2 = m_rbB.getCenterOfMassTransform().getBasis() * m_frameInB.getBasis().getColumn(2);
|
||||
btScalar btGeneric6DofConstraint::getAngle(int axis_index) const
|
||||
{
|
||||
return m_calculatedAxisAngleDiff[axis_index];
|
||||
}
|
||||
|
||||
btScalar s = v1.dot(w2);
|
||||
btScalar c = v1.dot(v2);
|
||||
|
||||
angle = btAtan2( s, c );
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
{
|
||||
btVector3 w1 = m_rbA.getCenterOfMassTransform().getBasis() * m_frameInA.getBasis().getColumn(2);
|
||||
btVector3 w2 = m_rbB.getCenterOfMassTransform().getBasis() * m_frameInB.getBasis().getColumn(2);
|
||||
btVector3 u2 = m_rbB.getCenterOfMassTransform().getBasis() * m_frameInB.getBasis().getColumn(0);
|
||||
|
||||
btScalar s = w1.dot(u2);
|
||||
btScalar c = w1.dot(w2);
|
||||
|
||||
angle = btAtan2( s, c );
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
{
|
||||
btVector3 u1 = m_rbA.getCenterOfMassTransform().getBasis() * m_frameInA.getBasis().getColumn(0);
|
||||
btVector3 u2 = m_rbB.getCenterOfMassTransform().getBasis() * m_frameInB.getBasis().getColumn(0);
|
||||
btVector3 v2 = m_rbB.getCenterOfMassTransform().getBasis() * m_frameInB.getBasis().getColumn(1);
|
||||
|
||||
btScalar s = u1.dot(v2);
|
||||
btScalar c = u1.dot(u2);
|
||||
|
||||
angle = btAtan2( s, c );
|
||||
}
|
||||
break;
|
||||
default:
|
||||
btAssert ( 0 ) ;
|
||||
|
||||
break ;
|
||||
}
|
||||
|
||||
return angle;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,14 +4,21 @@ Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
|
||||
|
||||
This software is provided 'as-is', without any express or implied warranty.
|
||||
In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it freely,
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it freely,
|
||||
subject to the following restrictions:
|
||||
|
||||
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.
|
||||
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
/*
|
||||
2007-09-09
|
||||
btGeneric6DofConstraint Refactored by Francisco Le<4C>n
|
||||
email: projectileman@yahoo.com
|
||||
http://gimpact.sf.net
|
||||
*/
|
||||
|
||||
|
||||
#ifndef GENERIC_6DOF_CONSTRAINT_H
|
||||
#define GENERIC_6DOF_CONSTRAINT_H
|
||||
@@ -23,97 +30,403 @@ subject to the following restrictions:
|
||||
class btRigidBody;
|
||||
|
||||
|
||||
//! Rotation Limit structure for generic joints
|
||||
class btRotationalLimitMotor
|
||||
{
|
||||
public:
|
||||
//! limit_parameters
|
||||
//!@{
|
||||
btScalar m_loLimit;//!< joint limit
|
||||
btScalar m_hiLimit;//!< joint limit
|
||||
btScalar m_targetVelocity;//!< target motor velocity
|
||||
btScalar m_maxMotorForce;//!< max force on motor
|
||||
btScalar m_maxLimitForce;//!< max force on limit
|
||||
btScalar m_damping;//!< Damping.
|
||||
btScalar m_limitSoftness;//! Relaxation factor
|
||||
btScalar m_ERP;//!< Error tolerance factor when joint is at limit
|
||||
btScalar m_bounce;//!< restitution factor
|
||||
bool m_enableMotor;
|
||||
|
||||
//!@}
|
||||
|
||||
//! temp_variables
|
||||
//!@{
|
||||
btScalar m_currentLimitError;//! How much is violated this limit
|
||||
int m_currentLimit;//!< 0=free, 1=at lo limit, 2=at hi limit
|
||||
btScalar m_accumulatedImpulse;
|
||||
//!@}
|
||||
|
||||
btRotationalLimitMotor()
|
||||
{
|
||||
m_accumulatedImpulse = 0.f;
|
||||
m_targetVelocity = 0;
|
||||
m_maxMotorForce = 0.1f;
|
||||
m_maxLimitForce = 300.0f;
|
||||
m_loLimit = -SIMD_INFINITY;
|
||||
m_hiLimit = SIMD_INFINITY;
|
||||
m_ERP = 0.5f;
|
||||
m_bounce = 0.0f;
|
||||
m_damping = 1.0f;
|
||||
m_limitSoftness = 0.5f;
|
||||
m_currentLimit = 0;
|
||||
m_currentLimitError = 0;
|
||||
m_enableMotor = false;
|
||||
}
|
||||
|
||||
btRotationalLimitMotor(const btRotationalLimitMotor & limot)
|
||||
{
|
||||
m_targetVelocity = limot.m_targetVelocity;
|
||||
m_maxMotorForce = limot.m_maxMotorForce;
|
||||
m_limitSoftness = limot.m_limitSoftness;
|
||||
m_loLimit = limot.m_loLimit;
|
||||
m_hiLimit = limot.m_hiLimit;
|
||||
m_ERP = limot.m_ERP;
|
||||
m_bounce = limot.m_bounce;
|
||||
m_currentLimit = limot.m_currentLimit;
|
||||
m_currentLimitError = limot.m_currentLimitError;
|
||||
m_enableMotor = limot.m_enableMotor;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//! Is limited
|
||||
bool isLimited()
|
||||
{
|
||||
if(m_loLimit>=m_hiLimit) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
//! Need apply correction
|
||||
bool needApplyTorques()
|
||||
{
|
||||
if(m_currentLimit == 0 && m_enableMotor == false) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
//! calculates error
|
||||
/*!
|
||||
calculates m_currentLimit and m_currentLimitError.
|
||||
*/
|
||||
int testLimitValue(btScalar test_value);
|
||||
|
||||
//! apply the correction impulses for two bodies
|
||||
btScalar solveAngularLimits(btScalar timeStep,btVector3 axis, btScalar jacDiagABInv,btRigidBody * body0, btRigidBody * body1);
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
class btTranslationalLimitMotor
|
||||
{
|
||||
public:
|
||||
btVector3 m_lowerLimit;//!< the constraint lower limits
|
||||
btVector3 m_upperLimit;//!< the constraint upper limits
|
||||
btVector3 m_accumulatedImpulse;
|
||||
//! Linear_Limit_parameters
|
||||
//!@{
|
||||
btScalar m_limitSoftness;//!< Softness for linear limit
|
||||
btScalar m_damping;//!< Damping for linear limit
|
||||
btScalar m_restitution;//! Bounce parameter for linear limit
|
||||
//!@}
|
||||
|
||||
btTranslationalLimitMotor()
|
||||
{
|
||||
m_lowerLimit.setValue(0.f,0.f,0.f);
|
||||
m_upperLimit.setValue(0.f,0.f,0.f);
|
||||
m_accumulatedImpulse.setValue(0.f,0.f,0.f);
|
||||
|
||||
m_limitSoftness = 0.7f;
|
||||
m_damping = btScalar(1.0f);
|
||||
m_restitution = btScalar(0.5f);
|
||||
}
|
||||
|
||||
btTranslationalLimitMotor(const btTranslationalLimitMotor & other )
|
||||
{
|
||||
m_lowerLimit = other.m_lowerLimit;
|
||||
m_upperLimit = other.m_upperLimit;
|
||||
m_accumulatedImpulse = other.m_accumulatedImpulse;
|
||||
|
||||
m_limitSoftness = other.m_limitSoftness ;
|
||||
m_damping = other.m_damping;
|
||||
m_restitution = other.m_restitution;
|
||||
}
|
||||
|
||||
//! Test limit
|
||||
/*!
|
||||
- free means upper < lower,
|
||||
- locked means upper == lower
|
||||
- limited means upper > lower
|
||||
- limitIndex: first 3 are linear, next 3 are angular
|
||||
*/
|
||||
inline bool isLimited(int limitIndex)
|
||||
{
|
||||
return (m_upperLimit[limitIndex] >= m_lowerLimit[limitIndex]);
|
||||
}
|
||||
|
||||
|
||||
btScalar solveLinearAxis(
|
||||
btScalar timeStep,
|
||||
btScalar jacDiagABInv,
|
||||
btRigidBody& body1,const btVector3 &pointInA,
|
||||
btRigidBody& body2,const btVector3 &pointInB,
|
||||
int limit_index,
|
||||
const btVector3 & axis_normal_on_a);
|
||||
|
||||
|
||||
};
|
||||
|
||||
/// btGeneric6DofConstraint between two rigidbodies each with a pivotpoint that descibes the axis location in local space
|
||||
/// btGeneric6DofConstraint can leave any of the 6 degree of freedom 'free' or 'locked'
|
||||
/// Work in progress (is still a Hinge actually)
|
||||
/*!
|
||||
btGeneric6DofConstraint can leave any of the 6 degree of freedom 'free' or 'locked'.
|
||||
currently this limit supports rotational motors<br>
|
||||
<ul>
|
||||
<li> For Linear limits, use btGeneric6DofConstraint.setLinearUpperLimit, btGeneric6DofConstraint.setLinearLowerLimit. You can set the parameters with the btTranslationalLimitMotor structure accsesible through the btGeneric6DofConstraint.getTranslationalLimitMotor method.
|
||||
At this moment translational motors are not supported. May be in the future. </li>
|
||||
|
||||
<li> For Angular limits, use the btRotationalLimitMotor structure for configuring the limit.
|
||||
This is accessible through btGeneric6DofConstraint.getLimitMotor method,
|
||||
This brings support for limit parameters and motors. </li>
|
||||
|
||||
<li> Angulars limits have these possible ranges:
|
||||
<table border=1 >
|
||||
<tr
|
||||
|
||||
<td><b>AXIS</b></td>
|
||||
<td><b>MIN ANGLE</b></td>
|
||||
<td><b>MAX ANGLE</b></td>
|
||||
<td>X</td>
|
||||
<td>-PI</td>
|
||||
<td>PI</td>
|
||||
<td>Y</td>
|
||||
<td>-PI/2</td>
|
||||
<td>PI/2</td>
|
||||
<td>Z</td>
|
||||
<td>-PI/2</td>
|
||||
<td>PI/2</td>
|
||||
</tr>
|
||||
</table>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
*/
|
||||
class btGeneric6DofConstraint : public btTypedConstraint
|
||||
{
|
||||
btJacobianEntry m_jacLinear[3]; // 3 orthogonal linear constraints
|
||||
btJacobianEntry m_jacAng[3]; // 3 orthogonal angular constraints
|
||||
protected:
|
||||
|
||||
btTransform m_frameInA; // the constraint space w.r.t body A
|
||||
btTransform m_frameInB; // the constraint space w.r.t body B
|
||||
//! relative_frames
|
||||
//!@{
|
||||
btTransform m_frameInA;//!< the constraint space w.r.t body A
|
||||
btTransform m_frameInB;//!< the constraint space w.r.t body B
|
||||
//!@}
|
||||
|
||||
//! Jacobians
|
||||
//!@{
|
||||
btJacobianEntry m_jacLinear[3];//!< 3 orthogonal linear constraints
|
||||
btJacobianEntry m_jacAng[3];//!< 3 orthogonal angular constraints
|
||||
//!@}
|
||||
|
||||
//! Linear_Limit_parameters
|
||||
//!@{
|
||||
btTranslationalLimitMotor m_linearLimits;
|
||||
//!@}
|
||||
|
||||
|
||||
//! hinge_parameters
|
||||
//!@{
|
||||
btRotationalLimitMotor m_angularLimits[3];
|
||||
//!@}
|
||||
|
||||
|
||||
protected:
|
||||
//! temporal variables
|
||||
//!@{
|
||||
btScalar m_timeStep;
|
||||
btTransform m_calculatedTransformA;
|
||||
btTransform m_calculatedTransformB;
|
||||
btVector3 m_calculatedAxisAngleDiff;
|
||||
btVector3 m_calculatedAxis[3];
|
||||
|
||||
bool m_useLinearReferenceFrameA;
|
||||
|
||||
//!@}
|
||||
|
||||
btGeneric6DofConstraint& operator=(btGeneric6DofConstraint& other)
|
||||
{
|
||||
btAssert(0);
|
||||
(void) other;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void buildLinearJacobian(
|
||||
btJacobianEntry & jacLinear,const btVector3 & normalWorld,
|
||||
const btVector3 & pivotAInW,const btVector3 & pivotBInW);
|
||||
|
||||
void buildAngularJacobian(btJacobianEntry & jacAngular,const btVector3 & jointAxisW);
|
||||
|
||||
|
||||
//! calcs the euler angles between the two bodies.
|
||||
void calculateAngleInfo();
|
||||
|
||||
btScalar m_lowerLimit[6]; // the constraint lower limits
|
||||
btScalar m_upperLimit[6]; // the constraint upper limits
|
||||
|
||||
btScalar m_accumulatedImpulse[6];
|
||||
|
||||
btGeneric6DofConstraint& operator=(btGeneric6DofConstraint& other)
|
||||
{
|
||||
btAssert(0);
|
||||
(void) other;
|
||||
return *this;
|
||||
}
|
||||
|
||||
public:
|
||||
btGeneric6DofConstraint(btRigidBody& rbA, btRigidBody& rbB, const btTransform& frameInA, const btTransform& frameInB );
|
||||
btGeneric6DofConstraint(btRigidBody& rbA, btRigidBody& rbB, const btTransform& frameInA, const btTransform& frameInB ,bool useLinearReferenceFrameA);
|
||||
|
||||
btGeneric6DofConstraint();
|
||||
btGeneric6DofConstraint();
|
||||
|
||||
|
||||
virtual void buildJacobian();
|
||||
//! Calcs global transform of the offsets
|
||||
/*!
|
||||
Calcs the global transform for the joint offset for body A an B, and also calcs the agle differences between the bodies.
|
||||
\sa btGeneric6DofConstraint.getCalculatedTransformA , btGeneric6DofConstraint.getCalculatedTransformB, btGeneric6DofConstraint.calculateAngleInfo
|
||||
*/
|
||||
void calculateTransforms();
|
||||
|
||||
virtual void solveConstraint(btScalar timeStep);
|
||||
//! Gets the global transform of the offset for body A
|
||||
/*!
|
||||
\sa btGeneric6DofConstraint.getFrameOffsetA, btGeneric6DofConstraint.getFrameOffsetB, btGeneric6DofConstraint.calculateAngleInfo.
|
||||
*/
|
||||
const btTransform & getCalculatedTransformA() const
|
||||
{
|
||||
return m_calculatedTransformA;
|
||||
}
|
||||
|
||||
void updateRHS(btScalar timeStep);
|
||||
//! Gets the global transform of the offset for body B
|
||||
/*!
|
||||
\sa btGeneric6DofConstraint.getFrameOffsetA, btGeneric6DofConstraint.getFrameOffsetB, btGeneric6DofConstraint.calculateAngleInfo.
|
||||
*/
|
||||
const btTransform & getCalculatedTransformB() const
|
||||
{
|
||||
return m_calculatedTransformB;
|
||||
}
|
||||
|
||||
btScalar computeAngle(int axis) const;
|
||||
const btTransform & getFrameOffsetA() const
|
||||
{
|
||||
return m_frameInA;
|
||||
}
|
||||
|
||||
void setLinearLowerLimit(const btVector3& linearLower)
|
||||
{
|
||||
m_lowerLimit[0] = linearLower.getX();
|
||||
m_lowerLimit[1] = linearLower.getY();
|
||||
m_lowerLimit[2] = linearLower.getZ();
|
||||
}
|
||||
const btTransform & getFrameOffsetB() const
|
||||
{
|
||||
return m_frameInB;
|
||||
}
|
||||
|
||||
void setLinearUpperLimit(const btVector3& linearUpper)
|
||||
{
|
||||
m_upperLimit[0] = linearUpper.getX();
|
||||
m_upperLimit[1] = linearUpper.getY();
|
||||
m_upperLimit[2] = linearUpper.getZ();
|
||||
}
|
||||
|
||||
void setAngularLowerLimit(const btVector3& angularLower)
|
||||
{
|
||||
m_lowerLimit[3] = angularLower.getX();
|
||||
m_lowerLimit[4] = angularLower.getY();
|
||||
m_lowerLimit[5] = angularLower.getZ();
|
||||
}
|
||||
btTransform & getFrameOffsetA()
|
||||
{
|
||||
return m_frameInA;
|
||||
}
|
||||
|
||||
void setAngularUpperLimit(const btVector3& angularUpper)
|
||||
{
|
||||
m_upperLimit[3] = angularUpper.getX();
|
||||
m_upperLimit[4] = angularUpper.getY();
|
||||
m_upperLimit[5] = angularUpper.getZ();
|
||||
}
|
||||
btTransform & getFrameOffsetB()
|
||||
{
|
||||
return m_frameInB;
|
||||
}
|
||||
|
||||
//first 3 are linear, next 3 are angular
|
||||
void SetLimit(int axis, btScalar lo, btScalar hi)
|
||||
{
|
||||
m_lowerLimit[axis] = lo;
|
||||
m_upperLimit[axis] = hi;
|
||||
}
|
||||
|
||||
//free means upper < lower,
|
||||
//locked means upper == lower
|
||||
//limited means upper > lower
|
||||
//limitIndex: first 3 are linear, next 3 are angular
|
||||
bool isLimited(int limitIndex)
|
||||
{
|
||||
return (m_upperLimit[limitIndex] >= m_lowerLimit[limitIndex]);
|
||||
}
|
||||
//! performs Jacobian calculation, and also calculates angle differences and axis
|
||||
virtual void buildJacobian();
|
||||
|
||||
virtual void solveConstraint(btScalar timeStep);
|
||||
|
||||
void updateRHS(btScalar timeStep);
|
||||
|
||||
//! Get the rotation axis in global coordinates
|
||||
/*!
|
||||
\pre btGeneric6DofConstraint.buildJacobian must be called previously.
|
||||
*/
|
||||
btVector3 getAxis(int axis_index) const;
|
||||
|
||||
//! Get the relative Euler angle
|
||||
/*!
|
||||
\pre btGeneric6DofConstraint.buildJacobian must be called previously.
|
||||
*/
|
||||
btScalar getAngle(int axis_index) const;
|
||||
|
||||
//! Test angular limit.
|
||||
/*!
|
||||
Calculates angular correction and returns true if limit needs to be corrected.
|
||||
\pre btGeneric6DofConstraint.buildJacobian must be called previously.
|
||||
*/
|
||||
bool testAngularLimitMotor(int axis_index);
|
||||
|
||||
void setLinearLowerLimit(const btVector3& linearLower)
|
||||
{
|
||||
m_linearLimits.m_lowerLimit = linearLower;
|
||||
}
|
||||
|
||||
void setLinearUpperLimit(const btVector3& linearUpper)
|
||||
{
|
||||
m_linearLimits.m_upperLimit = linearUpper;
|
||||
}
|
||||
|
||||
void setAngularLowerLimit(const btVector3& angularLower)
|
||||
{
|
||||
m_angularLimits[0].m_loLimit = angularLower.getX();
|
||||
m_angularLimits[1].m_loLimit = angularLower.getY();
|
||||
m_angularLimits[2].m_loLimit = angularLower.getZ();
|
||||
}
|
||||
|
||||
void setAngularUpperLimit(const btVector3& angularUpper)
|
||||
{
|
||||
m_angularLimits[0].m_hiLimit = angularUpper.getX();
|
||||
m_angularLimits[1].m_hiLimit = angularUpper.getY();
|
||||
m_angularLimits[2].m_hiLimit = angularUpper.getZ();
|
||||
}
|
||||
|
||||
//! Retrieves the angular limit informacion
|
||||
btRotationalLimitMotor * getRotationalLimitMotor(int index)
|
||||
{
|
||||
return &m_angularLimits[index];
|
||||
}
|
||||
|
||||
//! Retrieves the limit informacion
|
||||
btTranslationalLimitMotor * getTranslationalLimitMotor()
|
||||
{
|
||||
return &m_linearLimits;
|
||||
}
|
||||
|
||||
//first 3 are linear, next 3 are angular
|
||||
void setLimit(int axis, btScalar lo, btScalar hi)
|
||||
{
|
||||
if(axis<3)
|
||||
{
|
||||
m_linearLimits.m_lowerLimit[axis] = lo;
|
||||
m_linearLimits.m_upperLimit[axis] = hi;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_angularLimits[axis-3].m_loLimit = lo;
|
||||
m_angularLimits[axis-3].m_hiLimit = hi;
|
||||
}
|
||||
}
|
||||
|
||||
//! Test limit
|
||||
/*!
|
||||
- free means upper < lower,
|
||||
- locked means upper == lower
|
||||
- limited means upper > lower
|
||||
- limitIndex: first 3 are linear, next 3 are angular
|
||||
*/
|
||||
bool isLimited(int limitIndex)
|
||||
{
|
||||
if(limitIndex<3)
|
||||
{
|
||||
return m_linearLimits.isLimited(limitIndex);
|
||||
|
||||
}
|
||||
return m_angularLimits[limitIndex-3].isLimited();
|
||||
}
|
||||
|
||||
const btRigidBody& getRigidBodyA() const
|
||||
{
|
||||
return m_rbA;
|
||||
}
|
||||
const btRigidBody& getRigidBodyB() const
|
||||
{
|
||||
return m_rbB;
|
||||
}
|
||||
|
||||
const btRigidBody& getRigidBodyA() const
|
||||
{
|
||||
return m_rbA;
|
||||
}
|
||||
const btRigidBody& getRigidBodyB() const
|
||||
{
|
||||
return m_rbB;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user