Instantaneous vs. continuous friction

Started by
4 comments, last by alex_myrpg 16 years, 11 months ago
Hello, I'm writing a physical solver to handle collisons between objects. The friction is confusing to me, and I'm having difficulty finding the information that I need. 1) Every example of how to calculate normal force involves a moving object on a flat surface. What if I want to find the normal force between two objects at the instant of collision? Or would that be more properly called the normal impulse? 2) Do I need to treat sustained contact differently than instantaneous collisions, or could I get by with always using the last frame interval for all collisions. I'm aware that my friction code is wrong, since it doesn't account for dT. 3) Also, would the coefficient of restitution have any effect on the normal force at the contact point? Here's what I have so far:

vec2 para1, perpen1;
actor1->velocity.resolve(contact.normal, para1, perpen1);
vec2 para2, perpen2;
actor2->velocity.resolve(contact.normal, para2, perpen2);

// Formula for collision (uses coefficients of restitution and friction)
double m1 = 1.0 / actor1->inverseMass;
double m2 = 1.0 / actor2->inverseMass;
double m = m1 + m2;
double c = actor1->elasticity * actor2->elasticity;
double fS = actor1->staticFriction * actor2->staticFriction;
double fK = actor1->kineticFriction * actor2->kineticFriction;

double normalDiffV = (para1 - para2) * contact.normal;
double tangentDiffV = (perpen1 - perpen2) * contact.normal.right();
double frictionImpulse;

if(tangentDiffV < -normalDiffV * fS)
    frictionImpulse = -tangentDiffV;
else
    frictionImpulse = -tangentDiffV * fK;

actor1->velocity = ((c + 1) * m2 * para2 + para1 * (m1 - c * m2))
    / (m1 + m2) + perpen1 * (1.0 + frictionImpulse / m1);
actor2->velocity = ((c + 1) * m1 * para1 + para2 * (m2 - c * m1))
    / (m1 + m2) + perpen2 * (1.0 - frictionImpulse / m2);

Advertisement
Hey, I'll try to do my best to explain this and tell you how I would implement it in an engine, but don't necessarily take it as the only way to do it, I ought to say.

1) To find the normal force at the instant of collision would require you to know the time. The impulse can just be calculated by the change in momentum of the colliding object.

2) To start, why would you have sustained collisions in the first place? In reality, all collisions are sustained for a very short period of time, but the only case I can think of where it *might* be useful to calculate in an engine/solver is where at least one of the materials is elastic, but this is handled more easily by the coefficient of restitution anyway, so it would seem wrong to take into account time for this. Perhaps you are referring to another situation however...

3) The normal force can be defined as the force exerted by an object on an adjacent object to stop this adjacent object passing through (entering) the original object. The coefficient of restitution *would* have an effect on the normal force in this case, since the normal force must be less than the force exerted by the object if it is to give elastically. But then you have to worry about how the normal force changes with time, so really the simplest way is to use the coefficient of restitution to calculate the rebound speed.

Sorry if these turn out to be misleading - I haven't actually tried them out, but they do seem like the simplest solutions to me if I were coding an engine like this. Anyway, hope it helps!
Quote:
1) To find the normal force at the instant of collision would require you to know the time. The impulse can just be calculated by the change in momentum of the colliding object.


So it sounds like I will need to find two normal forces, one per change in momentum for actor1 and one for actor2.

1) Calculate change in actors' momentum along normal of collision.
2) Use that change in momentum as normal force/impulse/something.
3) Calculate change in actor's momentum along tangent of collision using the normal impulse from step 2.

Quote:
2) To start, why would you have sustained collisions in the first place?


I was hoping to handle sliding and rolling with the same code, but it seems that sliding and rolling friction would require dt somewhere.

Quote:
3) The normal force can be defined as the force exerted by an object on an adjacent object to stop this adjacent object passing through (entering) the original object. The coefficient of restitution *would* have an effect on the normal force in this case, since the normal force must be less than the force exerted by the object if it is to give elastically. But then you have to worry about how the normal force changes with time, so really the simplest way is to use the coefficient of restitution to calculate the rebound speed.


So it sounds like you are saying that I can indeed use the change in velocity * mass for an object to determine the normal impulse. I'll code that up and see what happens.

Ok that sounds alright mainly. Just to clarify, a change in momentum is an impulse, which is also force x time of action.

For point 2), it would seem that sliding doesn't require time at all, since the actor is continuously in contact with the other object. Also, I'm not totally sure on this point but for rolling can't you just set the coefficient of restitution to zero and it will all work out?

If you have any more questions after you code it up, feel free to ask.
Wow! So I got it working and I discovered a fascinating reason that I don't have to explicitly code any awareness of time issues.

// Get components of velocity that are along normal axis// and components that are tangent to itvec2 Nvs1, Tvs1;actor1->velocity.resolve(contact.normal, Nvs1, Tvs1);vec2 Nvs2, Tvs2;actor2->velocity.resolve(contact.normal, Nvs2, Tvs2);// Calculate combined values of coefficients and massdouble m1 = 1.0 / actor1->inverseMass;double m2 = 1.0 / actor2->inverseMass;double m = m1 + m2;double e = actor1->elasticity * actor2->elasticity;double fS = actor1->staticFriction * actor2->staticFriction;double fK = actor1->kineticFriction * actor2->kineticFriction;// The normal velocity for actors after restitution// The formula is from http://en.wikipedia.org/wiki/Coefficient_of_restitutionvec2 Nvf1 = ((e + 1) * m2 * Nvs2 + Nvs1 * (m1 - e * m2)) / m;vec2 Nvf2 = ((e + 1) * m1 * Nvs1 + Nvs2 * (m2 - e * m1)) / m;// The delta of normal velocity for actors over the span of the collisiondouble Nvd1 = (Nvf1 - Nvs1) * contact.normal;double Nvd2 = (Nvf2 - Nvs2) * contact.normal;// Total magnitude of tangential velocityvec2 Tvd = Tvs1 - Tvs2;// The tangent velocity for actors after kinetic frictionvec2 Tvf1 = Tvs1 + Tvd * -fK * Nvd1;vec2 Tvf2 = Tvs2 + Tvd * -fK * Nvd2;// Final actor velocity is final normal component + tangent componentactor1->velocity = Nvf1 + Tvf1;actor2->velocity = Nvf2 + Tvf2;


The static coefficient of friction isn't coded yet, but I'm pretty sure that I'm on the right track. I was not understanding why I didn't need to code dT, but then it hit me!

I do the following loop for object updates:

0) Warm up objects (set initial states and call Update once)
1) Have objects update position from velocity, very simple, no real object behaviors. This method takes a dT and only changes X.
2) Detect collisions, scaling object motions back as needed, by redoing step 1 with smaller dT.
3) Update objects' velocity using accelerations and game object specific code. This will be where accelerations are applied for things like homing missiles and other stuff. This method uses the last dT that was given from step 1, and only changes X'.
4) Resolve collisions.

So if my framerate varies, so will the accelerations in velocity! A large frame interval will cause a large acceleration and a small frame interval will cause a small acceleration. The modified velocities affect the normal impulse magnitude. In fact, a framerate of zero will cause no velocity modification, causing the normal impulse to be zero. Anyhow, the normal impulse is used to modulate how much friction is applied. Obviously, since I'm not using RK4, my simulation is crap, but it looks good enough now. Thanks!

Not sure if I fully understand your code there, but that's not a problem - I'm glad it's working for you now! :)

This topic is closed to new replies.

Advertisement