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:
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!