What am I doing wrong? ( Closing Velocity )

Started by
19 comments, last by johnstanp 13 years, 6 months ago
My physics loop is set up such that it only resolves collisions where the 2 objects within the collision are closing in on each other. This prevents a collision from being resolved, that may be reversed again in the next frame if there was still penetration, due to the fact that the impulse may take a fgood few frames to resolve the penetration.

for( all contacts in contact list ){   if( contact.penetration > 0 )   {      if( GetClosingVelocity( contact.pBody1, contact.pBody2 ) > 0 )      {          ResolveContact( contact );      }   }}


But I cant seem to get the GetClosingVelocity() function to work for all situations, and often objects get stuck in one another, I believe due to collisions being resolved and then reversed indefinatly. The function should return a positive value if the objects are closing in on each other, and a negative value when they're separting, both in relation to the contact normal. Where the normal is always given in relation to body A.

Situation 1
-----------

Involves 2 bodies that are deeply penetrating each other, where A is going left and B is going right. These are separating as one is going left and one right, and the contact normal is relative to A, so would be ( 1, 0 )

VelocityA = ( -10, 0 );
VelocityB = ( 11, 0 );

ClosingVelocity = Dot( VelocityA - VelocityB, ContactNormal );
= Dot( ( -21, 0 ), ( 1, 0 ) );
= ( -21 )

So this produces the correct result of them not closing in on each other as the result is negative, and so no collision needs to be resloved


Situation 2
-----------

Involves 2 bodies that are deeply penetrating each other, where A is going up and B is going down. These are separating as one is going up and one down, and the contact normal is relative to A, so would be ( 0, -1 )

VelocityA = ( 0, 10 );
VelocityB = ( 0, -11 );

ClosingVelocity = Dot( VelocityA - VelocityB, ContactNormal );
= Dot( ( 0, -21 ), ( 0, -1 ) );
= ( 21 )

So this produces the incorrect result of them closing in on each other as the result is positive, when they're actually separating, and so a collision will to be resloved that shouldnt. and the impulse will flip flop each frame




[/source]
Advertisement
So, you may have found a fundamental flaw in your approach. This could work, but what would have to happen is that when you resolve the collision, e.g., the moment you first detect and resolve the collision (when the objects are closing), then in addition to changing the velocity you would have to physically move the objects away from each other to guarantee they are not interpenetrating at the next frame (e.g., while moving apart). There are also some other approaches to detecting the collisions to begin with that may be more robust than your closing velocity approach. And some approaches to resolving collisions do allow the objects to remain interpenetrated for a few frames...basically they push the objects apart over a few frames until the penetration depth becomes zero. Note that one benefit of some of the other approaches is that you wouldn't necessarily have to guarantee all objects are 100% separated at the start of the game/simulation.

There are some good background/educational slides in the Essential Math physics GDC tutorials, available online via a link in this sticky thread:

