1
\$\begingroup\$

I'm trying to make a fairly simple, impulse based rigid body simulator as part of a Uni assignment. I'm using bullet physics to perform collision detection, and my own code to perform collision resolution.

My physics engine runs as follows:

Loop rigid bodies and do the following:

  • Apply gravity to the body's velocity, and damping to the body's velocity and angular velocity.
  • Integrate the position and orientation of the body from the previous frame to the next frame.
  • If the object is moving fast, perform a convex cast with bullet from the previous position and orientation to the new position and orientation. If this cast hits something, move the object up to the contact point (with an allowed penetration of 0.04, because for some reason if I don't allow the penetration, bullet will sometimes not generate contacts correctly later).
  • Loop over the current contacts for each object. Find the deepest contact for each body and move the body along the contact normal by this distance.

Perform collision resolution (done once):

  • Perform discrete collision detection to generate contact points.
  • Loop over each of the contact manifold points and generate an impulse for each point. Apply the impulse directly to the velocity and angular velocity of the associated rigid body(s).

This system works fine without gravity, but when I add gravity, one of my bodies never comes to a rest. The following short video should illustrate this pretty well:

https://www.youtube.com/watch?v=E4B8Lo7xnqc The first part shows the simulation without gravity (all good from what I can see) and the second part (around 0:42) shows what happens when I introduce gravity.

It appears as though the body is somehow gaining too much angular velocity when it collides with the ground, which forces it to continue bouncing around indefinitely. If I manually scale the angular velocity impulse back by a large amount (like 0.1) it reduces the bounding considerably, but doesn't eliminate. Plus, it seems hacky to just simply reduce the angular velocity like that.

The following is what I use to generate the impulse vector against static objects:

Vector CalculateLinearRotationalImpuleSingular(const PhysFrame& state, 
const PhysConstants& constants, 
const Vector& r, 
const Vector& impactNormal)
{
    Vector impulse, rxn;
    const float restitution = 0.85f;
    const float restitutionTerm = -(1 + restitution);
    float lt, ut;

    // r x n
    VectorCrossProduct(r, impactNormal, rxn);

    // Bottom term
    Mat3::MatrixMulVector(state.m_WorldInverseInertiaTensor, rxn, impulse);
    lt = VectorDotProduct(rxn, impulse) + constants.m_InverseMass;

    // Top term
    ut = VectorDotProduct(impactNormal, state.m_Velocity) * restitutionTerm;

    VectorMultiply(impactNormal, ut / lt, impulse);

    return impulse;
}

This is my implementation of this equation: enter image description here

And the following is how I'm applying the impulse of that equation to my rigid body:

void RigidBodyPhysics::ResolveContactWithStatic(RigidBody* rb, const Vector& contactPoint, 
    const Vector& contactNormal)
{
    // Do calculation with one rb
    Vector worldCOG, r1, impulse, angMomentum;
    PhysFrame& state = rb->GetState();
    const PhysConstants& constants = rb->GetConstants();

    worldCOG = CalculateWorldCentreOfMass(rb->GetGameObject()->GetOrigin(),
        state,
        constants);

    // work out r
    VectorSubtract(contactPoint, worldCOG, r1);

    impulse = CalculateLinearRotationalImpuleSingular(state,
        constants, r1, contactNormal);

    // Apply linear velocity change
    state.m_Velocity += (impulse * constants.m_InverseMass);   

    // Apply angular velocity change
    VectorCrossProduct(r1, impulse, angMomentum);
    angMomentum = state.m_WorldInverseInertiaTensor * angMomentum;
    state.m_AngularVelocity += angMomentum * 0.5f;
    // If I add this 0.5 it reduces the jitter, but seems mathematically wrong.

    return; // All done
}

Does anyone know why this super bouncy jittering might be occurring? If needed, I can post more source code snippets, just let me know what you need to see!

\$\endgroup\$
  • \$\begingroup\$ My knowledge of physics is wrong, but in the event that my thought might be helpful, I'll leave it here; In real life physics, objects transfer energy to the other body during a collision, is that being taken into account here? (Specifically into the static body of the floor) \$\endgroup\$ – JonBee Oct 10 '16 at 13:15
  • \$\begingroup\$ I think I account for that using the restitutionTerm in CalculateLinearRotationalImpuleSingular. I'm not entirely sure though, I might be missing some other term that's designed to remove additional energy when impacting a static object. If that is the case, I haven't been able to find any equations explaining how I'd do that. \$\endgroup\$ – S. Foster Oct 11 '16 at 0:22
0
\$\begingroup\$

It's on the right track but there are a couple of odd things happening. Firstly the body doesn't come to rest, it continues gliding and if you are applying damping that shouldn't happen.

Before anything, just have the object in the air, give it an impulse along of say 1m/s and don't process any collisions. You should see it damp down to nothing and then come to rest. Whereas in the video the block never stops it continues floating ad infinitum - unless the damping is so small as to not really effect anything.

The next thing to do, same test, is to test that with slow movement & angular that it comes to a rest. If it does not then before doing anything more complex I would fix that.

With that working the next thing I would do is rig up the scene such that the object is at 45 degrees, drops to the floor, and then rotates to land flat. From that you know exactly what is going into the system, and what you should see coming out.

You would expect to see nothing happening until contact with the floor then you would expect to see an angular velocity along X only which will then die away to nothing as it lands on the floor. If you see anything else then you can debug through to see what is causing that.

Also don't forget when dealing with the world that the angular is applied to the object only, given the world is presumed to have infinite mass for the purposes of the calculations.

Your equations look correct. I've not checked the code thoroughly but this looks like some sort of bug rather than anything fatally wrong.

\$\endgroup\$
  • \$\begingroup\$ Thanks, I'm going through some of your suggestions trying to fix up my simulation. The damping issue was one thing I missed, thanks for pointing it out! \$\endgroup\$ – S. Foster Oct 12 '16 at 4:21
0
\$\begingroup\$

I worked it out. The trick was for me to remove any velocity introduced by gravitational acceleration over the last frame. This stopped the contacts from producing a separating force when they should, in fact, be still on the ground.

This presentation helped me work it out: http://www.cs.qub.ac.uk/~P.Hanna/CSC3049/resources/3.6.%20Contact%20Resolution%20-%20Resting%20Contacts%20and%20Friction.pptx

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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