BGE Physics
authorCampbell Barton <ideasman42@gmail.com>
Tue, 14 Apr 2009 12:34:39 +0000 (12:34 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Tue, 14 Apr 2009 12:34:39 +0000 (12:34 +0000)
Clamp objects min/max velocity.
Accessed with bullet physics from the advanced button with dynamic and rigid body objects.
- useful for preventing unstable physics in cases where objects move too fast.
- can add linear velocity with the motion actuator to give smooth motion transitions, without moving too fast.
- minimum velocity means objects don't stop moving.
- python scripts can adjust these values speedup or throttle velocity in the existing direction.

Also made copy properties from an object with no properties work (in case you want to clear all props)

15 files changed:
source/blender/makesdna/DNA_object_types.h
source/blender/src/buttons_logic.c
source/blender/src/editobject.c
source/gameengine/Converter/BL_BlenderDataConversion.cpp
source/gameengine/Ketsji/KX_BulletPhysicsController.cpp
source/gameengine/Ketsji/KX_BulletPhysicsController.h
source/gameengine/Ketsji/KX_ConvertPhysicsObjects.cpp
source/gameengine/Ketsji/KX_GameObject.cpp
source/gameengine/Ketsji/KX_GameObject.h
source/gameengine/Ketsji/KX_IPhysicsController.h
source/gameengine/Physics/Bullet/CcdPhysicsController.cpp
source/gameengine/Physics/Bullet/CcdPhysicsController.h
source/gameengine/Physics/common/PHY_IPhysicsController.h
source/gameengine/Physics/common/PHY_Pro.h
source/gameengine/PyDoc/KX_GameObject.py

index 3a408404b0b15d60defbc796ac647344489ddfe5..82da883df4af7d5c6e35f1088a327698b635363f 100644 (file)
@@ -157,7 +157,9 @@ typedef struct Object {
        float formfactor;
        float rdamping, sizefac;
        float margin;
-       int   pad3;
+       float max_vel; /* clamp the maximum velocity 0.0 is disabled */
+       float min_vel; /* clamp the maximum velocity 0.0 is disabled */
+       float pad3; /* clamp the maximum velocity 0.0 is disabled */
 
        char dt, dtx;
        char totcol;    /* copy of mesh or curve or meta */
index 2f68720acb081233cd0ccc09b23e0e6347a52e69..67531e9b3b822cab51deb8c9a694cf8b44942e4d 100644 (file)
@@ -3139,6 +3139,7 @@ static uiBlock *advanced_bullet_menu(void *arg_ob)
                        uiDefButF(block, NUM, 0, "Margin", 
                                        xco, yco, 180, 19, &ob->margin, 0.001, 1.0, 1, 0, 
                                        "Collision margin");
+                       
                        yco -= 20;
 
                        if (ob->gameflag & OB_RIGID_BODY)
@@ -3166,7 +3167,24 @@ static uiBlock *advanced_bullet_menu(void *arg_ob)
                                uiDefButBitI(block, TOG, OB_LOCK_RIGID_BODY_Z_ROT_AXIS, 0, "Lock Z Rot Axis", 
                                        xco+=180, yco, 180, 19, &ob->gameflag2, 0, 0, 0, 0, 
                                        "Disable simulation of angular motion along the Z axis");
+                               yco -= 20;
                        }
+                       xco = 0;
+                       
+                       uiBlockEndAlign(block);
+                       
+                       uiDefBut(block, LABEL, 0, "Clamp Velocity (zero disables)",       xco, yco, 180*2, 19, NULL, 0, 0, 0, 0, "");
+                       
+                       uiBlockBeginAlign(block);
+                       
+                       uiDefButF(block, NUM, 0, "Min", 
+                               xco+=180, yco, 90, 19, &ob->min_vel, 0.0, 1000.0, 1, 0, 
+                               "Clamp velocity to this minimum speed (except when totally still)");
+                       uiDefButF(block, NUM, 0, "Max", 
+                               xco+=90, yco, 90, 19, &ob->max_vel, 0.0, 1000.0, 1, 0, 
+                               "Clamp velocity to this maximum speed");
+                       uiBlockEndAlign(block);
+                       
                        /*
                        uiDefButBitI(block, TOG, OB_BSB_COL_CL_RS, 0, "Cluster Collision RS", 
                                xco, yco, 180, 19, &ob->bsoft->collisionflags, 0, 0, 0, 0, 
index bb9be49c347446b11aba5d5ccac66f09b1b8df90..2f127f9a3ec26eba0eda1a61f8366dd205f7c28f 100644 (file)
@@ -3205,14 +3205,12 @@ static void copymenu_properties(Object *ob)
                prop= prop->next;
        }
        
-       if(tot==0) {
-               error("No properties in the active object to copy");
-               return;
-       }
-       
        str= MEM_callocN(50 + 33*tot, "copymenu prop");
        
-       strcpy(str, "Copy Property %t|Replace All|Merge All|%l");
+       if (tot)
+               strcpy(str, "Copy Property %t|Replace All|Merge All|%l");
+       else
+               strcpy(str, "Copy Property %t|Clear All (no properties on active)");
        
        tot= 0; 
        prop= ob->prop.first;
@@ -3526,7 +3524,8 @@ void copy_attr(short event)
                                        base->object->formfactor = ob->formfactor;
                                        base->object->damping= ob->damping;
                                        base->object->rdamping= ob->rdamping;
-                                       base->object->mass= ob->mass;
+                                       base->object->min_vel= ob->min_vel;
+                                       base->object->max_vel= ob->max_vel;
                                        if (ob->gameflag & OB_BOUNDS) {
                                                base->object->boundtype = ob->boundtype;
                                        }
index 5de2c4a2fe7d5929a0f71184a8a5fdd05a4922ee..2ae47e47d746547c51fbfcf21f927b67fa4a1b50 100644 (file)
@@ -1107,6 +1107,10 @@ static PHY_ShapeProps *CreateShapePropsFromBlenderObject(struct Object* blendero
        shapeProps->m_do_fh     = (blenderobject->gameflag & OB_DO_FH) != 0; 
        shapeProps->m_do_rot_fh = (blenderobject->gameflag & OB_ROT_FH) != 0;
        
+//     velocity clamping XXX
+       shapeProps->m_clamp_vel_min = blenderobject->min_vel;
+       shapeProps->m_clamp_vel_max = blenderobject->max_vel;
+       
        return shapeProps;
 }
 
index c621f11994abd5fadb77878e1a1585dbbe0108e0..831f9241fec998378cffde2dad778a16947de661 100644 (file)
@@ -59,6 +59,24 @@ void KX_BulletPhysicsController::applyImpulse(const MT_Point3& attach, const MT_
 
 }
 
+float KX_BulletPhysicsController::GetLinVelocityMin()
+{
+       return (float)CcdPhysicsController::GetLinVelocityMin();
+}
+void  KX_BulletPhysicsController::SetLinVelocityMin(float val)
+{
+       CcdPhysicsController::SetLinVelocityMin(val);
+}
+
+float KX_BulletPhysicsController::GetLinVelocityMax()
+{
+       return (float)CcdPhysicsController::GetLinVelocityMax();
+}
+void  KX_BulletPhysicsController::SetLinVelocityMax(float val)
+{
+       CcdPhysicsController::SetLinVelocityMax(val);
+}
+
 void   KX_BulletPhysicsController::SetObject (SG_IObject* object)
 {
        SG_Controller::SetObject(object);
@@ -73,6 +91,10 @@ void KX_BulletPhysicsController::SetObject (SG_IObject* object)
 
 }
 
+MT_Scalar KX_BulletPhysicsController::GetRadius()
+{
+       return MT_Scalar(CcdPhysicsController::GetRadius());
+}
 
 void   KX_BulletPhysicsController::setMargin (float collisionMargin)
 {
@@ -176,11 +198,6 @@ MT_Vector3 KX_BulletPhysicsController::GetLocalInertia()
     return inertia;
 }
 
-MT_Scalar KX_BulletPhysicsController::GetRadius()
-{
-       return MT_Scalar(CcdPhysicsController::GetRadius());
-}
-
 MT_Vector3     KX_BulletPhysicsController::getReactionForce()
 {
        assert(0);
index 9821b3fd253d6cf45208c34219805f7df3a489f0..b39098206f73d7df2906269ed1e1c35364ffa95d 100644 (file)
@@ -56,7 +56,11 @@ public:
        virtual SG_Controller*  GetReplica(class SG_Node* destnode);
 
        virtual MT_Scalar GetRadius();
-
+       
+       virtual float GetLinVelocityMin();
+       virtual void  SetLinVelocityMin(float val);
+       virtual float GetLinVelocityMax();
+       virtual void  SetLinVelocityMax(float val);
 
        virtual void    SetSumoTransform(bool nondynaonly);
        // todo: remove next line !
index 03149859f4d2d40c782b87ae7e308b0cada3be15..08e2ea30414ba380f6318cff3ac6a2f1ab7d4e95 100644 (file)
@@ -801,6 +801,8 @@ void        KX_ConvertBulletObject( class   KX_GameObject* gameobj,
        ci.m_gravity = btVector3(0,0,0);
        ci.m_localInertiaTensor =btVector3(0,0,0);
        ci.m_mass = objprop->m_dyna ? shapeprops->m_mass : 0.f;
+       ci.m_clamp_vel_min = shapeprops->m_clamp_vel_min;
+       ci.m_clamp_vel_max = shapeprops->m_clamp_vel_max;
        ci.m_margin = objprop->m_margin;
        shapeInfo->m_radius = objprop->m_radius;
        isbulletdyna = objprop->m_dyna;
index 16cf3d9ae323728de80eafc774e721274ab4d2d7..a399d3b477ac89eba08f44b77ea7852ea7d41af4 100644 (file)
@@ -1086,6 +1086,8 @@ PyAttributeDef KX_GameObject::Attributes[] = {
        KX_PYATTRIBUTE_RO_FUNCTION("name",              KX_GameObject, pyattr_get_name),
        KX_PYATTRIBUTE_RO_FUNCTION("parent",    KX_GameObject, pyattr_get_parent),
        KX_PYATTRIBUTE_RW_FUNCTION("mass",              KX_GameObject, pyattr_get_mass,         pyattr_set_mass),
+       KX_PYATTRIBUTE_RW_FUNCTION("linVelocityMin",            KX_GameObject, pyattr_get_lin_vel_min, pyattr_set_lin_vel_min),
+       KX_PYATTRIBUTE_RW_FUNCTION("linVelocityMax",            KX_GameObject, pyattr_get_lin_vel_max, pyattr_set_lin_vel_max),
        KX_PYATTRIBUTE_RW_FUNCTION("visible",   KX_GameObject, pyattr_get_visible,      pyattr_set_visible),
        KX_PYATTRIBUTE_BOOL_RW    ("occlusion", KX_GameObject, m_bOccluder),
        KX_PYATTRIBUTE_RW_FUNCTION("position",  KX_GameObject, pyattr_get_position,     pyattr_set_position),
@@ -1364,6 +1366,53 @@ int KX_GameObject::pyattr_set_mass(void *self_v, const KX_PYATTRIBUTE_DEF *attrd
        return 0;
 }
 
+PyObject* KX_GameObject::pyattr_get_lin_vel_min(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
+{
+       KX_GameObject* self= static_cast<KX_GameObject*>(self_v);
+       KX_IPhysicsController *spc = self->GetPhysicsController();
+       return PyFloat_FromDouble(spc ? spc->GetLinVelocityMax() : 0.0f);
+}
+
+int KX_GameObject::pyattr_set_lin_vel_min(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
+{
+       KX_GameObject* self= static_cast<KX_GameObject*>(self_v);
+       KX_IPhysicsController *spc = self->GetPhysicsController();
+       MT_Scalar val = PyFloat_AsDouble(value);
+       if (val < 0.0f) { /* also accounts for non float */
+               PyErr_SetString(PyExc_AttributeError, "expected a float zero or above");
+               return 1;
+       }
+
+       if (spc)
+               spc->SetLinVelocityMin(val);
+
+       return 0;
+}
+
+PyObject* KX_GameObject::pyattr_get_lin_vel_max(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
+{
+       KX_GameObject* self= static_cast<KX_GameObject*>(self_v);
+       KX_IPhysicsController *spc = self->GetPhysicsController();
+       return PyFloat_FromDouble(spc ? spc->GetLinVelocityMax() : 0.0f);
+}
+
+int KX_GameObject::pyattr_set_lin_vel_max(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
+{
+       KX_GameObject* self= static_cast<KX_GameObject*>(self_v);
+       KX_IPhysicsController *spc = self->GetPhysicsController();
+       MT_Scalar val = PyFloat_AsDouble(value);
+       if (val < 0.0f) { /* also accounts for non float */
+               PyErr_SetString(PyExc_AttributeError, "expected a float zero or above");
+               return 1;
+       }
+
+       if (spc)
+               spc->SetLinVelocityMax(val);
+
+       return 0;
+}
+
+
 PyObject* KX_GameObject::pyattr_get_visible(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
 {
        KX_GameObject* self= static_cast<KX_GameObject*>(self_v);
index c389d6cc7761be85a1d916f9633fe575c7ded152..9419258085943662ea2841f6fa7044f0ec4f92da 100644 (file)
@@ -960,6 +960,10 @@ public:
 
        static PyObject*        pyattr_get_mass(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
        static int                      pyattr_set_mass(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
+       static PyObject*        pyattr_get_lin_vel_min(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
+       static int                      pyattr_set_lin_vel_min(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
+       static PyObject*        pyattr_get_lin_vel_max(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
+       static int                      pyattr_set_lin_vel_max(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
        static PyObject*        pyattr_get_visible(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
        static int                      pyattr_set_visible(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
        static PyObject*        pyattr_get_position(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
index b7603203241947139104cb9ca6bca26d0ef8499a..10b66da7b7666c9bbe1401b17896d5a2a065aa61 100644 (file)
@@ -79,6 +79,12 @@ public:
        virtual void setScaling(const MT_Vector3& scaling)=0;
        virtual MT_Scalar       GetMass()=0;
        virtual void    SetMass(MT_Scalar newmass)=0;
+       
+       virtual float GetLinVelocityMin()=0;
+       virtual void    SetLinVelocityMin(float newmass)=0;
+       virtual float GetLinVelocityMax()=0;
+       virtual void    SetLinVelocityMax(float newmass)=0;
+       
        virtual MT_Vector3      GetLocalInertia()=0;
        virtual MT_Vector3      getReactionForce()=0;
        virtual void    setRigidBody(bool rigid)=0;
index 2283968801f7c686a52bbb84f015f1013dd14873..0b9da8f46d30d4943cc729169e1bd0dde75b573c 100644 (file)
@@ -584,7 +584,19 @@ bool               CcdPhysicsController::SynchronizeMotionStates(float time)
 
        if (body && !body->isStaticObject())
        {
-
+               
+               if ((m_cci.m_clamp_vel_max>0.0) || (m_cci.m_clamp_vel_min>0.0))
+               {
+                       const btVector3& linvel = body->getLinearVelocity();
+                       float len= linvel.length();
+                       
+                       if((m_cci.m_clamp_vel_max>0.0) && (len > m_cci.m_clamp_vel_max))
+                                       body->setLinearVelocity(linvel * (m_cci.m_clamp_vel_max / len));
+                       
+                       else if ((m_cci.m_clamp_vel_min>0.0) && btFuzzyZero(len)==0 && (len < m_cci.m_clamp_vel_min))
+                               body->setLinearVelocity(linvel * (m_cci.m_clamp_vel_min / len));
+               }
+               
                const btVector3& worldPos = body->getCenterOfMassPosition();
                m_MotionState->setWorldPosition(worldPos[0],worldPos[1],worldPos[2]);
                
index 245cde2baaa67e2932affb9588fc016f8e3070d6..c7638b36728aaf9343f004aa96ea5fbafd27345e 100644 (file)
@@ -214,6 +214,8 @@ struct CcdConstructionInfo
                m_gravity(0,0,0),
                m_scaling(1.f,1.f,1.f),
                m_mass(0.f),
+               m_clamp_vel_min(-1.f), 
+               m_clamp_vel_max(-1.f), 
                m_restitution(0.1f),
                m_friction(0.5f),
                m_linearDamping(0.1f),
@@ -239,6 +241,8 @@ struct CcdConstructionInfo
        btVector3       m_gravity;
        btVector3       m_scaling;
        btScalar        m_mass;
+       btScalar        m_clamp_vel_min;  
+       btScalar        m_clamp_vel_max;  
        btScalar        m_restitution;
        btScalar        m_friction;
        btScalar        m_linearDamping;
@@ -479,7 +483,24 @@ class CcdPhysicsController : public PHY_IPhysicsController
                        }
                        m_cci.m_radius = margin;
                }
-
+               
+               // velocity clamping
+               virtual void SetLinVelocityMin(float val) 
+               {
+                       m_cci.m_clamp_vel_min= val;
+               }
+               virtual float GetLinVelocityMin() const 
+               {
+                       return m_cci.m_clamp_vel_min;
+               }
+               virtual void SetLinVelocityMax(float val) 
+               {
+                       m_cci.m_clamp_vel_max= val;
+               }
+               virtual float GetLinVelocityMax() const 
+               {
+                       return m_cci.m_clamp_vel_max;
+               }
 
                bool    wantsSleeping();
 
index 6cba6fa88afb47d497d7cb9c5bc217734c113846..770426b48db613558c3238348eb5b7608cb510f8 100644 (file)
@@ -90,6 +90,12 @@ class PHY_IPhysicsController : public PHY_IController
                virtual float GetMargin() const=0;
                virtual float GetRadius() const=0;
                virtual void  SetRadius(float margin) = 0;
+
+               virtual float GetLinVelocityMin() const=0;
+               virtual void  SetLinVelocityMin(float val) = 0;
+               virtual float GetLinVelocityMax() const=0;
+               virtual void  SetLinVelocityMax(float val) = 0;
+               
                PHY__Vector3    GetWorldPosition(PHY__Vector3& localpos);
 
 };
index 32e63ac2f6d2d8406d60e108a01d2d016eff6679..0249fc3118aa6f9a0a248ae2857d9d7f471a928b 100644 (file)
 struct PHY_ShapeProps {
        MT_Scalar  m_mass;                  // Total mass
        MT_Scalar  m_inertia;               // Inertia, should be a tensor some time 
-       MT_Scalar  m_lin_drag;              // Linear drag (air, water) 0 = concrete, 1 = vacuum 
-       MT_Scalar  m_ang_drag;              // Angular drag
+       MT_Scalar  m_lin_drag;              // Linear drag (air, water) 0 = concrete, 1 = vacuum, inverted and called dampening in blenders UI
+       MT_Scalar  m_ang_drag;              // Angular drag, inverted and called dampening in blenders UI
        MT_Scalar  m_friction_scaling[3];   // Scaling for anisotropic friction. Component in range [0, 1]   
+       MT_Scalar  m_clamp_vel_min;                     // Clamp the minimum velocity, this ensures an object moves at a minimum speed unless its stationary
+       MT_Scalar  m_clamp_vel_max;                     // Clamp max velocity
        bool       m_do_anisotropic;        // Should I do anisotropic friction? 
        bool       m_do_fh;                 // Should the object have a linear Fh spring?
        bool       m_do_rot_fh;             // Should the object have an angular Fh spring?
index fa4641c3e2f08391bd10e056c0891f07a05184a9..44b84d44d8d4dcf6d9bd60ed1b8001e353ff8cf0 100644 (file)
@@ -16,8 +16,18 @@ class KX_GameObject: # (SCA_IObject)
        @ivar name: The object's name. (Read only)
                - note: Currently (Blender 2.49) the prefix "OB" is added to all objects name. This may change in blender 2.5.
        @type name: string.
-       @ivar mass: The object's mass (provided the object has a physics controller).
+       @ivar mass: The object's mass
+               - note: The object must have a physics controller for the mass to be applied, otherwise the mass value will be returned as 0.0
        @type mass: float
+       @ivar linVelocityMin: Enforces the object keeps moving at a minimum velocity.
+               - note: Applies to dynamic and rigid body objects only.
+               - note: A value of 0.0 disables this option.
+               - note: While objects are stationary the minimum velocity will not be applied.
+       @type linVelocityMin: float
+       @ivar linVelocityMax: Clamp the maximum linear velocity to prevent objects moving beyond a set speed.
+               - note: Applies to dynamic and rigid body objects only.
+               - note: A value of 0.0 disables this option (rather then setting it stationary).
+       @type linVelocityMax: float
        @ivar localInertia: the object's inertia vector in local coordinates. Read only.
        @type localInertia: list [ix, iy, iz]
        @ivar parent: The object's parent object. (Read only)
@@ -35,7 +45,7 @@ class KX_GameObject: # (SCA_IObject)
        @type scaling: list [sx, sy, sz]
        @ivar timeOffset: adjust the slowparent delay at runtime.
        @type timeOffset: float
-       @ivar state: the game object's state bitmask.
+       @ivar state: the game object's state bitmask, using the first 30 bits, one bit must always be set.
        @type state: int
        @ivar meshes: a list meshes for this object.
                - note: Most objects use only 1 mesh.