List of physics engines and reference material (search on "Essential Math" for the tutorials link. Once you get to the ES page, you'll have to hit "tutorials" again on the left side to get to the tutorials page)
Graham Rhodes Moderator, Math & Physics forum @ gamedev.net
Yeah, I already had a look at those slides (Essential Math ones), and they dont seem to resolve penetration, they allow it and let the impulse correct it. But they dont mention how they solve the problem that I seem to be coming across.

That is, when you resolve a collision where the calculated impulse isnt large enough to remove the penetration in a single frame, which on the next frame gets reversed, and the objects get stuck within each other.

Do all physics libraries resolve penetration by moving the objects out of eachother by a position change?
Simply compute the closing velocity this way:
closing_velocity = dot( velocityB - velocityA, contact_normal )

You want to know if body B is moving away from body A. If the relative velocity of body B to body A has a positive component along the contact normal relative to body A, then body B is moving away from body A. Test that with your examples.
Are you sure your contact normal is always pointing outside of body A? And that your impulses make the two bodies reverse their components along the contact normal?
Thats what I'm already doing. Just the other way around, by flipping the sign.
maya, I will always recommend adding some "debug visualization" into the simulation, which can aid in debugging problems. For example, you may want to draw some lines to visualize the detected point of contact, the current velocity vector, the contact normal...things like that. Then may enable stepping through the simulation one time step at a time with the keyboard. Sometimes just visualization the vectors you are working with can help you to figure out what is going wrong.
Graham Rhodes Moderator, Math & Physics forum @ gamedev.net
Quote:Original post by maya18222
Thats what I'm already doing. Just the other way around, by flipping the sign.

You don't do the same thing.
Your logic is wrong.
And I was asking those last two questions because even if your logic was right, we would have no way to know if the contact normals are correctly computed, no way to know if your impulses are correctly computed. Your logic could be right, but the bug(s) could be somewhere else.

And finally, using my formula, you would clearly see that in both cases, the component of the closing velocity along the normal is positive, meaning the bodies are separating...

Situation 1
-----------

VelocityA = ( -10, 0 );
VelocityB = ( 11, 0 );

ClosingVelocity = Dot( VelocityB - VelocityA, ContactNormal );
= Dot( ( 21, 0 ), ( 1, 0 ) );
= ( 21 )

Bodies A and B are separating.


Situation 2
-----------

VelocityA = ( 0, 10 );
VelocityB = ( 0, -11 );

ClosingVelocity = Dot( VelocityB - VelocityA, ContactNormal );
= Dot( ( 0, -21 ), ( 0, -1 ) );
= ( 21 )

Bodies A and B are separating.

You should try to understand why I compute the closing velocity the way I do: your formula is obviously wrong.

[Edited by - johnstanp on September 28, 2010 5:17:26 PM]
Thanks John. I'll try it with your code. But confused though, as all the other sources I see say to calculate it with A-B as opposed to B-A. But as you showed, it solves my problem.

hmmmm.

Can I ask if in your code you solve penetration by asjusting position or you just let the velocity do it over time?

I've come a cross a few other issues too.

This is a 2D demo, and im using the sat test for collision detection. But in the case of a square colliding with another square, each square has 2 identical separating axis', just with the direction pointing in different ways. ie the the top and bottom edge, and the left and right edge. The obvious way to choose the contact normal would be to choose the edge with the normal thats most opposite to A's velocity.

This works for the first collision. But then if the penetration isnt fixed in one frame, there is still a collision detected, and using the technique above, will then cause the normal chosen to make the object reverse back, as the contact normal is now the reverse of what it was in the last frame. Causing the 2 objects to appear to stick.


Why velocityB - velocityA?
Because it is the relative velocity of body B to body A. To remember it, just remember that velocityA - velocityA is equal to zero: body A is not moving relatively to itself. So substracting velocity A from any velocity gives the relative velocity to body A.
Since the normal points outside body A, if [edit]the relative velocity of body B to body A[/edit] has a component positive along that normal, it just means that body B is moving further away from body A.

I prefer predicting times of collision to avoid interpenetration: this method is a little more complex for even the simplest shapes (OBB for example).

[Edited by - johnstanp on September 30, 2010 2:40:48 PM]
Quote:Original post by maya18222
Thanks John. I'll try it with your code. But confused though, as all the other sources I see say to calculate it with A-B as opposed to B-A. But as you showed, it solves my problem.

hmmmm.

Can I ask if in your code you solve penetration by asjusting position or you just let the velocity do it over time?

I compute the collision impulse: so the component of velocityB - velocityA along the contact normal, has its sign reversed provided there was a colliding contact. This is an adjustment of velocities.
To test if your computing is right, test that change of sign, I mean test that dot_product( velocityB - velocityA, contact_normal ) after the collision, has a different sign than before the addition of the collision impulse.

Quote:Original post by maya18222
I've come a cross a few other issues too.

This is a 2D demo, and im using the sat test for collision detection. But in the case of a square colliding with another square, each square has 2 identical separating axis', just with the direction pointing in different ways. ie the the top and bottom edge, and the left and right edge. The obvious way to choose the contact normal would be to choose the edge with the normal thats most opposite to A's velocity.


There's a contradiction in your second sentence: if there exists a separating axis then the two bodies are not colliding. There's no collision when at least there exists a separating axis. So there's a collision when there doesn't exist a single separating axis.

Quote:Original post by maya18222
This works for the first collision. But then if the penetration isnt fixed in one frame, there is still a collision detected, and using the technique above, will then cause the normal chosen to make the object reverse back, as the contact normal is now the reverse of what it was in the last frame. Causing the 2 objects to appear to stick.


Well, you should first be able to certify that your collision detection algorithm is working properly. Without seeing your code nor a concrete situation, I can't help you efficiently.

This topic is closed to new replies.

Advertisement