BGE: added clamping of angular velocity.
authorSybren A. Stüvel <sybren@stuvel.eu>
Tue, 23 Jun 2015 13:02:28 +0000 (15:02 +0200)
committerSybren A. Stüvel <sybren@stuvel.eu>
Sun, 28 Jun 2015 10:54:53 +0000 (12:54 +0200)
Angular velocity clamping was missing from the BGE. It is implemented
similarly to the linear velocity clamping. It is needed to be able to
drive physical simulations of systems that have a limited rotational
speed.

Reviewed by: campbellbarton, panzergame, ton

Differential Revision: https://developer.blender.org/D1365

13 files changed:
doc/python_api/rst/bge_types/bge.types.KX_GameObject.rst
release/scripts/startup/bl_ui/properties_game.py
source/blender/editors/object/object_edit.c
source/blender/makesdna/DNA_object_types.h
source/blender/makesrna/intern/rna_object.c
source/gameengine/Converter/BL_BlenderDataConversion.cpp
source/gameengine/Ketsji/KX_GameObject.cpp
source/gameengine/Ketsji/KX_GameObject.h
source/gameengine/Physics/Bullet/CcdPhysicsController.cpp
source/gameengine/Physics/Bullet/CcdPhysicsController.h
source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp
source/gameengine/Physics/common/PHY_IPhysicsController.h
source/gameengine/Physics/common/PHY_Pro.h

index 672df3728a95bf57033032e6644fe9f0198051df..a24aa546cb900ce55ec4731c673c135754fa1d4a 100644 (file)
@@ -139,6 +139,29 @@ base class --- :class:`SCA_IObject`
 
          A value of 0.0 disables this option (rather then setting it stationary).
 
+   .. attribute:: angularVelocityMin
+
+      Enforces the object keeps rotating at a minimum velocity. A value of 0.0 disables this.
+
+      :type: non-negative float
+
+      .. note::
+
+         Applies to dynamic and rigid body objects only.
+         While objects are stationary the minimum velocity will not be applied.
+
+
+   .. attribute:: angularVelocityMax
+
+      Clamp the maximum angular velocity to prevent objects rotating beyond a set speed.
+      A value of 0.0 disables clamping; it does not stop rotation.
+
+      :type: non-negative float
+
+      .. note::
+
+         Applies to dynamic and rigid body objects only.
+
    .. attribute:: localInertia
 
       the object's inertia vector in local coordinates. Read only.
index ceeb45ac4852f6c48c25e99859adfd6c7f5bde3a..fa57bf2115fb881e75d045eac04c7841d5c048d8 100644 (file)
@@ -89,10 +89,14 @@ class PHYSICS_PT_game_physics(PhysicsButtonsPanel, Panel):
             split = layout.split()
 
             col = split.column()
-            col.label(text="Velocity:")
+            col.label(text="Linear velocity:")
             sub = col.column(align=True)
             sub.prop(game, "velocity_min", text="Minimum")
             sub.prop(game, "velocity_max", text="Maximum")
+            col.label(text="Angular velocity:")
+            sub = col.column(align=True)
+            sub.prop(game, "angular_velocity_min", text="Minimum")
+            sub.prop(game, "angular_velocity_max", text="Maximum")
 
             col = split.column()
             col.label(text="Damping:")
index 2681a1f8de0f1cd7a7ff97b2680cc8d0b9cd1f1b..3499a3cc3649592ce472d516ac2b97d7da582872 100644 (file)
@@ -905,6 +905,8 @@ static void copy_attr(Main *bmain, Scene *scene, View3D *v3d, short event)
                                        base->object->rdamping = ob->rdamping;
                                        base->object->min_vel = ob->min_vel;
                                        base->object->max_vel = ob->max_vel;
+                                       base->object->min_angvel = ob->min_angvel;
+                                       base->object->max_angvel = ob->max_angvel;
                                        if (ob->gameflag & OB_BOUNDS) {
                                                base->object->collision_boundtype = ob->collision_boundtype;
                                        }
@@ -2044,6 +2046,8 @@ static int game_physics_copy_exec(bContext *C, wmOperator *UNUSED(op))
                        ob_iter->rdamping = ob->rdamping;
                        ob_iter->min_vel = ob->min_vel;
                        ob_iter->max_vel = ob->max_vel;
