Sign in to follow this  

What am I doing wrong? ( Closing Velocity )

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

If you intended to correct an error in the post then please contact us.

Recommended Posts

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[i].penetration > 0 )
{
if( GetClosingVelocity( contact[i].pBody1, contact[i].pBody2 ) > 0 )
{
ResolveContact( contact[i] );
}
}
}





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]

Share this post


Link to post
Share on other sites
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)

Share this post


Link to post
Share on other sites
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?

Share this post


Link to post
Share on other sites
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?

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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]

Share this post


Link to post
Share on other sites
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.


Share this post


Link to post
Share on other sites
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]

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
Sorry John. But I missed your reply. And just saw your message.

Quote:
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.


Sorry, when I refer to the Sep-Axis there, I meant the axis where the collision has the least amount of penetration. I know I used the wrong term. What I meant here was the following

Image and video hosting by TinyPic

Frame 1 :

A Vel = (-6,0)
B Vel = (5,0)

Normal for use within closing vel test = (1,0) or (-1, 0)
pick (1,0) as its most opposite A's Vel

ClosVel = Dot( B-A, (1,0) );
= Dot( (11,0), (1,0) );
= positive, so closing

Frame 2 :

A Vel = ( 6,0)
B Vel = (-5,0)

Normal for use within closing vel test = (1,0) or (-1, 0)
pick (-1,0) as its most opposite A's Vel

ClosVel = Dot( B-A, (-1,0) );
= Dot( (-11,0), (-1,0) );
= positive, so closing

Share this post


Link to post
Share on other sites
Well, if you have two bodies colliding what matters is: the normal is related to which body?
If it is related to the first body, then let's say that by definition, it points outside the first body. This is all we need to know. You could choose the normal that points ouside the second body: the choice is arbitrary.

//contact_normal points outside volume1
bool intersection( Bounding_volume const & volume1, Bounding_volume const & volume2, Vector3 & contact_normal );

If the contact_normal points outside volume1, then if body2 is traveling further inside body1, we know that they're not separating: that's the opposite.


if( intersection( volume1, volume2, contact_normal ) )
{
Vector3 relative_velocity = substract( velocity2, velocity1 );
//relative velocity of body 2 to body 1

if( dot_product( relative_velocity, contact_normal ) < 0 )
{
//body 2 is going further inside body 1
}
else
{
//the two bodies are in contact, but are separating
}
}


In short, the value stored in contact_normal should clearly respect a convention. I mean a convention: you should always return the value of the normal pointing outside volume1, if it is the convention you chose. Now apply that convention in the examples you provided, and see what I mean. Next change the convention (normal pointing outside volume2 and relative_velocity = substract(velocity1, velocity2)), and see what I mean.

Share this post


Link to post
Share on other sites
Quote:
Original post by johnstanp
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?


Share this post


Link to post
Share on other sites
At the moment my SAT test method just returns the axis, and so the contact normal doesnt follow a convention. So I'll need to fix that.

I plan to have it so that the contact normal is always facing A, and that B will have an impulse of -Normal, such as in the following examples.

Image and video hosting by TinyPic

So now I need a way to look at the collision of A and B, and return the axis in the form of a normalized contact normal that is always facing A. This part doesnt need to take into consideration the velocities does it? I plan to do this by using the minimumX of A and B ( where the X axis is the SAT axis ) to first figure out if a is on the left or right of B, and then dot it with the current axis to see if it is pointing the right way. Any suggestions?

Share this post


Link to post
Share on other sites
Quote:
Original post by maya18222
At the moment my SAT test method just returns the axis, and so the contact normal doesnt follow a convention. So I'll need to fix that.

Which axis?
If the two bodies do collide, then there's no separating axis. If they do not collide, then there's no need of that kind of information.
You need a contact normal when a collision is detected: not an axis. Unless, by "axis", you meant "vector", which would imply all vectors are axes and only axes.
To do collision detection and response, you must be able to generate contact information ( normal and contact point(s)/segment/polygon) when there is a collision detected.
But why should we go further? You posted a figure with two possible normals: have you at least tested my algorithm with an arbitrary choice of contact normal between the two possibilities? Start there first.

