Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I'm having a small issue where after applying an impulse or force it is impossible to actually get an object to stop, i.e. a velocity of zero.

This code is run every 1 / 60 of a second:

void RigidBody::Update(double deltaTime) {

    double mass = GetMass();
    //If static body, do nothing.
    if(Math::IsEqual(mass, 0.0)) return;

    Vector2D F;
    Vector2D total_forces = std::accumulate(_curState._forces.begin(), _curState._forces.end(), Vector2D());
    Vector2D total_impulses = std::accumulate(_curState._impulses.begin(), _curState._impulses.end(), Vector2D());
    F = _curState._gravity + total_forces + total_impulses;
    _curState.ClearImpulses();
    SetAcceleration(F / mass);
    SetVelocity(GetVelocity() + GetAcceleration() * deltaTime);
    SetPosition(GetPosition() + GetVelocity() * deltaTime);

}

RigidBody::SetAcceleration(const Vector2D& acceleration) {
    _prevState.SetAcceleration(_curState._acceleration);
    _curState.SetAcceleration(acceleration);
}
//Similar for RigidBody::SetVelocity and RigidBody::SetPosition...

If I apply an impulse, say (-1.0, 0.0), the object's acceleration changes by -0.012 or -0.011 instantaneously and only once then reverts to (0.0, 0.0), which then changes the velocity to (-0.012/-0.011, 0.0). Equal and opposite changes in acceleration causes rounding errors to accumulate to the point where the velocity will never be zero and the object will never stop.

Similarly, if I apply a force, (-1.0, 0.0), the object's acceleration changes to (-1.0, 0.0), equal and opposite forces applied so the acceleration changes to (0.0, 0.0) works but the velocity changes so minutely that again, the object will never stop. (The closest I've ever gotten it was (0.009, 0.0) )

share|improve this question

1 Answer 1

up vote 2 down vote accepted

When you add the impulse to the force, perhaps it might be better to use the force = impulse / dTime formula (There was a question on these topics). Apart from that, when running a simulation, the null vector is almost never numerically encountered. That's quite bad because, in reality, the objects stop at a macro level, whereas they never (or never should) on the quantum level.

Game Physics engines cheat their way around this numerical issue and make up for two major issues: update almost stable objects like crazy even they are not changing their states that much and have the objects vibrate like electrons in a dielectric structure. They do this with a technique that's quite obvious to a programmer: when the dynamic states of the objects allow it and the kinematics are also almost stable (a threshold for velocities and forces that is), the objects are put in a "sleep"mode. Only when they're perturbed beyond this threshold the engine starts managing their updates again and actually moves them. That's why a box thrown against a wall will eventually stop on the ground and not continue to bounce indefinitely near the surface of contact.

Here's a post on the Bullet Forums that explains the concept nicely.

share|improve this answer
1  
+1 Just define a constant float Epsilon, which is low enough, and set values which are below this to 0. Of course I mean the abs() of the values. –  Marton Aug 17 '12 at 10:30

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.