+                       ob_iter->min_angvel = ob->min_angvel;
+                       ob_iter->max_angvel = ob->max_angvel;
                        ob_iter->obstacleRad = ob->obstacleRad;
                        ob_iter->mass = ob->mass;
                        copy_v3_v3(ob_iter->anisotropicFriction, ob->anisotropicFriction);
index 978a97f4b49e37aaaccb862fe4d73e44f53ffafa..2daba6a3f0dcb4aa6e61a022f0b80b0cbead310a 100644 (file)
@@ -214,6 +214,8 @@ typedef struct Object {
        float margin;
        float max_vel; /* clamp the maximum velocity 0.0 is disabled */
        float min_vel; /* clamp the minimum velocity 0.0 is disabled */
+       float max_angvel; /* clamp the maximum angular velocity, 0.0 is disabled */
+       float min_angvel; /* clamp the minimum angular velocity, 0.0 is disabled */
        float obstacleRad;
        
        /* "Character" physics properties */
index 3113b702dadb325c522ce5b4cd062b7aaf86de79..f433c2c36a8f1b36ea9724d0251b4447252d8f3f 100644 (file)
@@ -1737,6 +1737,17 @@ static void rna_def_object_game_settings(BlenderRNA *brna)
        RNA_def_property_range(prop, 0.0, 1000.0);
        RNA_def_property_ui_text(prop, "Velocity Max", "Clamp velocity to this maximum speed");
        
+       prop = RNA_def_property(srna, "angular_velocity_min", PROP_FLOAT, PROP_NONE);
+       RNA_def_property_float_sdna(prop, NULL, "min_angvel");
+       RNA_def_property_range(prop, 0.0, 1000.0);
+       RNA_def_property_ui_text(prop, "Angular Velocity Min",
+                                "Clamp angular velocity to this minimum speed (except when totally still)");
+
+       prop = RNA_def_property(srna, "angular_velocity_max", PROP_FLOAT, PROP_NONE);
+       RNA_def_property_float_sdna(prop, NULL, "max_angvel");
+       RNA_def_property_range(prop, 0.0, 1000.0);
+       RNA_def_property_ui_text(prop, "Angular Velocity Max", "Clamp angular velocity to this maximum speed");
+
        /* Character physics */
        prop = RNA_def_property(srna, "step_height", PROP_FLOAT, PROP_NONE);
        RNA_def_property_float_sdna(prop, NULL, "step_height");
index 3da0863508b288074ad9877379d10fc9730ac208..4899eafd84c3f36092d0f3847fbc88569e052125 100644 (file)
@@ -1200,7 +1200,9 @@ static PHY_ShapeProps *CreateShapePropsFromBlenderObject(struct Object* blendero
 //     velocity clamping XXX
        shapeProps->m_clamp_vel_min = blenderobject->min_vel;
        shapeProps->m_clamp_vel_max = blenderobject->max_vel;
-       
+       shapeProps->m_clamp_angvel_min = blenderobject->min_angvel;
+       shapeProps->m_clamp_angvel_max = blenderobject->max_angvel;
+
 //  Character physics properties
        shapeProps->m_step_height = blenderobject->step_height;
        shapeProps->m_jump_speed = blenderobject->jump_speed;
index 34d50e2474169c766be2be1a038afbfea18ad375..5701d0e54a075f150e99d39f88dbf77c06f754c5 100644 (file)
@@ -1965,6 +1965,8 @@ PyAttributeDef KX_GameObject::Attributes[] = {
        KX_PYATTRIBUTE_RO_FUNCTION("isSuspendDynamics",         KX_GameObject, pyattr_get_is_suspend_dynamics),
        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("angularVelocityMin", KX_GameObject, pyattr_get_ang_vel_min, pyattr_set_ang_vel_min),
+       KX_PYATTRIBUTE_RW_FUNCTION("angularVelocityMax", KX_GameObject, pyattr_get_ang_vel_max, pyattr_set_ang_vel_max),
        KX_PYATTRIBUTE_RW_FUNCTION("visible",   KX_GameObject, pyattr_get_visible,      pyattr_set_visible),
        KX_PYATTRIBUTE_RW_FUNCTION("record_animation",  KX_GameObject, pyattr_get_record_animation,     pyattr_set_record_animation),
        KX_PYATTRIBUTE_BOOL_RW    ("occlusion", KX_GameObject, m_bOccluder),
@@ -2487,6 +2489,54 @@ int KX_GameObject::pyattr_set_lin_vel_max(void *self_v, const KX_PYATTRIBUTE_DEF
        return PY_SET_ATTR_SUCCESS;
 }
 
+PyObject *KX_GameObject::pyattr_get_ang_vel_min(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
+{
+       KX_GameObject *self = static_cast<KX_GameObject*>(self_v);
+       PHY_IPhysicsController *spc = self->GetPhysicsController();
+       return PyFloat_FromDouble(spc ? spc->GetAngularVelocityMin() : 0.0f);
+}
+
+int KX_GameObject::pyattr_set_ang_vel_min(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
+{
+       KX_GameObject *self = static_cast<KX_GameObject*>(self_v);
+       PHY_IPhysicsController *spc = self->GetPhysicsController();
+       MT_Scalar val = PyFloat_AsDouble(value);
+       if (val < 0.0f) { /* also accounts for non float */
+               PyErr_SetString(PyExc_AttributeError,
+                               "gameOb.angularVelocityMin = float: KX_GameObject, expected a nonnegative float");
+               return PY_SET_ATTR_FAIL;
+       }
+
+       if (spc)
+               spc->SetAngularVelocityMin(val);
+
+       return PY_SET_ATTR_SUCCESS;
+}
+
+PyObject *KX_GameObject::pyattr_get_ang_vel_max(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
+{
+       KX_GameObject *self = static_cast<KX_GameObject*>(self_v);
+       PHY_IPhysicsController *spc = self->GetPhysicsController();
+       return PyFloat_FromDouble(spc ? spc->GetAngularVelocityMax() : 0.0f);
+}
+
+int KX_GameObject::pyattr_set_ang_vel_max(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
+{
+       KX_GameObject *self = static_cast<KX_GameObject*>(self_v);
+       PHY_IPhysicsController *spc = self->GetPhysicsController();
+       MT_Scalar val = PyFloat_AsDouble(value);
+       if (val < 0.0f) { /* also accounts for non float */
+               PyErr_SetString(PyExc_AttributeError,
+                               "gameOb.angularVelocityMax = float: KX_GameObject, expected a nonnegative float");
+               return PY_SET_ATTR_FAIL;
+       }
+
+       if (spc)
+               spc->SetAngularVelocityMax(val);
+
+       return PY_SET_ATTR_SUCCESS;
+}
+
 
 PyObject *KX_GameObject::pyattr_get_visible(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
 {
index 9c081b449ecffdd28a6dbabe88d9622dcf028fba..670fcd6fb6e8cbec0245864d15f768223fd76408 100644 (file)
@@ -1054,6 +1054,10 @@ public:
        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_ang_vel_min(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
+       static int                      pyattr_set_ang_vel_min(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
+       static PyObject*        pyattr_get_ang_vel_max(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
+       static int                      pyattr_set_ang_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_record_animation(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
index 4306d6d0cd7824517c80e82a175a41a3addeec96..692704b508073bcae70b642b66a761e42dd46e26 100644 (file)
@@ -713,6 +713,17 @@ void CcdPhysicsController::SimulationTick(float timestep)
                else if (m_cci.m_clamp_vel_min > 0.0f && !btFuzzyZero(len) && len < m_cci.m_clamp_vel_min)
                        body->setLinearVelocity(linvel * (m_cci.m_clamp_vel_min / len));
        }
+
+       // Clamp angular velocity
+       if (m_cci.m_clamp_angvel_max > 0.0f || m_cci.m_clamp_angvel_min > 0.0f) {
+               const btVector3 &angvel = body->getAngularVelocity();
+               btScalar len = angvel.length();
+
+               if (m_cci.m_clamp_angvel_max > 0.0f && len > m_cci.m_clamp_angvel_max)
+                       body->setAngularVelocity(angvel * (m_cci.m_clamp_angvel_max / len));
+               else if (m_cci.m_clamp_angvel_min > 0.0f && !btFuzzyZero(len) && len < m_cci.m_clamp_angvel_min)
+                       body->setAngularVelocity(angvel * (m_cci.m_clamp_angvel_min / len));
+       }
 }
 
 
index 2a15b6136e486e51d38ac5b609db0f020b3fcd4c..c49ae8d20e1fdbaa6c35f363c7da7b28b56f21e6 100644 (file)
@@ -236,6 +236,8 @@ struct CcdConstructionInfo
                m_mass(0.f),
                m_clamp_vel_min(-1.f),
                m_clamp_vel_max(-1.f),
+           m_clamp_angvel_min(0.0f),
+           m_clamp_angvel_max(0.0f),
                m_restitution(0.1f),
                m_friction(0.5f),
                m_linearDamping(0.1f),
@@ -302,6 +304,8 @@ struct CcdConstructionInfo
        btScalar        m_mass;
        btScalar        m_clamp_vel_min;  
        btScalar        m_clamp_vel_max;  
+       btScalar        m_clamp_angvel_min;  // Minimum angular velocity, in radians/sec.
+       btScalar        m_clamp_angvel_max;  // Maximum angular velocity, in radians/sec.
        btScalar        m_restitution;
        btScalar        m_friction;
        btScalar        m_linearDamping;
@@ -708,6 +712,23 @@ protected:
                        return m_cci.m_clamp_vel_max;
                }
 
+               virtual void SetAngularVelocityMin(float val)
+               {
+                       m_cci.m_clamp_angvel_min = val;
+               }
+               virtual float GetAngularVelocityMin() const
+               {
+                       return m_cci.m_clamp_angvel_min;
+               }
+               virtual void SetAngularVelocityMax(float val)
+               {
+                       m_cci.m_clamp_angvel_max = val;
+               }
+               virtual float GetAngularVelocityMax() const
+               {
+                       return m_cci.m_clamp_angvel_max;
+               }
+
                bool    WantsSleeping();
 
                void    UpdateDeactivation(float timeStep);
index 14a19fdfb416573185a8cb76893c5c1096f5b112..82451e6a3ed4a5b15ede01083eac71b02ba7e4be 100644 (file)
@@ -3111,6 +3111,8 @@ void CcdPhysicsEnvironment::ConvertObject(KX_GameObject *gameobj, RAS_MeshObject
        ci.m_mass = isbulletdyna ? 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_clamp_angvel_min = shapeprops->m_clamp_angvel_min;
+       ci.m_clamp_angvel_max = shapeprops->m_clamp_angvel_max;
        ci.m_stepHeight = isbulletchar ? shapeprops->m_step_height : 0.f;
        ci.m_jumpSpeed = isbulletchar ? shapeprops->m_jump_speed : 0.f;
        ci.m_fallSpeed = isbulletchar ? shapeprops->m_fall_speed : 0.f;
index 3e2337f01ea231c05b835382896522394dc60fcd..62b163536ddbce714cbe567310add73ef655fadc 100644 (file)
@@ -125,6 +125,11 @@ class PHY_IPhysicsController : public PHY_IController
                virtual float GetLinVelocityMax() const=0;
                virtual void  SetLinVelocityMax(float val) = 0;
                
+               virtual void SetAngularVelocityMin(float val) = 0;
+               virtual float GetAngularVelocityMin() const = 0;
+               virtual void SetAngularVelocityMax(float val) = 0;
+               virtual float GetAngularVelocityMax() const = 0;
+
                MT_Vector3      GetWorldPosition(MT_Vector3& localpos);
 
                // Shape control
index 7c5d9c9638e4f57d16418bd1f8d39aed8678a83a..c9b91b06a3c1d9b4ba1fc8886222c343b59ad98c 100644 (file)
@@ -43,6 +43,8 @@ struct PHY_ShapeProps {
        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
+       MT_Scalar  m_clamp_angvel_min;          // Clamp the minimum angular velocity.
+       MT_Scalar  m_clamp_angvel_max;          // Clamp the maximum angular 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?