added anisotropic friction support for Bullet. Both for static and dynamic objects
authorErwin Coumans <blender@erwincoumans.com>
Mon, 29 Sep 2008 03:09:03 +0000 (03:09 +0000)
committerErwin Coumans <blender@erwincoumans.com>
Mon, 29 Sep 2008 03:09:03 +0000 (03:09 +0000)
extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionObject.cpp
extern/bullet2/src/BulletCollision/CollisionDispatch/btCollisionObject.h
extern/bullet2/src/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.cpp
extern/bullet2/src/BulletDynamics/Dynamics/btRigidBody.cpp
source/blender/src/buttons_logic.c
source/gameengine/Ketsji/KX_ConvertPhysicsObjects.cpp
source/gameengine/Physics/Bullet/CcdPhysicsController.cpp
source/gameengine/Physics/Bullet/CcdPhysicsController.h

index eebd0c99fcbdd659739178254b6a196dcc3634ba..846c9b9b989a21c54fc0a70484728921deb114b0 100644 (file)
@@ -17,7 +17,9 @@ subject to the following restrictions:
 #include "btCollisionObject.h"
 
 btCollisionObject::btCollisionObject()
-       :       m_broadphaseHandle(0),
+       :       m_anisotropicFriction(1.f,1.f,1.f),
+       m_hasAnisotropicFriction(false),
+               m_broadphaseHandle(0),
                m_collisionShape(0),
                m_rootCollisionShape(0),
                m_collisionFlags(btCollisionObject::CF_STATIC_OBJECT),
index 0961f3e75c98ed37ff2eecb4ca6c54ca12b3705e..8442868cf89fb872c0b93e15b9128d66c64ce318 100644 (file)
@@ -49,6 +49,9 @@ protected:
        //without destroying the continuous interpolated motion (which uses this interpolation velocities)
        btVector3       m_interpolationLinearVelocity;
        btVector3       m_interpolationAngularVelocity;
+       btVector3               m_anisotropicFriction;
+       bool    m_hasAnisotropicFriction;
+
        btBroadphaseProxy*              m_broadphaseHandle;
        btCollisionShape*               m_collisionShape;
        
@@ -119,6 +122,20 @@ public:
                return  ((m_collisionFlags & (CF_STATIC_OBJECT | CF_KINEMATIC_OBJECT | CF_NO_CONTACT_RESPONSE) )==0);
        }
 
+       const btVector3& getAnisotropicFriction() const
+       {
+               return m_anisotropicFriction;
+       }
+       void    setAnisotropicFriction(const btVector3& anisotropicFriction)
+       {
+               m_anisotropicFriction = anisotropicFriction;
+               m_hasAnisotropicFriction = (anisotropicFriction[0]!=1.f) || (anisotropicFriction[1]!=1.f) || (anisotropicFriction[2]!=1.f);
+       }
+       bool    hasAnisotropicFriction() const
+       {
+               return m_hasAnisotropicFriction;
+       }
+
 
        SIMD_FORCE_INLINE bool          isStaticObject() const {
                return (m_collisionFlags & CF_STATIC_OBJECT) != 0;
index b8afbd6aac5578a20016687e446055517704bd44..2911d52e5ea470e42919ce4fae34fd561550a2e5 100644 (file)
@@ -149,6 +149,7 @@ void        initSolverBody(btSolverBody* solverBody, btCollisionObject* collisionObject
                solverBody->m_originalBody = 0;
                solverBody->m_angularFactor = 1.f;
        }
+       
        solverBody->m_pushVelocity.setValue(0.f,0.f,0.f);
        solverBody->m_turnVelocity.setValue(0.f,0.f,0.f);
 }
@@ -292,7 +293,7 @@ btScalar resolveSingleCollisionCombinedCacheFriendly(
        return normalImpulse;
 }
 
