From 22fb7d5c1e360b3340551c8f816067d7bf8ba2c7 Mon Sep 17 00:00:00 2001 From: "erwin.coumans" Date: Sun, 16 Sep 2012 17:01:25 +0000 Subject: [PATCH] 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 --- Demos/CcdPhysicsDemo/CcdPhysicsDemo.cpp | 3 +- .../RollingFrictionDemo.cpp | 68 ++++++++++++------- .../CollisionDispatch/btCollisionObject.h | 16 +++-- .../CollisionShapes/btCapsuleShape.h | 8 +++ .../CollisionShapes/btCollisionShape.h | 7 ++ .../CollisionShapes/btConeShape.h | 17 +++++ .../CollisionShapes/btCylinderShape.h | 7 ++ .../btSequentialImpulseConstraintSolver.cpp | 37 ++++++---- 8 files changed, 120 insertions(+), 43 deletions(-) diff --git a/Demos/CcdPhysicsDemo/CcdPhysicsDemo.cpp b/Demos/CcdPhysicsDemo/CcdPhysicsDemo.cpp index 0fb5322e7..9d7477b1a 100644 --- a/Demos/CcdPhysicsDemo/CcdPhysicsDemo.cpp +++ b/Demos/CcdPhysicsDemo/CcdPhysicsDemo.cpp @@ -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) { diff --git a/Demos/RollingFrictionDemo/RollingFrictionDemo.cpp b/Demos/RollingFrictionDemo/RollingFrictionDemo.cpp index a54248147..1e11fc524 100644 --- a/Demos/RollingFrictionDemo/RollingFrictionDemo.cpp +++ b/Demos/RollingFrictionDemo/RollingFrictionDemo.cpp @@ -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;icalculateLocalInertia(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;ksetFriction(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); + } } } } diff --git a/src/BulletCollision/CollisionDispatch/btCollisionObject.h b/src/BulletCollision/CollisionDispatch/btCollisionObject.h index b384eaceb..2b2d57d94 100644 --- a/src/BulletCollision/CollisionDispatch/btCollisionObject.h +++ b/src/BulletCollision/CollisionDispatch/btCollisionObject.h @@ -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. diff --git a/src/BulletCollision/CollisionShapes/btCapsuleShape.h b/src/BulletCollision/CollisionShapes/btCapsuleShape.h index 7197ab6a0..7578bb258 100644 --- a/src/BulletCollision/CollisionShapes/btCapsuleShape.h +++ b/src/BulletCollision/CollisionShapes/btCapsuleShape.h @@ -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) diff --git a/src/BulletCollision/CollisionShapes/btCollisionShape.h b/src/BulletCollision/CollisionShapes/btCollisionShape.h index c5d4128e3..ff017a206 100644 --- a/src/BulletCollision/CollisionShapes/btCollisionShape.h +++ b/src/BulletCollision/CollisionShapes/btCollisionShape.h @@ -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; diff --git a/src/BulletCollision/CollisionShapes/btConeShape.h b/src/BulletCollision/CollisionShapes/btConeShape.h index 8bf78201d..5966ae48f 100644 --- a/src/BulletCollision/CollisionShapes/btConeShape.h +++ b/src/BulletCollision/CollisionShapes/btConeShape.h @@ -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 diff --git a/src/BulletCollision/CollisionShapes/btCylinderShape.h b/src/BulletCollision/CollisionShapes/btCylinderShape.h index 01467d42f..6f796950e 100644 --- a/src/BulletCollision/CollisionShapes/btCylinderShape.h +++ b/src/BulletCollision/CollisionShapes/btCylinderShape.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(); diff --git a/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.cpp b/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.cpp index 37a7c2fae..e4bc94fc7 100644 --- a/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.cpp +++ b/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.cpp @@ -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);