BGE patch: Add damping and clamping option to motion actuator.

This patch introduces two options for the motion actuator:

damping: number of frames to reach the target velocity. It takes
into account the startup velocityin the target velocity direction
and add 1/damping fraction of target velocity until the full 
velocity is reached. Works only with linear and angular velocity.
It will be extended to delta and force motion method in a future
release.

clamping: apply the force and torque as long as the target velocity
is not reached. If this option is set, the velocity specified 
in linV or angV are not applied to the object but used as target
velocity. You should also specify a force in force or torque field: 
the force will be applied as long as the velocity along the axis of
the vector set in linV or angV is not reached. Works best in low
friction environment.
This commit is contained in:
Benoit Bolsee 2008-06-24 19:37:43 +00:00
parent 533539901b
commit 15c105c157
12 changed files with 203 additions and 22 deletions

@ -98,7 +98,8 @@ typedef struct bPropertyActuator {
} bPropertyActuator;
typedef struct bObjectActuator {
int flag, type;
short flag, type;
int damping;
float forceloc[3], forcerot[3];
float loc[3], rot[3];
float dloc[3], drot[3];
@ -252,6 +253,7 @@ typedef struct FreeCamera {
#define ACT_ANG_VEL_LOCAL 32
//#define ACT_ADD_LIN_VEL_LOCAL 64
#define ACT_ADD_LIN_VEL 64
#define ACT_CLAMP_VEL 128
#define ACT_OBJECT_FORCE 0
#define ACT_OBJECT_TORQUE 1

@ -1613,7 +1613,7 @@ static short draw_actuatorbuttons(Object *ob, bActuator *act, uiBlock *block, sh
{
case ACT_OBJECT:
{
ysize= 129;
ysize= 152;
glRects(xco, yco-ysize, xco+width, yco);
uiEmboss((float)xco, (float)yco-ysize, (float)xco+width, (float)yco, 1);
@ -1651,6 +1651,10 @@ static short draw_actuatorbuttons(Object *ob, bActuator *act, uiBlock *block, sh
uiDefButF(block, NUM, 0, "", xco+45+wval, yco-125, wval, 19, oa->angularvelocity+1, -10000.0, 10000.0, 10, 0, "");
uiDefButF(block, NUM, 0, "", xco+45+2*wval, yco-125, wval, 19, oa->angularvelocity+2, -10000.0, 10000.0, 10, 0, "");
uiDefBut(block, LABEL, 0, "damp", xco, yco-148, 45, 19, NULL, 0, 0, 0, 0, "Number of frames to reach the target velocity");
uiDefButI(block, NUM, 0, "", xco+45, yco-148, wval, 19, &oa->damping, 0.0, 1000.0, 100, 0, "");
uiDefButBitI(block, TOG, ACT_CLAMP_VEL, 0, "clamp",xco+45+wval, yco-148, wval, 19, &oa->flag, 0.0, 0.0, 0, 0, "Toggles between SET and CLAMP Velocity");
uiDefButBitI(block, TOG, ACT_FORCE_LOCAL, 0, "L", xco+45+3*wval, yco-22, 15, 19, &oa->flag, 0.0, 0.0, 0, 0, "Local transformation");
uiDefButBitI(block, TOG, ACT_TORQUE_LOCAL, 0, "L", xco+45+3*wval, yco-41, 15, 19, &oa->flag, 0.0, 0.0, 0, 0, "Local transformation");
uiDefButBitI(block, TOG, ACT_DLOC_LOCAL, 0, "L", xco+45+3*wval, yco-64, 15, 19, &oa->flag, 0.0, 0.0, 0, 0, "Local transformation");

@ -1668,6 +1668,8 @@ static KX_GameObject *gameobject_from_blenderobject(
BL_ShapeDeformer *dcont = new BL_ShapeDeformer((BL_DeformableGameObject*)gameobj,
ob, (BL_SkinMeshObject*)meshobj);
((BL_DeformableGameObject*)gameobj)->m_pDeformer = dcont;
if (bHasArmature)
dcont->LoadShapeDrivers(ob->parent);
} else if (bHasArmature) {
BL_SkinDeformer *dcont = new BL_SkinDeformer(ob, (BL_SkinMeshObject*)meshobj );
((BL_DeformableGameObject*)gameobj)->m_pDeformer = dcont;
@ -2329,7 +2331,7 @@ void BL_ConvertBlenderObjects(struct Main* maggie,
{
KX_GameObject* gameobj = static_cast<KX_GameObject*>(logicbrick_conversionlist->GetValue(i));
struct Object* blenderobj = converter->FindBlenderObject(gameobj);
gameobj->SetState(blenderobj->state);
gameobj->SetState((blenderobj->init_state)?blenderobj->init_state:blenderobj->state);
}
#endif //CONVERT_LOGIC

@ -137,6 +137,7 @@ void BL_ConvertActuators(char* maggiename,
MT_Vector3 angvelvec ( KX_BLENDERTRUNC(obact->angularvelocity[0]),
KX_BLENDERTRUNC(obact->angularvelocity[1]),
KX_BLENDERTRUNC(obact->angularvelocity[2]));
short damping = obact->damping;
drotvec /= BLENDER_HACK_DTIME;
//drotvec /= BLENDER_HACK_DTIME;
@ -157,7 +158,7 @@ void BL_ConvertActuators(char* maggiename,
bitLocalFlag.DRot = bool((obact->flag & ACT_DROT_LOCAL)!=0);
bitLocalFlag.LinearVelocity = bool((obact->flag & ACT_LIN_VEL_LOCAL)!=0);
bitLocalFlag.AngularVelocity = bool((obact->flag & ACT_ANG_VEL_LOCAL)!=0);
bitLocalFlag.ClampVelocity = bool((obact->flag & ACT_CLAMP_VEL)!=0);
bitLocalFlag.AddOrSetLinV = bool((obact->flag & ACT_ADD_LIN_VEL)!=0);
@ -168,6 +169,7 @@ void BL_ConvertActuators(char* maggiename,
drotvec.getValue(),
linvelvec.getValue(),
angvelvec.getValue(),
damping,
bitLocalFlag
);
baseact = tmpbaseact;

@ -102,6 +102,13 @@ MT_Vector3 KX_BulletPhysicsController::GetLinearVelocity()
CcdPhysicsController::GetLinearVelocity(angVel[0],angVel[1],angVel[2]);//rcruiz
return MT_Vector3(angVel[0],angVel[1],angVel[2]);
}
MT_Vector3 KX_BulletPhysicsController::GetAngularVelocity()
{
float angVel[3];
//CcdPhysicsController::GetAngularVelocity(angVel[0],angVel[1],angVel[2]);
CcdPhysicsController::GetAngularVelocity(angVel[0],angVel[1],angVel[2]);//rcruiz
return MT_Vector3(angVel[0],angVel[1],angVel[2]);
}
MT_Vector3 KX_BulletPhysicsController::GetVelocity(const MT_Point3& pos)
{
float linVel[3];

@ -25,6 +25,7 @@ public:
virtual void ApplyTorque(const MT_Vector3& torque,bool local);
virtual void ApplyForce(const MT_Vector3& force,bool local);
virtual MT_Vector3 GetLinearVelocity();
virtual MT_Vector3 GetAngularVelocity();
virtual MT_Vector3 GetVelocity(const MT_Point3& pos);
virtual void SetAngularVelocity(const MT_Vector3& ang_vel,bool local);
virtual void SetLinearVelocity(const MT_Vector3& lin_vel,bool local);

@ -664,6 +664,27 @@ MT_Vector3 KX_GameObject::GetLinearVelocity(bool local)
return velocity;
}
MT_Vector3 KX_GameObject::GetAngularVelocity(bool local)
{
MT_Vector3 velocity(0.0,0.0,0.0), locvel;
MT_Matrix3x3 ori;
int i, j;
if (m_pPhysicsController1)
{
velocity = m_pPhysicsController1->GetAngularVelocity();
if (local)
{
ori = GetSGNode()->GetWorldOrientation();
locvel = velocity * ori;
return locvel;
}
}
return velocity;
}
// scenegraph node stuff

@ -258,6 +258,14 @@ public:
bool local=false
);
/**
* Return the angular velocity of the game object.
*/
MT_Vector3
GetAngularVelocity(
bool local=false
);
/**
* Align the object to a given normal.
*/

@ -64,6 +64,7 @@ public:
virtual void ApplyTorque(const MT_Vector3& torque,bool local)=0;
virtual void ApplyForce(const MT_Vector3& force,bool local)=0;
virtual MT_Vector3 GetLinearVelocity()=0;
virtual MT_Vector3 GetAngularVelocity()=0;
virtual MT_Vector3 GetVelocity(const MT_Point3& pos)=0;
virtual void SetAngularVelocity(const MT_Vector3& ang_vel,bool local)=0;
virtual void SetLinearVelocity(const MT_Vector3& lin_vel,bool local)=0;

@ -50,6 +50,7 @@ KX_ObjectActuator(
const MT_Vector3& drot,
const MT_Vector3& linV,
const MT_Vector3& angV,
const short damping,
const KX_LocalFlags& flag,
PyTypeObject* T
) :
@ -60,9 +61,16 @@ KX_ObjectActuator(
m_drot(drot),
m_linear_velocity(linV),
m_angular_velocity(angV),
m_linear_length2(0.0),
m_current_linear_factor(0.0),
m_current_angular_factor(0.0),
m_damping(damping),
m_bitLocalFlag (flag),
m_active_combined_velocity (false)
m_active_combined_velocity (false),
m_linear_damping_active(false),
m_angular_damping_active(false)
{
UpdateFuzzyFlags();
}
bool KX_ObjectActuator::Update()
@ -87,42 +95,98 @@ bool KX_ObjectActuator::Update()
);
m_active_combined_velocity = false;
}
m_linear_damping_active = false;
return false;
} else
if (parent)
{
/* Probably better to use some flags, so these MT_zero tests can be */
/* skipped. */
if (!MT_fuzzyZero(m_force))
if (!m_bitLocalFlag.ZeroForce)
{
parent->ApplyForce(m_force,(m_bitLocalFlag.Force) != 0);
if (m_bitLocalFlag.ClampVelocity && !m_bitLocalFlag.ZeroLinearVelocity)
{
// The user is requesting not to exceed the velocity set in m_linear_velocity
// The verification is done by projecting the actual speed along the linV direction
// and comparing it with the linV vector length
MT_Vector3 linV;
linV = parent->GetLinearVelocity(m_bitLocalFlag.LinearVelocity);
if (linV.dot(m_linear_velocity) < m_linear_length2)
parent->ApplyForce(m_force,(m_bitLocalFlag.Force) != 0);
} else
{
parent->ApplyForce(m_force,(m_bitLocalFlag.Force) != 0);
}
}
if (!MT_fuzzyZero(m_torque))
if (!m_bitLocalFlag.ZeroTorque)
{
parent->ApplyTorque(m_torque,(m_bitLocalFlag.Torque) != 0);
if (m_bitLocalFlag.ClampVelocity && !m_bitLocalFlag.ZeroAngularVelocity)
{
// The user is requesting not to exceed the velocity set in m_angular_velocity
// The verification is done by projecting the actual speed in the
MT_Vector3 angV;
angV = parent->GetAngularVelocity(m_bitLocalFlag.AngularVelocity);
if (angV.dot(m_angular_velocity) < m_angular_velocity.length2())
parent->ApplyTorque(m_torque,(m_bitLocalFlag.Torque) != 0);
} else
{
parent->ApplyTorque(m_torque,(m_bitLocalFlag.Torque) != 0);
}
}
if (!MT_fuzzyZero(m_dloc))
if (!m_bitLocalFlag.ZeroDLoc)
{
parent->ApplyMovement(m_dloc,(m_bitLocalFlag.DLoc) != 0);
}
if (!MT_fuzzyZero(m_drot))
if (!m_bitLocalFlag.ZeroDRot)
{
parent->ApplyRotation(m_drot,(m_bitLocalFlag.DRot) != 0);
}
if (!MT_fuzzyZero(m_linear_velocity))
if (!m_bitLocalFlag.ZeroLinearVelocity && !m_bitLocalFlag.ClampVelocity)
{
if (m_bitLocalFlag.AddOrSetLinV) {
parent->addLinearVelocity(m_linear_velocity,(m_bitLocalFlag.LinearVelocity) != 0);
} else {
m_active_combined_velocity = true;
parent->setLinearVelocity(m_linear_velocity,(m_bitLocalFlag.LinearVelocity) != 0);
if (m_damping > 0) {
MT_Vector3 linV;
if (!m_linear_damping_active) {
// delta and the start speed (depends on the existing speed in that direction)
linV = parent->GetLinearVelocity(m_bitLocalFlag.LinearVelocity);
// keep only the projection along the desired direction
m_current_linear_factor = linV.dot(m_linear_velocity)/m_linear_length2;
m_linear_damping_active = true;
}
if (m_current_linear_factor < 1.0)
m_current_linear_factor += 1.0/m_damping;
if (m_current_linear_factor > 1.0)
m_current_linear_factor = 1.0;
linV = m_current_linear_factor * m_linear_velocity;
parent->setLinearVelocity(linV,(m_bitLocalFlag.LinearVelocity) != 0);
} else {
parent->setLinearVelocity(m_linear_velocity,(m_bitLocalFlag.LinearVelocity) != 0);
}
}
}
if (!MT_fuzzyZero(m_angular_velocity))
if (!m_bitLocalFlag.ZeroAngularVelocity && !m_bitLocalFlag.ClampVelocity)
{
parent->setAngularVelocity(m_angular_velocity,(m_bitLocalFlag.AngularVelocity) != 0);
m_active_combined_velocity = true;
if (m_damping > 0) {
MT_Vector3 angV;
if (!m_angular_damping_active) {
// delta and the start speed (depends on the existing speed in that direction)
angV = parent->GetAngularVelocity(m_bitLocalFlag.AngularVelocity);
// keep only the projection along the desired direction
m_current_angular_factor = angV.dot(m_angular_velocity)/m_angular_length2;
m_angular_damping_active = true;
}
if (m_current_angular_factor < 1.0)
m_current_angular_factor += 1.0/m_damping;
if (m_current_angular_factor > 1.0)
m_current_angular_factor = 1.0;
angV = m_current_angular_factor * m_angular_velocity;
parent->setAngularVelocity(angV,(m_bitLocalFlag.AngularVelocity) != 0);
} else {
parent->setAngularVelocity(m_angular_velocity,(m_bitLocalFlag.AngularVelocity) != 0);
}
}
}
@ -199,6 +263,8 @@ PyMethodDef KX_ObjectActuator::Methods[] = {
{"setLinearVelocity", (PyCFunction) KX_ObjectActuator::sPySetLinearVelocity, METH_VARARGS},
{"getAngularVelocity", (PyCFunction) KX_ObjectActuator::sPyGetAngularVelocity, METH_VARARGS},
{"setAngularVelocity", (PyCFunction) KX_ObjectActuator::sPySetAngularVelocity, METH_VARARGS},
{"setVelocityDamping", (PyCFunction) KX_ObjectActuator::sPySetVelocityDamping, METH_VARARGS},
{"getVelocityDamping", (PyCFunction) KX_ObjectActuator::sPyGetVelocityDamping, METH_VARARGS},
{NULL,NULL} //Sentinel
@ -238,6 +304,7 @@ PyObject* KX_ObjectActuator::PySetForce(PyObject* self,
}
m_force.setValue(vecArg);
m_bitLocalFlag.Force = PyArgToBool(bToggle);
UpdateFuzzyFlags();
Py_Return;
}
@ -268,6 +335,7 @@ PyObject* KX_ObjectActuator::PySetTorque(PyObject* self,
}
m_torque.setValue(vecArg);
m_bitLocalFlag.Torque = PyArgToBool(bToggle);
UpdateFuzzyFlags();
Py_Return;
}
@ -298,6 +366,7 @@ PyObject* KX_ObjectActuator::PySetDLoc(PyObject* self,
}
m_dloc.setValue(vecArg);
m_bitLocalFlag.DLoc = PyArgToBool(bToggle);
UpdateFuzzyFlags();
Py_Return;
}
@ -328,6 +397,7 @@ PyObject* KX_ObjectActuator::PySetDRot(PyObject* self,
}
m_drot.setValue(vecArg);
m_bitLocalFlag.DRot = PyArgToBool(bToggle);
UpdateFuzzyFlags();
Py_Return;
}
@ -341,6 +411,7 @@ PyObject* KX_ObjectActuator::PyGetLinearVelocity(PyObject* self,
PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_linear_velocity[1]));
PyList_SetItem(retVal, 2, PyFloat_FromDouble(m_linear_velocity[2]));
PyList_SetItem(retVal, 3, BoolToPyArg(m_bitLocalFlag.LinearVelocity));
PyList_SetItem(retVal, 4, BoolToPyArg(m_bitLocalFlag.ClampVelocity));
return retVal;
}
@ -351,12 +422,15 @@ PyObject* KX_ObjectActuator::PySetLinearVelocity(PyObject* self,
PyObject* kwds) {
float vecArg[3];
int bToggle = 0;
if (!PyArg_ParseTuple(args, "fffi", &vecArg[0], &vecArg[1],
&vecArg[2], &bToggle)) {
int bClamp = 0;
if (!PyArg_ParseTuple(args, "fffi|i", &vecArg[0], &vecArg[1],
&vecArg[2], &bToggle, &bClamp)) {
return NULL;
}
m_linear_velocity.setValue(vecArg);
m_bitLocalFlag.LinearVelocity = PyArgToBool(bToggle);
m_bitLocalFlag.ClampVelocity = PyArgToBool(bClamp);
UpdateFuzzyFlags();
Py_Return;
}
@ -371,6 +445,7 @@ PyObject* KX_ObjectActuator::PyGetAngularVelocity(PyObject* self,
PyList_SetItem(retVal, 1, PyFloat_FromDouble(m_angular_velocity[1]));
PyList_SetItem(retVal, 2, PyFloat_FromDouble(m_angular_velocity[2]));
PyList_SetItem(retVal, 3, BoolToPyArg(m_bitLocalFlag.AngularVelocity));
PyList_SetItem(retVal, 4, BoolToPyArg(m_bitLocalFlag.ClampVelocity));
return retVal;
}
@ -380,15 +455,37 @@ PyObject* KX_ObjectActuator::PySetAngularVelocity(PyObject* self,
PyObject* kwds) {
float vecArg[3];
int bToggle = 0;
if (!PyArg_ParseTuple(args, "fffi", &vecArg[0], &vecArg[1],
&vecArg[2], &bToggle)) {
int bClamp = 0;
if (!PyArg_ParseTuple(args, "fffi|i", &vecArg[0], &vecArg[1],
&vecArg[2], &bToggle, &bClamp)) {
return NULL;
}
m_angular_velocity.setValue(vecArg);
m_bitLocalFlag.AngularVelocity = PyArgToBool(bToggle);
m_bitLocalFlag.ClampVelocity = PyArgToBool(bClamp);
UpdateFuzzyFlags();
Py_Return;
}
/* 13. setVelocityDamping */
PyObject* KX_ObjectActuator::PySetVelocityDamping(PyObject* self,
PyObject* args,
PyObject* kwds) {
int damping = 0;
if (!PyArg_ParseTuple(args, "i", &damping) || damping < 0 || damping > 1000) {
return NULL;
}
m_damping = damping;
Py_Return;
}
/* 13. getVelocityDamping */
PyObject* KX_ObjectActuator::PyGetVelocityDamping(PyObject* self,
PyObject* args,
PyObject* kwds) {
return Py_BuildValue("i",m_damping);
}

@ -46,7 +46,13 @@ struct KX_LocalFlags {
DLoc(false),
LinearVelocity(false),
AngularVelocity(false),
AddOrSetLinV(false)
AddOrSetLinV(false),
ClampVelocity(false),
ZeroForce(false),
ZeroDRot(false),
ZeroDLoc(false),
ZeroLinearVelocity(false),
ZeroAngularVelocity(false)
{
}
@ -57,6 +63,13 @@ struct KX_LocalFlags {
unsigned short LinearVelocity : 1;
unsigned short AngularVelocity : 1;
unsigned short AddOrSetLinV : 1;
unsigned short ClampVelocity : 1;
unsigned short ZeroForce : 1;
unsigned short ZeroTorque : 1;
unsigned short ZeroDRot : 1;
unsigned short ZeroDLoc : 1;
unsigned short ZeroLinearVelocity : 1;
unsigned short ZeroAngularVelocity : 1;
};
class KX_ObjectActuator : public SCA_IActuator
@ -69,6 +82,11 @@ class KX_ObjectActuator : public SCA_IActuator
MT_Vector3 m_drot;
MT_Vector3 m_linear_velocity;
MT_Vector3 m_angular_velocity;
MT_Scalar m_linear_length2;
MT_Scalar m_angular_length2;
MT_Scalar m_current_linear_factor;
MT_Scalar m_current_angular_factor;
short m_damping;
KX_LocalFlags m_bitLocalFlag;
// A hack bool -- oh no sorry everyone
@ -77,6 +95,8 @@ class KX_ObjectActuator : public SCA_IActuator
// setting linear velocity.
bool m_active_combined_velocity;
bool m_linear_damping_active;
bool m_angular_damping_active;
public:
enum KX_OBJECT_ACT_VEC_TYPE {
@ -103,6 +123,7 @@ public:
const MT_Vector3& drot,
const MT_Vector3& linV,
const MT_Vector3& angV,
const short damping,
const KX_LocalFlags& flag,
PyTypeObject* T=&Type
);
@ -110,6 +131,17 @@ public:
CValue* GetReplica();
void SetForceLoc(const double force[3]) { /*m_force=force;*/ }
void UpdateFuzzyFlags()
{
m_bitLocalFlag.ZeroForce = MT_fuzzyZero(m_force);
m_bitLocalFlag.ZeroTorque = MT_fuzzyZero(m_torque);
m_bitLocalFlag.ZeroDLoc = MT_fuzzyZero(m_dloc);
m_bitLocalFlag.ZeroDRot = MT_fuzzyZero(m_drot);
m_bitLocalFlag.ZeroLinearVelocity = MT_fuzzyZero(m_linear_velocity);
m_linear_length2 = (m_bitLocalFlag.ZeroLinearVelocity) ? 0.0 : m_linear_velocity.length2();
m_bitLocalFlag.ZeroAngularVelocity = MT_fuzzyZero(m_angular_velocity);
m_angular_length2 = (m_bitLocalFlag.ZeroAngularVelocity) ? 0.0 : m_angular_velocity.length2();
}
virtual bool Update();
@ -132,6 +164,8 @@ public:
KX_PYMETHOD(KX_ObjectActuator,SetLinearVelocity);
KX_PYMETHOD(KX_ObjectActuator,GetAngularVelocity);
KX_PYMETHOD(KX_ObjectActuator,SetAngularVelocity);
KX_PYMETHOD(KX_ObjectActuator,SetVelocityDamping);
KX_PYMETHOD(KX_ObjectActuator,GetVelocityDamping);
};
#endif //__KX_OBJECTACTUATOR

@ -68,6 +68,8 @@ public:
void ApplyTorque(const MT_Vector3& torque,bool local);
void ApplyForce(const MT_Vector3& force,bool local);
MT_Vector3 GetLinearVelocity();
MT_Vector3 GetAngularVelocity() // to keep compiler happy
{ return MT_Vector3(0.0,0.0,0.0); }
MT_Vector3 GetVelocity(const MT_Point3& pos);
void SetAngularVelocity(const MT_Vector3& ang_vel,bool local);
void SetLinearVelocity(const MT_Vector3& lin_vel,bool local);