BGE Physics

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)
This commit is contained in:
2009-04-14 12:34:39 +00:00
parent 1bc31fc7f9
commit 3511f8ef9f
15 changed files with 176 additions and 20 deletions

View 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 */

View 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,

View 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;
}

View 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;
}

View 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);

View 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 !

View 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;

View 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);

View 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);

View 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;

View 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]);

View 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();

View 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);
};

View File

@@ -35,9 +35,11 @@
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?

View 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.