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 3a40840..82da883 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 2f68720..67531e9 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 bb9be49..2f127f9 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 5de2c4a..2ae47e4 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 c621f11..831f924 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 9821b3f..b390982 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 0314985..08e2ea3 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 16cf3d9..a399d3b 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 c389d6c..9419258 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 b760320..10b66da 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 2283968..0b9da8f 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 245cde2..c7638b3 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 6cba6fa..770426b 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 32e63ac..0249fc3 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 fa4641c..44b84d4 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.