# Impulses causing both objects to drift in normal direction when in contact.

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

## Recommended Posts

I'm currently working on getting my impulse behaviour correct for two rigid bodies that are colliding: Body a has 0 mass and is not affected by an impulse Body b will be pushed in the direction of the -ve collision normal (0, 1) using an impulse. Both the colliding shapes will be repositioned based on the following formula: a.Shape.Centre += contacts.normal * contacts.penetration; b.Shape.Centre += -contacts.normal * contacts.penetration; The problem is that when both shapes/bodies are in contact, they both gradually drift in the direction of the collision normal (0, -1). Here is how I'm currently applying the impulses/resolving the collisions:
            // Collect all contacts from collision detection then solve them one by one
List<Contact2D> contacts = detector.contact_List;

// Iterate backwards through contacts so they can be removed from the list in the same loop
for (int i = contacts.Count - 1; i >= 0; i--)
{
Contact2D contact = contacts;

RigidBody2D a = contact.body[0];                // Solid object
RigidBody2D b = contact.body[1];                // Man

// Correct collision shape positions
a.Shape.Centre += contacts.normal * contacts.penetration;
b.Shape.Centre += -contacts.normal * contacts.penetration;

// Coefficient of restitution
float e = 0.9f; // BOING!

// Calculate relative velocity
Vector2 velocity_Relative = a.Velocity - b.Velocity;

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

// The following is not needed if normal is normalised (unit length):
//j /= Vector2.Dot(contact.normal, contact.normal * (a.Mass_Inverse + b.Mass_Inverse));

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

// Add impulse force at contact point for each body
a.ApplyImpulse(impulse, contact.point);

// Negate the force for the opposite body (Newton's Third Law)
b.ApplyImpulse(-impulse, contact.point);

// Remove this contact now that it has been resolved
contacts.RemoveAt(i);
}


Applying the impulse for the body is as follows:
        public void ApplyImpulse(Vector2 impulse, Vector2 point)
{
// v2 = v1 + j/m * n
velocity_Linear += mass_Inverse * impulse;
}


The collision shapes positions/centres are also being updated when the body is integrated, if body does not have 0 mass:
        public void Integrate(float duration)
{
// We don't integrate things with zero mass
if (!HasFiniteMass)
{
return;
}

// Update acceleration from accumulated forces
// F = M * A
// A = F / M
//Vector2 acceleration_Resulting = acceleration;
//acceleration_Resulting += force_Accumulated;
Vector2 acceleration = force_Accumulated / Mass;

// 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;

// aA = T / I
float acceleration_Angular = torque_Accumulated / (Mass * shape.Inertia);

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

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

// Clear the accumulated forces
ClearAccumulatedForce();

// Does the world transform need recreating this frame?
//isAwake = velocity != Vector2.Zero ? true : false;

// Update the shape
shape.Centre = position;
shape.Rotation = rotation;
}


Can anyone please explain why the drifting might be occuring? Thank you.

##### Share on other sites
In your Integrate function, you set the shape's centre according to force_Accumulated. Where/how is force_Accumulated set?

##### Share on other sites
Quote:
 Original post by BuckeyeIn your Integrate function, you set the shape's centre according to force_Accumulated. Where/how is force_Accumulated set?

Are you talking about these lines in the Integrate() method?

            // Update the shape             shape.Position = position;            shape.Rotation = rotation;

