BGE Fix: apply velocity clamping on every physics subtick
This patch uses the Bullet "internal tick callback" functionality to ensure that velocity clamping is performed after every physics update. This makes a difference when physics subticks > 1, as in that case the too-high velocity could have impacted the simulation. This patch follows the examples at [1] and [2]; the latter example also explains that the way we limit velocity in the BGE (before this patch) is wrong. [1] http://bulletphysics.org/mediawiki-1.5.8/index.php/Simulation_Tick_Callbacks [2] http://www.bulletphysics.org/mediawiki-1.5.8/index.php/Code_Snippets#I_want_to_cap_the_speed_of_my_spaceship; Reviewed by: panzergame Differential Revision: https://developer.blender.org/D1364
This commit is contained in:
parent
32319dd106
commit
c5c2883ce0
|
@ -697,6 +697,24 @@ CcdPhysicsController::~CcdPhysicsController()
|
|||
}
|
||||
}
|
||||
|
||||
void CcdPhysicsController::SimulationTick(float timestep)
|
||||
{
|
||||
btRigidBody *body = GetRigidBody();
|
||||
if (!body && body->isStaticObject())
|
||||
return;
|
||||
|
||||
// Clamp linear velocity
|
||||
if (m_cci.m_clamp_vel_max > 0.0f || m_cci.m_clamp_vel_min > 0.0f) {
|
||||
const btVector3 &linvel = body->getLinearVelocity();
|
||||
btScalar len = linvel.length();
|
||||
|
||||
if (m_cci.m_clamp_vel_max > 0.0f && 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.0f && !btFuzzyZero(len) && len < m_cci.m_clamp_vel_min)
|
||||
body->setLinearVelocity(linvel * (m_cci.m_clamp_vel_min / len));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* SynchronizeMotionStates ynchronizes dynas, kinematic and deformable entities (and do 'late binding')
|
||||
|
@ -732,19 +750,6 @@ 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 btTransform& xform = body->getCenterOfMassTransform();
|
||||
const btMatrix3x3& worldOri = xform.getBasis();
|
||||
const btVector3& worldPos = xform.getOrigin();
|
||||
|
|
|
@ -579,6 +579,13 @@ protected:
|
|||
* SynchronizeMotionStates ynchronizes dynas, kinematic and deformable entities (and do 'late binding')
|
||||
*/
|
||||
virtual bool SynchronizeMotionStates(float time);
|
||||
|
||||
/**
|
||||
* Called for every physics simulation step. Use this method for
|
||||
* things like limiting linear and angular velocity.
|
||||
*/
|
||||
void SimulationTick(float timestep);
|
||||
|
||||
/**
|
||||
* WriteMotionStateToDynamics ynchronizes dynas, kinematic and deformable entities (and do 'late binding')
|
||||
*/
|
||||
|
|
|
@ -452,6 +452,7 @@ m_scalingPropagated(false)
|
|||
SetSolverType(1);//issues with quickstep and memory allocations
|
||||
// m_dynamicsWorld = new btDiscreteDynamicsWorld(dispatcher,m_broadphase,m_solver,m_collisionConfiguration);
|
||||
m_dynamicsWorld = new btSoftRigidDynamicsWorld(dispatcher,m_broadphase,m_solver,m_collisionConfiguration);
|
||||
m_dynamicsWorld->setInternalTickCallback(&CcdPhysicsEnvironment::StaticSimulationSubtickCallback, this);
|
||||
//m_dynamicsWorld->getSolverInfo().m_linearSlop = 0.01f;
|
||||
//m_dynamicsWorld->getSolverInfo().m_solverMode= SOLVER_USE_WARMSTARTING + SOLVER_USE_2_FRICTION_DIRECTIONS + SOLVER_RANDMIZE_ORDER + SOLVER_USE_FRICTION_WARMSTARTING;
|
||||
|
||||
|
@ -677,6 +678,22 @@ void CcdPhysicsEnvironment::DebugDrawWorld()
|
|||
m_dynamicsWorld->debugDrawWorld();
|
||||
}
|
||||
|
||||
void CcdPhysicsEnvironment::StaticSimulationSubtickCallback(btDynamicsWorld *world, btScalar timeStep)
|
||||
{
|
||||
// Get the pointer to the CcdPhysicsEnvironment associated with this Bullet world.
|
||||
CcdPhysicsEnvironment *this_ = static_cast<CcdPhysicsEnvironment*>(world->getWorldUserInfo());
|
||||
this_->SimulationSubtickCallback(timeStep);
|
||||
}
|
||||
|
||||
void CcdPhysicsEnvironment::SimulationSubtickCallback(btScalar timeStep)
|
||||
{
|
||||
std::set<CcdPhysicsController*>::iterator it;
|
||||
|
||||
for (it = m_controllers.begin(); it != m_controllers.end(); it++) {
|
||||
(*it)->SimulationTick(timeStep);
|
||||
}
|
||||
}
|
||||
|
||||
bool CcdPhysicsEnvironment::ProceedDeltaTime(double curTime,float timeStep,float interval)
|
||||
{
|
||||
std::set<CcdPhysicsController*>::iterator it;
|
||||
|
|
|
@ -52,6 +52,7 @@ class btBroadphaseInterface;
|
|||
struct btDbvtBroadphase;
|
||||
class btOverlappingPairCache;
|
||||
class btIDebugDraw;
|
||||
class btDynamicsWorld;
|
||||
class PHY_IVehicle;
|
||||
class CcdOverlapFilterCallBack;
|
||||
class CcdShapeConstructionInfo;
|
||||
|
@ -129,6 +130,14 @@ protected:
|
|||
/// Perform an integration step of duration 'timeStep'.
|
||||
virtual bool ProceedDeltaTime(double curTime,float timeStep,float interval);
|
||||
|
||||
/**
|
||||
* Called by Bullet for every physical simulation (sub)tick.
|
||||
* Our constructor registers this callback to Bullet, which stores a pointer to 'this' in
|
||||
* the btDynamicsWorld::getWorldUserInfo() pointer.
|
||||
*/
|
||||
static void StaticSimulationSubtickCallback(btDynamicsWorld *world, btScalar timeStep);
|
||||
void SimulationSubtickCallback(btScalar timeStep);
|
||||
|
||||
virtual void DebugDrawWorld();
|
||||
// virtual bool proceedDeltaTimeOneStep(float timeStep);
|
||||
|
||||
|
|
Loading…
Reference in New Issue