2
\$\begingroup\$

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

\$\endgroup\$

1 Answer 1

3
\$\begingroup\$

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.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ +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. \$\endgroup\$
    – Marton
    Commented Aug 17, 2012 at 10:30

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .