• 9
• 13
• 18
• 19
• 27

# Gravity, simple circle collision and calculating impulses.

This topic is 2946 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

I have figured out the exact contact points and the velocity for my rigid bodies but something is still not correct with my impulse calculation as something as simple as two interpenetrating circles do not resolve penetration correctly based on impulses. I calculate the impulse as follows:
                //================================================================================
//-- Compute Impulse (Friction and restitution) ----------------------------------
//================================================================================
//
//									-(1+e)(Vr • n)
//			j =  -------------------------------------------------------
//			     (1/Ma + 1/Mb) + (Ia' * (ra x n)^2) + (Ib' * (rb x n)^2)
//
// Where:
//
// j   = Impulse
// e   = Coefficient of Restitution
// Vr  = Relative velocity (A.Velocity - B.Velocity)
// n   = Collision normal
// Ma  = Mass of A
// Mb  = Mass of B
// Ia' = Inverse Moment of Inertia for A
// Ib' = Inverse Moment of Inertia for B

RigidBody2D a = contact.body[0];
RigidBody2D b = contact.body[1];

float ma = a.Mass_Inverse;
float mb = b.Mass_Inverse;

// (1/Ma + 1/Mb)
float m = ma + mb;

// Coefficient of restitution
float e = 0.1f;

// Calculate relative velocity
Vector2 velocity_Relative = a.Velocity - b.Velocity;            // Velocity under gravity = (0, -9.81f)

Vector2 ra = contact.point[0] - a.Position;
Vector2 rb = contact.point[1] - b.Position;

float raXn = Math_Util.Cross(ra, contact.normal);
float rbXn = Math_Util.Cross(rb, contact.normal);

// (Ia' * (ra x n)^2)
float t0 = raXn * raXn * a.Inertia_Inverse;

// (Ib' * (rb x n)^2)
float t1 = rbXn * rbXn * b.Inertia_Inverse;

// (1/Ma + 1/Mb) + (Ia' * (ra x n)^2) + (Ib' * (rb x n)^2)
float denom = m + t0 + t1;

// Calculate scalar impulse
float j = -(1f + e) * Vector2.Dot(velocity_Relative, contact.normal);
j /= denom;

// Calculate vector impulse
Vector2 impulse = j * contact.normal;

// ===========================================
// -[FRICTION]--------------------------------
// ===========================================
// Coefficient of friction
//float f = 0f;

if (!a.HasInfiniteMass)
{
// Add impulse force at contact point for each body
a.ApplyImpulse(impulse, contact.point[0]);

if (a.Velocity.LengthSquared() < 0.001f)
{
a.Velocity = Vector2.Zero;
}
}

if (!b.HasInfiniteMass)
{
// Negate the force for the opposite body (Newton's Third Law)
b.ApplyImpulse(-impulse, contact.point[1]);

if (b.Velocity.LengthSquared() < 0.001f)
{
b.Velocity = Vector2.Zero;
}
}


I have tried zeroing out the velocity vector if it is too small due to floating point inaccuracies but that doesn't help. The only force acting here is gravity and that still allows one shape to intersect another. The shape positions are updated according to the body positions in the rigid body integrate method:
        public void Integrate(float duration)
{
// ==========================================================================================================
// --[Linear]------------------------------------------------------------------------------------------------
// ==========================================================================================================

// Update acceleration from accumulated forces
// F = M * A
// A = F / M
Vector2 acceleration = force_Accumulated * mass_Inverse;

// Update linear velocity from the acceleration
// V = V + A * dT
velocity_Linear += acceleration * duration;

// Update linear position
// P = P + V * dT
position += velocity_Linear * duration;

// ==========================================================================================================
// --[Angular]-----------------------------------------------------------------------------------------------
// ==========================================================================================================

// aA = T / I
float acceleration_Angular = torque_Accumulated * shape.Inertia_Inverse;

// aV = aV + aA * dT
velocity_Angular += acceleration_Angular * duration;

// R = R + aV * dT
rotation += velocity_Angular * duration;

// ==========================================================================================================

// Clear the accumulated forces
force_Accumulated = Vector2.Zero;
torque_Accumulated = 0f;

// Update collision shape if it exists
if (shape != null)
{
shape.Position = position;
shape.Rotation = rotation;
}
}


This is where the force due to gravity pulls one shape inside the other very slowly as if the shape were made of quicksand. I've tried everything I can think of and I've simply no idea how to stop this from occuring. Collision detection works perfectly based on shape position alone, so something about this impulse process just isn't correct. I've combed through a lot of oliii's code for ideas but I still can't find any obvious errors in my code based on his. Can anyone help here, this is driving me crazy! Thank you.

##### Share on other sites
You're back for more punishment, huh?

I think it should be position = v0*t + 1/2*a*t2.

In your Integrate function, try updating your position using the above before you update the velocity.

Yeah, I know. I missed that before.

##### Share on other sites
Quote:
 You're back for more punishment, huh?

It would appear so! :)

Thank you for your suggestions, I have now updated the linear motion part of the integrator:

            // ==========================================================================================================            // --[Linear]------------------------------------------------------------------------------------------------            // ==========================================================================================================                        // Update acceleration from accumulated forces            // F = M * A            // A = F / M            Vector2 acceleration = force_Accumulated * mass_Inverse;            // Update linear position            // P = P + V * dT                     //position += velocity_Linear * duration;            // dP = V0 * t + 0.5 * a * t^2            position += velocity_Linear * duration + (0.5f * acceleration * duration * duration);            // Update linear velocity from the acceleration            // V = V + A * dT            velocity_Linear += acceleration * duration;

Unfortunately this makes no difference to the outcome. Any circle can still sink slowly into another non moving circle whilst only under the force of gravity. Other applied forces will have the same effect.

It just doesn't make any sense to me why this is happening but I can record a video of what is going on if that helps?

##### Share on other sites
You might try setting some of the variables in your equation for j to values such that they don't make a contribution to j. Then add them back in, one at a time to see where the behavior comes from.

##### Share on other sites
I've removed gravity altogether and added 0.02f to the scalar value of j.

When applying a force to one circle, moving it towards a static circle, the moving circle will not sink into the static one.

Instead, when I stop applying the force to the moving circle, it will then move in the direction of the impulse with a velocity of precisely 0.02f.

The same goes for j += 0.06f, j+= 0.09f, etc

The velocity will not change unless another force is applied.

                // Calculate scalar impulse                float j = -(1f + e) * Vector2.Dot(velocity_Relative, contact.normal);                j /= denom;                j += 0.02f;             // <---------------- Added this line

I'm not sure why this would occur though or why, when the small value is omitted, the circles overlap.

Any thoughts?

##### Share on other sites
No-one knows how you want your code to work better than you do. Have you set breakpoints and stepped through your code, looking at variable values and checking that they're giving you the results you expect?

Output some debug values to your debug window while the program is running and see if it's doing what you want it to do. You have a very simple situation, if gravity is all you've got plugged. Does each line of code behave correctly?

##### Share on other sites

As a random thought, if the 'pull-in' is really, really slow you may be looking at numerical instability. Floating point and rounding errors are making your impulse lose to the constant gravity push. If that's the case, you might want to try limiting the number of updates you run each second to see if things get better.

You could also fudge it by doing something like j *= 1.01. This is better than the addition you're doing now, because it will vanish along with the impulse and thus doesn't cause the drift you're seeing now.