diff options
author | Sybren A. Stüvel <sybren@stuvel.eu> | 2015-06-18 15:43:30 +0300 |
---|---|---|
committer | Sergey Sharybin <sergey.vfx@gmail.com> | 2015-06-29 16:46:34 +0300 |
commit | adba5756050b37d4193f16aee35cdc001d2a4adf (patch) | |
tree | 6a7e5a786ce0a8ef3b6f5169579a0818419f0f23 /source | |
parent | a08f1d00ae190d1d8568482c3869018713b23122 (diff) |
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
Diffstat (limited to 'source')
4 files changed, 51 insertions, 13 deletions
diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp b/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp index 8ea2b4f299d..6fbd7861d87 100644 --- a/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp +++ b/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp @@ -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(); diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsController.h b/source/gameengine/Physics/Bullet/CcdPhysicsController.h index b1d38763fbb..2a15b6136e4 100644 --- a/source/gameengine/Physics/Bullet/CcdPhysicsController.h +++ b/source/gameengine/Physics/Bullet/CcdPhysicsController.h @@ -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') */ diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp index 3670d79a01e..cd579de8c2e 100644 --- a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp +++ b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp @@ -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; @@ -695,6 +696,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; diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h index 94aea215478..21cbd52fccc 100644 --- a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h +++ b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h @@ -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); |