mirror of
https://github.com/bulletphysics/bullet3
synced 2025-01-08 08:30:16 +00:00
improve rolling friction using anisotropic direction, to avoid resting in an instable position
(for implicit capsule, cylinder and cone shape) See Bullet/Demos/RollingFrictionDemo for an example
This commit is contained in:
parent
26c713423f
commit
22fb7d5c1e
@ -281,8 +281,9 @@ void CcdPhysicsDemo::initPhysics()
|
||||
float mass = 1.f;
|
||||
|
||||
btRigidBody* body = localCreateRigidBody(mass,trans,shape);
|
||||
body->setAnisotropicFriction(shape->getAnisotropicRollingFrictionDirection(),btCollisionObject::CF_ANISOTROPIC_ROLLING_FRICTION);
|
||||
|
||||
body->setRollingFriction(0.1);
|
||||
body->setRollingFriction(.3);
|
||||
///when using m_ccdMode
|
||||
if (m_ccdMode==USE_CCD)
|
||||
{
|
||||
|
@ -171,9 +171,21 @@ void RollingFrictionDemo::initPhysics()
|
||||
{
|
||||
//create a few dynamic rigidbodies
|
||||
// Re-using the same collision is better for memory usage and performance
|
||||
|
||||
btCollisionShape* colShape = new btSphereShape(btScalar(1.));
|
||||
m_collisionShapes.push_back(colShape);
|
||||
#define NUM_SHAPES 10
|
||||
btCollisionShape* colShapes[NUM_SHAPES] = {
|
||||
new btSphereShape(btScalar(1.)),
|
||||
new btCapsuleShape(0.5,1),
|
||||
new btCapsuleShapeX(0.5,1),
|
||||
new btCapsuleShapeZ(0.5,1),
|
||||
new btConeShape(0.5,1),
|
||||
new btConeShapeX(0.5,1),
|
||||
new btConeShapeZ(0.5,1),
|
||||
new btCylinderShape(btVector3(0.5,1,0.1)),
|
||||
new btCylinderShapeX(btVector3(1,0.5,0.1)),
|
||||
new btCylinderShapeZ(btVector3(0.5,0.5,1)),
|
||||
};
|
||||
for (int i=0;i<NUM_SHAPES;i++)
|
||||
m_collisionShapes.push_back(colShapes[i]);
|
||||
|
||||
/// Create Dynamic Objects
|
||||
btTransform startTransform;
|
||||
@ -182,36 +194,44 @@ void RollingFrictionDemo::initPhysics()
|
||||
btScalar mass(1.f);
|
||||
|
||||
//rigidbody is dynamic if and only if mass is non zero, otherwise static
|
||||
bool isDynamic = (mass != 0.f);
|
||||
|
||||
btVector3 localInertia(0,0,0);
|
||||
if (isDynamic)
|
||||
colShape->calculateLocalInertia(mass,localInertia);
|
||||
|
||||
|
||||
float start_x = START_POS_X - ARRAY_SIZE_X/2;
|
||||
float start_y = START_POS_Y;
|
||||
float start_z = START_POS_Z - ARRAY_SIZE_Z/2;
|
||||
|
||||
for (int k=0;k<ARRAY_SIZE_Y;k++)
|
||||
{
|
||||
for (int i=0;i<ARRAY_SIZE_X;i++)
|
||||
int shapeIndex = 0;
|
||||
for (int k=0;k<ARRAY_SIZE_Y;k++)
|
||||
{
|
||||
for(int j = 0;j<ARRAY_SIZE_Z;j++)
|
||||
for (int i=0;i<ARRAY_SIZE_X;i++)
|
||||
{
|
||||
startTransform.setOrigin(SCALING*btVector3(
|
||||
btScalar(2.0*i + start_x),
|
||||
btScalar(20+2.0*k + start_y),
|
||||
btScalar(2.0*j + start_z)));
|
||||
for(int j = 0;j<ARRAY_SIZE_Z;j++)
|
||||
{
|
||||
startTransform.setOrigin(SCALING*btVector3(
|
||||
btScalar(2.0*i + start_x),
|
||||
btScalar(20+2.0*k + start_y),
|
||||
btScalar(2.0*j + start_z)));
|
||||
|
||||
|
||||
//using motionstate is recommended, it provides interpolation capabilities, and only synchronizes 'active' objects
|
||||
btDefaultMotionState* myMotionState = new btDefaultMotionState(startTransform);
|
||||
btRigidBody::btRigidBodyConstructionInfo rbInfo(mass,myMotionState,colShape,localInertia);
|
||||
btRigidBody* body = new btRigidBody(rbInfo);
|
||||
body->setFriction(1.f);
|
||||
body->setRollingFriction(.3);
|
||||
|
||||
m_dynamicsWorld->addRigidBody(body);
|
||||
shapeIndex++;
|
||||
btCollisionShape* colShape = colShapes[shapeIndex%NUM_SHAPES];
|
||||
bool isDynamic = (mass != 0.f);
|
||||
btVector3 localInertia(0,0,0);
|
||||
|
||||
if (isDynamic)
|
||||
colShape->calculateLocalInertia(mass,localInertia);
|
||||
|
||||
//using motionstate is recommended, it provides interpolation capabilities, and only synchronizes 'active' objects
|
||||
btDefaultMotionState* myMotionState = new btDefaultMotionState(startTransform);
|
||||
btRigidBody::btRigidBodyConstructionInfo rbInfo(mass,myMotionState,colShape,localInertia);
|
||||
btRigidBody* body = new btRigidBody(rbInfo);
|
||||
body->setFriction(1.f);
|
||||
body->setRollingFriction(.3);
|
||||
body->setAnisotropicFriction(colShape->getAnisotropicRollingFrictionDirection(),btCollisionObject::CF_ANISOTROPIC_ROLLING_FRICTION);
|
||||
|
||||
|
||||
m_dynamicsWorld->addRigidBody(body);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -138,6 +138,13 @@ public:
|
||||
CO_USER_TYPE=32
|
||||
};
|
||||
|
||||
enum AnisotropicFrictionFlags
|
||||
{
|
||||
CF_ANISOTROPIC_FRICTION_DISABLED=0,
|
||||
CF_ANISOTROPIC_FRICTION = 1,
|
||||
CF_ANISOTROPIC_ROLLING_FRICTION = 2
|
||||
};
|
||||
|
||||
SIMD_FORCE_INLINE bool mergesSimulationIslands() const
|
||||
{
|
||||
///static objects, kinematic and object without contact response don't merge islands
|
||||
@ -148,14 +155,15 @@ public:
|
||||
{
|
||||
return m_anisotropicFriction;
|
||||
}
|
||||
void setAnisotropicFriction(const btVector3& anisotropicFriction)
|
||||
void setAnisotropicFriction(const btVector3& anisotropicFriction, int frictionMode = CF_ANISOTROPIC_FRICTION)
|
||||
{
|
||||
m_anisotropicFriction = anisotropicFriction;
|
||||
m_hasAnisotropicFriction = (anisotropicFriction[0]!=1.f) || (anisotropicFriction[1]!=1.f) || (anisotropicFriction[2]!=1.f);
|
||||
bool isUnity = (anisotropicFriction[0]!=1.f) || (anisotropicFriction[1]!=1.f) || (anisotropicFriction[2]!=1.f);
|
||||
m_hasAnisotropicFriction = isUnity?frictionMode : 0;
|
||||
}
|
||||
bool hasAnisotropicFriction() const
|
||||
bool hasAnisotropicFriction(int frictionMode = CF_ANISOTROPIC_FRICTION) const
|
||||
{
|
||||
return m_hasAnisotropicFriction!=0;
|
||||
return (m_hasAnisotropicFriction&frictionMode)!=0;
|
||||
}
|
||||
|
||||
///the constraint solver can discard solving contacts, if the distance is above this threshold. 0 by default.
|
||||
|
@ -104,6 +104,14 @@ public:
|
||||
|
||||
}
|
||||
|
||||
virtual btVector3 getAnisotropicRollingFrictionDirection() const
|
||||
{
|
||||
btVector3 aniDir(0,0,0);
|
||||
aniDir[getUpAxis()]=1;
|
||||
return aniDir;
|
||||
}
|
||||
|
||||
|
||||
virtual int calculateSerializeBufferSize() const;
|
||||
|
||||
///fills the dataBuffer and returns the struct name (and 0 on failure)
|
||||
|
@ -109,6 +109,13 @@ public:
|
||||
|
||||
|
||||
int getShapeType() const { return m_shapeType; }
|
||||
|
||||
///the getAnisotropicRollingFrictionDirection can be used in combination with setAnisotropicFriction
|
||||
///See Bullet/Demos/RollingFrictionDemo for an example
|
||||
virtual btVector3 getAnisotropicRollingFrictionDirection() const
|
||||
{
|
||||
return btVector3(1,1,1);
|
||||
}
|
||||
virtual void setMargin(btScalar margin) = 0;
|
||||
virtual btScalar getMargin() const = 0;
|
||||
|
||||
|
@ -84,6 +84,11 @@ public:
|
||||
return m_coneIndices[1];
|
||||
}
|
||||
|
||||
virtual btVector3 getAnisotropicRollingFrictionDirection() const
|
||||
{
|
||||
return btVector3 (0,1,0);
|
||||
}
|
||||
|
||||
virtual void setLocalScaling(const btVector3& scaling);
|
||||
|
||||
};
|
||||
@ -93,6 +98,12 @@ class btConeShapeX : public btConeShape
|
||||
{
|
||||
public:
|
||||
btConeShapeX(btScalar radius,btScalar height);
|
||||
|
||||
virtual btVector3 getAnisotropicRollingFrictionDirection() const
|
||||
{
|
||||
return btVector3 (1,0,0);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
///btConeShapeZ implements a Cone shape, around the Z axis
|
||||
@ -100,6 +111,12 @@ class btConeShapeZ : public btConeShape
|
||||
{
|
||||
public:
|
||||
btConeShapeZ(btScalar radius,btScalar height);
|
||||
|
||||
virtual btVector3 getAnisotropicRollingFrictionDirection() const
|
||||
{
|
||||
return btVector3 (0,0,1);
|
||||
}
|
||||
|
||||
};
|
||||
#endif //BT_CONE_MINKOWSKI_H
|
||||
|
||||
|
@ -97,6 +97,13 @@ BT_DECLARE_ALIGNED_ALLOCATOR();
|
||||
return m_upAxis;
|
||||
}
|
||||
|
||||
virtual btVector3 getAnisotropicRollingFrictionDirection() const
|
||||
{
|
||||
btVector3 aniDir(0,0,0);
|
||||
aniDir[getUpAxis()]=1;
|
||||
return aniDir;
|
||||
}
|
||||
|
||||
virtual btScalar getRadius() const
|
||||
{
|
||||
return getHalfExtentsWithMargin().getX();
|
||||
|
@ -324,12 +324,12 @@ btScalar btSequentialImpulseConstraintSolver::restitutionCurve(btScalar rel_vel,
|
||||
|
||||
|
||||
|
||||
static void applyAnisotropicFriction(btCollisionObject* colObj,btVector3& frictionDirection);
|
||||
static void applyAnisotropicFriction(btCollisionObject* colObj,btVector3& frictionDirection)
|
||||
static void applyAnisotropicFriction(btCollisionObject* colObj,btVector3& frictionDirection, int frictionMode);
|
||||
static void applyAnisotropicFriction(btCollisionObject* colObj,btVector3& frictionDirection, int frictionMode)
|
||||
{
|
||||
|
||||
|
||||
if (colObj && colObj->hasAnisotropicFriction())
|
||||
if (colObj && colObj->hasAnisotropicFriction(frictionMode))
|
||||
{
|
||||
// transform to local coordinates
|
||||
btVector3 loc_lateral = frictionDirection * colObj->getWorldTransform().getBasis();
|
||||
@ -807,15 +807,24 @@ void btSequentialImpulseConstraintSolver::convertContact(btPersistentManifold* m
|
||||
if (relAngVel.length()>infoGlobal.m_singleAxisRollingFrictionThreshold)
|
||||
{
|
||||
relAngVel.normalize();
|
||||
addRollingFrictionConstraint(relAngVel,solverBodyIdA,solverBodyIdB,frictionIndex,cp,rel_pos1,rel_pos2,colObj0,colObj1, relaxation);
|
||||
applyAnisotropicFriction(colObj0,relAngVel,btCollisionObject::CF_ANISOTROPIC_ROLLING_FRICTION);
|
||||
applyAnisotropicFriction(colObj1,relAngVel,btCollisionObject::CF_ANISOTROPIC_ROLLING_FRICTION);
|
||||
if (relAngVel.length()>0.001)
|
||||
addRollingFrictionConstraint(relAngVel,solverBodyIdA,solverBodyIdB,frictionIndex,cp,rel_pos1,rel_pos2,colObj0,colObj1, relaxation);
|
||||
|
||||
} else
|
||||
{
|
||||
addRollingFrictionConstraint(cp.m_normalWorldOnB,solverBodyIdA,solverBodyIdB,frictionIndex,cp,rel_pos1,rel_pos2,colObj0,colObj1, relaxation);
|
||||
btVector3 axis0,axis1;
|
||||
btPlaneSpace1(cp.m_normalWorldOnB,axis0,axis1);
|
||||
addRollingFrictionConstraint(axis0,solverBodyIdA,solverBodyIdB,frictionIndex,cp,rel_pos1,rel_pos2,colObj0,colObj1, relaxation);
|
||||
addRollingFrictionConstraint(axis1,solverBodyIdA,solverBodyIdB,frictionIndex,cp,rel_pos1,rel_pos2,colObj0,colObj1, relaxation);
|
||||
applyAnisotropicFriction(colObj0,axis0,btCollisionObject::CF_ANISOTROPIC_ROLLING_FRICTION);
|
||||
applyAnisotropicFriction(colObj1,axis0,btCollisionObject::CF_ANISOTROPIC_ROLLING_FRICTION);
|
||||
applyAnisotropicFriction(colObj0,axis1,btCollisionObject::CF_ANISOTROPIC_ROLLING_FRICTION);
|
||||
applyAnisotropicFriction(colObj1,axis1,btCollisionObject::CF_ANISOTROPIC_ROLLING_FRICTION);
|
||||
if (axis0.length()>0.001)
|
||||
addRollingFrictionConstraint(axis0,solverBodyIdA,solverBodyIdB,frictionIndex,cp,rel_pos1,rel_pos2,colObj0,colObj1, relaxation);
|
||||
if (axis1.length()>0.001)
|
||||
addRollingFrictionConstraint(axis1,solverBodyIdA,solverBodyIdB,frictionIndex,cp,rel_pos1,rel_pos2,colObj0,colObj1, relaxation);
|
||||
|
||||
}
|
||||
}
|
||||
@ -834,14 +843,14 @@ void btSequentialImpulseConstraintSolver::convertContact(btPersistentManifold* m
|
||||
{
|
||||
cp.m_lateralFrictionDir2 = cp.m_lateralFrictionDir1.cross(cp.m_normalWorldOnB);
|
||||
cp.m_lateralFrictionDir2.normalize();//??
|
||||
applyAnisotropicFriction(colObj0,cp.m_lateralFrictionDir2);
|
||||
applyAnisotropicFriction(colObj1,cp.m_lateralFrictionDir2);
|
||||
applyAnisotropicFriction(colObj0,cp.m_lateralFrictionDir2,btCollisionObject::CF_ANISOTROPIC_FRICTION);
|
||||
applyAnisotropicFriction(colObj1,cp.m_lateralFrictionDir2,btCollisionObject::CF_ANISOTROPIC_FRICTION);
|
||||
addFrictionConstraint(cp.m_lateralFrictionDir2,solverBodyIdA,solverBodyIdB,frictionIndex,cp,rel_pos1,rel_pos2,colObj0,colObj1, relaxation);
|
||||
|
||||
}
|
||||
|
||||
applyAnisotropicFriction(colObj0,cp.m_lateralFrictionDir1);
|
||||
applyAnisotropicFriction(colObj1,cp.m_lateralFrictionDir1);
|
||||
applyAnisotropicFriction(colObj0,cp.m_lateralFrictionDir1,btCollisionObject::CF_ANISOTROPIC_FRICTION);
|
||||
applyAnisotropicFriction(colObj1,cp.m_lateralFrictionDir1,btCollisionObject::CF_ANISOTROPIC_FRICTION);
|
||||
addFrictionConstraint(cp.m_lateralFrictionDir1,solverBodyIdA,solverBodyIdB,frictionIndex,cp,rel_pos1,rel_pos2,colObj0,colObj1, relaxation);
|
||||
|
||||
|
||||
@ -853,13 +862,13 @@ void btSequentialImpulseConstraintSolver::convertContact(btPersistentManifold* m
|
||||
|
||||
if ((infoGlobal.m_solverMode & SOLVER_USE_2_FRICTION_DIRECTIONS))
|
||||
{
|
||||
applyAnisotropicFriction(colObj0,cp.m_lateralFrictionDir2);
|
||||
applyAnisotropicFriction(colObj1,cp.m_lateralFrictionDir2);
|
||||
applyAnisotropicFriction(colObj0,cp.m_lateralFrictionDir2,btCollisionObject::CF_ANISOTROPIC_FRICTION);
|
||||
applyAnisotropicFriction(colObj1,cp.m_lateralFrictionDir2,btCollisionObject::CF_ANISOTROPIC_FRICTION);
|
||||
addFrictionConstraint(cp.m_lateralFrictionDir2,solverBodyIdA,solverBodyIdB,frictionIndex,cp,rel_pos1,rel_pos2,colObj0,colObj1, relaxation);
|
||||
}
|
||||
|
||||
applyAnisotropicFriction(colObj0,cp.m_lateralFrictionDir1);
|
||||
applyAnisotropicFriction(colObj1,cp.m_lateralFrictionDir1);
|
||||
applyAnisotropicFriction(colObj0,cp.m_lateralFrictionDir1,btCollisionObject::CF_ANISOTROPIC_FRICTION);
|
||||
applyAnisotropicFriction(colObj1,cp.m_lateralFrictionDir1,btCollisionObject::CF_ANISOTROPIC_FRICTION);
|
||||
addFrictionConstraint(cp.m_lateralFrictionDir1,solverBodyIdA,solverBodyIdB,frictionIndex,cp,rel_pos1,rel_pos2,colObj0,colObj1, relaxation);
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user