The force_Accumulated is only set inside the rigid body class via the following methods:

        public void AddForce(Vector2 force)        {            // Accumulation stage must take place before the particle is integrated [Integrate()]            force_Accumulated += force;        }        public void AddForce(Vector2 force, Vector2 point)        {            isAwake = true;            // Accumulation stage must take place before the particle is integrated [Integrate()]            force_Accumulated += force;            point -= position;            // Position is always at centre of mass            //torque_Accumulated += force.Cross(point);        }

Currently only gravity and drag are affecting the rigid body:

    class Particle2D_Gravity : IRigidBody2D_ForceGenerator    {        Vector2 gravity;    // Holds the acceleration due to gravity        // Create the generator with the given acceleration        public Particle2D_Gravity(Vector2 gravity)        {            this.gravity = gravity;        }        // Applies the gravitational force to the given particle        public override void UpdateForce(RigidBody2D body, float duration)        {            if (body.IgnoreGravity || !body.HasFiniteMass)            {                return;            }            // Apply the mass-scaled force to the particle            body.AddForce(gravity * body.Mass);        }    }    class Particle2D_Drag : IRigidBody2D_ForceGenerator    {        float k1;   // Holds the velocity drag coefficient        float k2;   // Holds the velocity squared drag coefficient        public Particle2D_Drag(float k1, float k2)        {            this.k1 = k1;            this.k2 = k2;        }        // Applies the drag force to the given particle        public override void UpdateForce(RigidBody2D body, float duration)        {            if (!body.HasFiniteMass)            {                return;            }            Vector2 force = body.Velocity;            // Calculate the total drag coefficient            float drag_Coefficient = force.Length();            drag_Coefficient = k1 * drag_Coefficient + k2 * drag_Coefficient * drag_Coefficient;            // Calculate the final force and apply it            if (drag_Coefficient != 0)            {                // Force must be normalised for drag equation to be correct                force.Normalize();            }            force *= -drag_Coefficient;            body.AddForce(force);        }    }

The acceleration of the body is as follows:

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

Thanks for coming to my hair's rescue Buckeye. I've been tearing it out for most of the day trying to figure this one out!

##### Share on other sites
Quote:
 Are you talking about these lines in the Integrate() method? // Update the shape shape.Position = position; shape.Rotation = rotation;

Nope. These lines:
Quote:
 // Update the shape shape.Centre = position; shape.Rotation = rotation;

##### Share on other sites
Apologies, they are the same two lines now I've updated my code since the first post:

        public void Integrate(float duration)        {            // We don't integrate things with zero mass            if (!HasFiniteMass)            {                return;            }            // ==========================================================================================================            // --[Linear]------------------------------------------------------------------------------------------------            // ==========================================================================================================            // Update acceleration from accumulated forces            // F = M * A            // A = F / M            Vector2 acceleration = force_Accumulated * mass_Inverse;            //Vector2 acceleration_Resulting = acceleration;            //acceleration_Resulting += force_Accumulated;                        // 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 / (Mass * shape.Inertia);                        // aV = aV + aA * dT            velocity_Angular += acceleration_Angular * duration;            // R = R + aV * dT             rotation += velocity_Angular * duration;            // ==========================================================================================================            // Clear the accumulated forces            ClearAccumulatedForce();            // Does the world transform need recreating this frame?            //isAwake = velocity != Vector2.Zero ? true : false;            // Update the shape             shape.Position = position;            shape.Rotation = rotation;        }

##### Share on other sites
What's the relationship between shape.Centre and shape.Position? It's not clear what you're using to render the shape.

Also, what do you use for mass_Inverse (assuming mass_Inverse = 1/mass) for mass=0?
Quote:
 // We don't integrate things with zero mass if (!HasFiniteMass) { return; }

Also, should that be if(!HasZeroMass)??

##### Share on other sites
Here is my shape class:

    public enum Shape_Type : int    {        CIRCLE = 0,        OBB = 1,        POLYGON = 2,        AABB = 3,                  Count = 4                               // Total number of shape types    }    public abstract class Shape    {           protected Vector2 centre;               // Shape's centroid (centre of mass)        protected float mass;                   // Shape's mass        protected float inertia;                // Moment of inertia        protected float inertia_Inverse;        // The inverse of the shape's inertia        protected Vector2 position;             // Position in world space coordinates        protected float radius;                 // Radius of minimum circle that encompasses all shape's points        protected bool recreateWorld = true;    // Recreate the world transform this frame?        protected float rotation;               // Rotation angle        protected Vector2 scale = Vector2.One;        protected Shape_Type type;              // Shape type        protected Vector2 velocity;             // Shape's velocity        protected Matrix world_Transform;               public Shape() { }#if DEBUG        public abstract void Draw();            // All shapes must be able to be drawn#endif        public Vector2 Position        {            get            {                return position;            }            set            {                recreateWorld = true;                position = value;            }        }        public float Inertia        {            get            {                return inertia;            }            set            {                inertia = value;            }        }        public float Radius        {            get            {                return radius;            }            set            {                recreateWorld = true;                radius = value;            }        }        public float Rotation        {            get            {                return rotation;            }            set            {                recreateWorld = true;                rotation = value;            }        }        public Shape_Type Type        {            get            {                return type;            }        }        public Vector2 Velocity        {            get            {                return velocity;            }            set            {                velocity = value;            }        }    }

Position is the world position of the shape. Centre no longer exists as a property as it has been replace by Position. The protected variable centre is the shape's centroid.

All shapes are drawn using a world transform, as follows:

                    world_Transform =                        // Translate centroid to origin first (only required if centroid is not (0,0,0))                        Matrix.CreateTranslation(new Vector3(-centre, 0.0f)) *                         Matrix.CreateScale(scale.X, scale.Y, 0f) *                        Matrix.CreateRotationZ(rotation) *                        Matrix.CreateTranslation(position.X, position.Y, 0f);

Quote:
 Also, what do you use for mass_Inverse (assuming mass_Inverse = 1/mass) for mass=0?

Mass and mass_Inverse are set as follows:

        public bool HasFiniteMass        {            get { return mass_Inverse > 0f; }        }        public float Mass        {            get            {                if (mass_Inverse == 0)                {                    return float.MaxValue;                }                else                {                    return (1.0f / mass_Inverse);                }            }            set            {                mass_Inverse = value;             }        }        public float Mass_Inverse        {            get { return mass_Inverse; }            set { mass_Inverse = value; }        }

Are my properties correct?

##### Share on other sites
public float Mass{  get  {    /* .. */  }  set  {    mass_Inverse = value; /* <- shouldn't that be mass_Inverse = 1 / value ? */  }}

##### Share on other sites
What Wan said, with maybe:
set{   if(value==0) mass_Inverse = FLT_MAX;   else mass_Inverse = 1/value;}

With your code, set(2); get() = 1/2;

Also, HasInfiniteMass is always true.

Maybe HasInfiniteMass = (mass==FLT_MAX)?

##### Share on other sites
Argh! Sorry folks and thanks for pointing that out.

Here are the corrected properties:

        public bool HasInfiniteMass        {            get { return mass_Inverse == float.MaxValue || mass_Inverse == 0; }        }        public bool IgnoreGravity        {            get { return ignoreGravity; }            set { ignoreGravity = value; }        }        public float Mass        {            get            {                return mass_Inverse == 0 ? float.MaxValue : 1f / mass_Inverse;            }            set            {                mass_Inverse = value == 0 ? float.MaxValue : 1f / value;             }        }        public float Mass_Inverse        {            get { return mass_Inverse; }            set { mass_Inverse = value; }        }

The "mass_Inverse == 0" is needed because the mass might not be set by default (remains at 0) and therefore infinite mass is assumed.

The drifting problem still remains though when the two bodies are in contact.

1. 1
2. 2
3. 3
Rutin
22
4. 4
5. 5

• 13
• 19
• 14
• 9
• 9
• ### Forum Statistics

• Total Topics
632936
• Total Posts
3009312
• ### Who's Online (See full list)

There are no registered users currently online

×