Share this post


Link to post
Share on other sites
When I refer to the axis from the Sat test, i mean the line marked in red. Which when a collision has occured, is the axis of minimum penetration of the objects. My sat test is defined to return a bool, and takes a reference as a parameter to a contactNormal which is set if a collision occurs.


bool Sat( object o1, object o2, Vector2& ContactNormal )
{
if( collision ) {

// figure out which way axis is to point, ie

// ContactNormal = axis;

// or

// ContactNormal = -axis;

return 1;
}
else return 0;
}












Now that line marked in red can point in 2 directions, when that line is set to the correct direction, i refer to that as the contact normal, which is the arrow marked in red.

Quote:

But why should we go further? You posted a figure with two possible normals: have you at least tested my algorithm with an arbitrary choice of contact normal between the two possibilities? Start there first.


I dont know what you mean. There is only one normal in those diagrams, marked by the red arrow. That is, to point towards A by convention, as in the diagram.

My problem at the moment is figuring out which way the axis should point when set for the contact normal. I've defined the fact that it needs to point towards A by convention, but I need a way to calculate this, as that red line ( which I refer to as the axis of collision ) when passed as the contact normal, could be -axis or +axis, shown above in the source code.

Doesnt this need to be calculated before moving onto the closing velocity test which I believe you're refering to in the following reply

Quote:
have you at least tested my algorithm with an arbitrary choice of contact normal between the two possibilities? Start there first


What Im trying to say is that before I use the closing velocty test, provided there is a collision, I first need to get the contact normal for that collision, pointing towards A.

All I have at the moment is the axis, ( shown by the red line ). I need to now get a contact normal from that, which always points towards A.

That is, I need to figure out should the Contact Normal be

ContactNormal = axis;

or

ContactNormal = -axis;

Share this post


Link to post
Share on other sites
Quote:
Original post by maya18222
What Im trying to say is that before I use the closing velocty test, provided there is a collision, I first need to get the contact normal for that collision, pointing towards A.

All I have at the moment is the axis, ( shown by the red line ). I need to now get a contact normal from that, which always points towards A.

That is, I need to figure out should the Contact Normal be

ContactNormal = axis;

or

ContactNormal = -axis;


You know the position of the two boxes (I mean the value of their respective centers).
Choosing the orientation that points towards the inside of A (towards its center), is then easy (litterally).

if( dot_product( axis, centerA - centerB ) > 0 ) contact_normal = axis;
else contact_normal = -axis;

Share this post


Link to post
Share on other sites
Quote:
Original post by maya18222
Yeah, that was my first thought, but then I figured it might not work for every shape. But I'll see how it goes.

The shapes must be convex, of course. Why should it work for every shape? Because it should work for every shape or is it because you do have some shapes that are not convex?

I have a question: how could you use SAT for a non-convex shape ("every shape") without decomposing it? What does an axis mean in that case?
If you want an algorithm that will work for every possible case, you'll need something more general and guess what, harder to understand and implement.
Unless you must take into account all possible cases, you'd better stick with simple cases, with convex shapes.

Share this post


Link to post
Share on other sites
All my shapes will be convex, but I was thinking more objects where the CM might not be in the center of the object, for certain effects, and where the position would always be the CM. Unless of course that is not the case.

But anyway, forget all that. I'll get the simple case working first :)

Share this post


Link to post
Share on other sites
Quote:
Original post by maya18222
All my shapes will be convex, but I was thinking more objects where the CM might not be in the center of the object, for certain effects, and where the position would always be the CM. Unless of course that is not the case.

But anyway, forget all that. I'll get the simple case working first :)


If the body is convex, the center of mass, even if it differs from the geometrical center, is inside the shape.
I don't want to look picky, but I simply feel that any misconception should be corrected for the benefit of everyone.

Share this post


Link to post
Share on other sites

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

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this