-
+//#define NO_FRICTION_TANGENTIALS 1
 #ifndef NO_FRICTION_TANGENTIALS
 
 btScalar resolveSingleFrictionCacheFriendly(
@@ -396,7 +397,7 @@ btScalar resolveSingleFrictionCacheFriendly(
                        return 0.f;
 
 
-               body1.getVelocityInLocalPoint(contactConstraint.m_rel_posA,vel1);
+               body1.getVelocityInLocalPoint(contactConstraint.m_relpos1CrossNormal,vel1);
                body2.getVelocityInLocalPoint(contactConstraint.m_rel_posB,vel2);
                btVector3 vel = vel1 - vel2;
                btScalar rel_vel;
@@ -421,9 +422,9 @@ btScalar resolveSingleFrictionCacheFriendly(
                                (body1.m_invMass + body2.m_invMass + lat_vel.dot(temp1.cross(rel_pos1) + temp2.cross(rel_pos2)));
                        btScalar normal_impulse = contactConstraint.m_appliedImpulse * combinedFriction;
 
-                       GEN_set_min(friction_impulse, normal_impulse);
-                       GEN_set_max(friction_impulse, -normal_impulse);
-                       body1.applyImpulse(lat_vel * -friction_impulse, rel_pos1);
+                       btSetMin(friction_impulse, normal_impulse);
+                       btSetMin(friction_impulse, -normal_impulse);
+                       body1.internalApplyImpulse(lat_vel * -friction_impulse, rel_pos1);
                        body2.applyImpulse(lat_vel * friction_impulse, rel_pos2);
                }
        }
@@ -495,6 +496,23 @@ void       btSequentialImpulseConstraintSolver::addFrictionConstraint(const btVector3&
 }
 
 
+void   applyAnisotropicFriction(btCollisionObject* colObj,btVector3& frictionDirection);
+void   applyAnisotropicFriction(btCollisionObject* colObj,btVector3& frictionDirection)
+{
+       if (colObj && colObj->hasAnisotropicFriction())
+       {
+               // transform to local coordinates
+               btVector3 loc_lateral = frictionDirection * colObj->getWorldTransform().getBasis();
+               const btVector3& friction_scaling = colObj->getAnisotropicFriction();
+               //apply anisotropic friction
+               loc_lateral *= friction_scaling;
+               // ... and transform it back to global coordinates
+               frictionDirection = colObj->getWorldTransform().getBasis() * loc_lateral;
+       }
+}
+
+
+
 
 btScalar btSequentialImpulseConstraintSolver::solveGroupCacheFriendlySetup(btCollisionObject** /*bodies */,int /*numBodies */,btPersistentManifold** manifoldPtr, int numManifolds,btTypedConstraint** constraints,int numConstraints,const btContactSolverInfo& infoGlobal,btIDebugDraw* debugDrawer,btStackAlloc* stackAlloc)
 {
@@ -755,19 +773,31 @@ btScalar btSequentialImpulseConstraintSolver::solveGroupCacheFriendlySetup(btCol
                                                        if (!cp.m_lateralFrictionInitialized)
                                                        {
                                                                cp.m_lateralFrictionDir1 = vel - cp.m_normalWorldOnB * rel_vel;
+                                                               
+                                                               //scale anisotropic friction
+                                                               
+                                                               applyAnisotropicFriction(colObj0,cp.m_lateralFrictionDir1);
+                                                               applyAnisotropicFriction(colObj1,cp.m_lateralFrictionDir1);
+
                                                                btScalar lat_rel_vel = cp.m_lateralFrictionDir1.length2();
+
+
                                                                if (lat_rel_vel > SIMD_EPSILON)//0.0f)
                                                                {
                                                                        cp.m_lateralFrictionDir1 /= btSqrt(lat_rel_vel);
                                                                        addFrictionConstraint(cp.m_lateralFrictionDir1,solverBodyIdA,solverBodyIdB,frictionIndex,cp,rel_pos1,rel_pos2,colObj0,colObj1, relaxation);
                                                                        cp.m_lateralFrictionDir2 = cp.m_lateralFrictionDir1.cross(cp.m_normalWorldOnB);
-                                                                       cp.m_lateralFrictionDir2.normalize();//??
+                                                                       cp.m_lateralFrictionDir2.normalize();
+                                                                       applyAnisotropicFriction(colObj0,cp.m_lateralFrictionDir2);
+                                                                       applyAnisotropicFriction(colObj1,cp.m_lateralFrictionDir2);
+
                                                                        addFrictionConstraint(cp.m_lateralFrictionDir2,solverBodyIdA,solverBodyIdB,frictionIndex,cp,rel_pos1,rel_pos2,colObj0,colObj1, relaxation);
                                                                } else
                                                                {
                                                                        //re-calculate friction direction every frame, todo: check if this is really needed
-                                                                       
                                                                        btPlaneSpace1(cp.m_normalWorldOnB,cp.m_lateralFrictionDir1,cp.m_lateralFrictionDir2);
+                                                                       applyAnisotropicFriction(colObj0,cp.m_lateralFrictionDir2);
+                                                                       applyAnisotropicFriction(colObj1,cp.m_lateralFrictionDir2);
                                                                        addFrictionConstraint(cp.m_lateralFrictionDir1,solverBodyIdA,solverBodyIdB,frictionIndex,cp,rel_pos1,rel_pos2,colObj0,colObj1, relaxation);
                                                                        addFrictionConstraint(cp.m_lateralFrictionDir2,solverBodyIdA,solverBodyIdB,frictionIndex,cp,rel_pos1,rel_pos2,colObj0,colObj1, relaxation);
                                                                }
index e2afb687ac652808c9612898c7cc0a3c6f6e16bb..93d70de39d832be1af5d2ebf53d9e50955567ad8 100644 (file)
@@ -45,6 +45,7 @@ void  btRigidBody::setupRigidBody(const btRigidBody::btRigidBodyConstructionInfo&
        m_linearVelocity.setValue(btScalar(0.0), btScalar(0.0), btScalar(0.0));
        m_angularVelocity.setValue(btScalar(0.),btScalar(0.),btScalar(0.));
        m_angularFactor = btScalar(1.);
+       m_anisotropicFriction.setValue(1.f,1.f,1.f);
        m_gravity.setValue(btScalar(0.0), btScalar(0.0), btScalar(0.0));
        m_totalForce.setValue(btScalar(0.0), btScalar(0.0), btScalar(0.0));
        m_totalTorque.setValue(btScalar(0.0), btScalar(0.0), btScalar(0.0)),
index 58fb2d456b954a5c9a7db0d4b9a6c59269c1bf82..3d6a82aef579bdef5bd43101f166506062c1cbe2 100644 (file)
@@ -3072,6 +3072,25 @@ static uiBlock *advanced_bullet_menu(void *arg_ob)
                                        xco, yco, 118, 19, &ob->margin, 0.0, 1.0, 1, 0, 
                                        "Collision margin");
                }
+               uiDefButBitI(block, TOG, OB_ANISOTROPIC_FRICTION, B_REDR, "Anisotropic", 
+                                               xco+120, yco, 120, 19,
+                                               &ob->gameflag, 0.0, 1.0, 10, 0,
+                                               "Enable anisotropic friction");                 
+
+               yco-=25;
+
+               if (ob->gameflag & OB_ANISOTROPIC_FRICTION) {
+                       uiDefButF(block, NUM, 0, "X:", 
+                               xco, yco, 80, 19,&ob->anisotropicFriction[0], 0.0, 1.0, 10, 0,
+                                       "Relative friction coefficient in the x-direction.");
+                       uiDefButF(block, NUM, 0, "Y:", 
+                               xco+80, yco, 80, 19,&ob->anisotropicFriction[1], 0.0, 1.0, 10, 0,
+                                       "Relative friction coefficient in the y-direction.");
+                       uiDefButF(block, NUM, 0, "Z:", 
+                               xco+160, yco, 80, 19,&ob->anisotropicFriction[2], 0.0, 1.0, 10, 0,
+                                       "Relative friction coefficient in the z-direction.");
+               }
+
        }
                        
        uiBlockSetDirection(block, UI_TOP);
@@ -3110,6 +3129,9 @@ void buttons_bullet(uiBlock *block, Object *ob)
                uiBlockSetCol(block, TH_BUT_SETTING2);
 
                uiBlockBeginAlign(block);
+               
+               
+
                uiDefButBitI(block, TOG, OB_GHOST, 0, "Ghost", 10, 182, 60, 19, 
                                &ob->gameflag, 0, 0, 0, 0, 
                                "Objects that don't restitute collisions (like a ghost)");
index e4c7e7f9317264ef55d86d782a844420d5b6d0b4..68e0997aec0f086403c4a0ca22a90bb43c74f4a0 100644 (file)
@@ -1025,6 +1025,14 @@ void     KX_ConvertBulletObject( class   KX_GameObject* gameobj,
        //need a bit of damping, else system doesn't behave well
        ci.m_inertiaFactor = shapeprops->m_inertia/0.4f;//defaults to 0.4, don't want to change behaviour
        
+       ci.m_do_anisotropic = shapeprops->m_do_anisotropic;
+       ci.m_anisotropicFriction.setValue(shapeprops->m_friction_scaling[0],shapeprops->m_friction_scaling[1],shapeprops->m_friction_scaling[2]);
+
+       //smprop->m_do_fh = kxshapeprops->m_do_fh;
+       //smprop->m_do_rot_fh = kxshapeprops->m_do_rot_fh ;
+
+       
+       
        
        ///////////////////
        ci.m_gamesoftFlag = objprop->m_gamesoftFlag;
index 166731459e7b1882516b464b5a0678c9e970f437..8ec040e89ee9467fc078f238cd319a1316528ea0 100644 (file)
@@ -500,6 +500,11 @@ void CcdPhysicsController::CreateRigidbody()
                        body->setAngularFactor(0.f);
                }
        }
+       if (m_object && m_cci.m_do_anisotropic)
+       {
+               m_object->setAnisotropicFriction(m_cci.m_anisotropicFriction);
+       }
+               
 }
 
 static void DeleteBulletShape(btCollisionShape* shape)
index 1366764eb63186288312dbd0d586c051aa9bc4d1..f001d6043cbe11c77a8d03ba2b1e8cf55a44cd53 100644 (file)
@@ -186,7 +186,9 @@ struct CcdConstructionInfo
                m_MotionState(0),
                m_shapeInfo(0),
                m_physicsEnv(0),
-               m_inertiaFactor(1.f)
+               m_inertiaFactor(1.f),
+               m_do_anisotropic(false),
+               m_anisotropicFriction(1.f,1.f,1.f)
        {
        }
 
@@ -259,6 +261,9 @@ struct CcdConstructionInfo
        
        CcdPhysicsEnvironment*  m_physicsEnv; //needed for self-replication
        float   m_inertiaFactor;//tweak the inertia (hooked up to Blender 'formfactor'
+       bool    m_do_anisotropic;
+       btVector3 m_anisotropicFriction;
+
 };