# Friction... (2D physics)

## Recommended Posts

I just implemented linear friction into my 2D physics engine like this: I take the velocity-components of two colliding bodies, which are parallel to the collision tangent, scale them down a bit and subtract them from the original velocities. The result is quite satisfying...except for a nasty problem that occurs now! :-( There's a strange "sliding" problem. Here's the two demos (seeing things in motion is better than a thousand words) ;-) Click me! See what I mean? Since the box stops sliding to the right, but still spins it just falls down where it is... Now my question: Did I do something wrong with linear friction? Or is only the angular stuff missing? ??? Thanks a lot for your help! again and again ;-)

##### Share on other sites
I don't see any motion just rectangular objects? nothings moving....

##### Share on other sites
Unfortunately I just seem to be getting a few lines on the screen, nothings moving.

##### Share on other sites
Oops, sorry! I forgot to display the controls ;-)

Press BACKSPACE to switch between timesteps / realtime mode
(RETURN proceeds a step)

##### Share on other sites
I think there is a big problem with how your executables work on other people's PC since you switched to DirectX (if I remember correctly you first posted OGL demos). It used to work with GL but your DX demos would output very tiny lines and I put it on Wine failing to emulate some DX features but I get the same result in VMWare so it might be with your code after all.

Here's what I get both with Wine and VMWare (can't reboot right now for confirmation on the real thing sorry):

##### Share on other sites
Huh? Looks all pretty good on my machine :-(
I'm new to DX, so I'm not quite sure how to fix this...can ANYONE see something? ;-)

##### Share on other sites
Quote:
 Original post by VanKurtHuh? Looks all pretty good on my machine :-(I'm new to DX, so I'm not quite sure how to fix this...can ANYONE see something? ;-)

But what I see is not what's supposed to be on screen right? :)

##### Share on other sites
Nope, those lines are actually boxes ;-)

##### Share on other sites
I can't help with the problem but it runs fine here.

##### Share on other sites
Quote:
 Original post by VanKurtNope, those lines are actually boxes ;-)

Works fine under native Windows :) so no problem with your code.
It's looking good! You finally sorted out the impulse problem.

I'd say the friction is not working, and when it seems to be it's just luck. I suppose this is impulse based so what happens if you completely cancel the tangential component of the impulse in your no friction code? This should give you full friction, even too much friction but that's a start... something like J = normal * J.Dot(normal) should do it.

edit: Seeing how well your no friction code works the problem is more likely to come from your friction code. The rigid body part looks fine.

##### Share on other sites
"...is more likely to come from your friction code"
Yes, that's what I'm thinking, too ;-)

But how should friction be implemented? Is my method not correct? Or is correct (->there's a bug in my code)?

BTW: You're able to run DirectX stuff under Linux? Wow, I'm impressed! :-D

##### Share on other sites
Quote:
 Original post by VanKurt"...is more likely to come from your friction code"Yes, that's what I'm thinking, too ;-)But how should friction be implemented? Is my method not correct? Or is correct (->there's a bug in my code)?

I made a mistake in my previous post... You actually do not want to remove the tangential component of the impulse as it will remove all chance of getting any friction :). So it's difficult to tell with no maths or code to check at. The impulse code should be really small, you could maybe post it?

Quote:
 BTW: You're able to run DirectX stuff under Linux? Wow, I'm impressed! :-D

Yes, there's many ways to run it, VMWare5 now emulate DirectX through OpenGL, very nice. Wine works fine too, but strangely enough not with your demo :(.

##### Share on other sites
Here's my ApplyImpulse method (featuring this buggy friction part) ;-)

void CSimulator::ApplyImpulse( CRigidBody *b1, CRigidBody *b2, CVector2 colNormal ){	// Calculate rel. velocity	CVector2 vRelativeVelocity;	CVector2 v1, v2;	v1 = b1->getVelocity() + CVector2( -b1->getVelocityAng()*b1->getColPoint().y, b1->getVelocityAng()*b1->getColPoint().x );	v2 = b2->getVelocity() + CVector2( -b2->getVelocityAng()*b2->getColPoint().y, b2->getVelocityAng()*b2->getColPoint().x );	vRelativeVelocity = v1-v2;	float fCr = 0.5f; //Temporary	// Find impulse	float impulse;	// Thank's to Oliii :-)	float denom_m;	float denom_1;	float denom_2;	impulse =  (-(1+fCr) * (vRelativeVelocity*colNormal));	denom_m = (b1->getInvMass() + b2->getInvMass());	denom_1 = colNormal.DotProduct(globalCorePtr->mMath.FloatCrossProduct((b1->getColPoint().CrossProduct(colNormal))*b1->getInvInertia(), b1->getColPoint()));	denom_2 = colNormal.DotProduct(globalCorePtr->mMath.FloatCrossProduct((b2->getColPoint().CrossProduct(colNormal))*b2->getInvInertia(), b2->getColPoint()));	impulse /= (denom_m + denom_1 + denom_2);		// Calculate changes in velocity for body1 and 2	CVector2 deltaVel1 = (impulse * colNormal) * b1->getInvMass();	CVector2 deltaVel2 = (impulse * colNormal) * b2->getInvMass();		// Friction!?!?!?!  Crappy, cause it doesn't work as it should	CVector2 colTan = colNormal;	colTan.Ortogonalize();	CVector2 projVel1 = globalCorePtr->mMath.ProjectAOnB( &b1->getVelocity(), &colTan );	CVector2 projVel2 = globalCorePtr->mMath.ProjectAOnB( &b2->getVelocity(), &colTan );	CVector2 frictionForce = projVel1 - projVel2;	// Now update body 1	if( b1->getMass() != 0 )	{		// Change linear velocity		b1->changeVelocity( deltaVel1 );		// Change angular velocity		float deltaVelAng1 = (b1->getColPoint().CrossProduct(impulse*colNormal))*b1->getInvInertia();		b1->changeVelocityAng(deltaVelAng1);		// Apply stupid friction		b1->changeVelocity( -frictionForce*0.1f );	}//end if	// Now update body 2	if( b2->getMass() != 0 )	{		// Change linear velocity		b2->changeVelocity( -deltaVel2 );		// Change angular velocity		float deltaVelAng2 = (b2->getColPoint().CrossProduct(impulse*colNormal))*b2->getInvInertia();		b2->changeVelocityAng(-deltaVelAng2);		// Apply stupid friction		b2->changeVelocity( frictionForce*0.1f );	}//end if}//end ApplyImpulse

##### Share on other sites
Can you clarify a few things for me please? :)

In: impulse = (-(1+fCr) * (vRelativeVelocity*colNormal));
I suppose that (vRelativeVelocity*colNormal) is a dot product operator, right?

If I'm not mistaken, the problem is that you only compute the normal impulse (ie. the one that modify the precollision velocity only along the collision normal). If you compute the complete impulse (with its tangential component) you will have an impulse sufficient to completely stop (or reverse the incoming velocity but anyway) not only along the normal of collision but also in the collision plane.

To compute the full impulse you will have to change a few types.
Something like that, should give full dead-on friction.

CVector2 impulse;float denom_m;float denom_1;float denom_2;impulse =  (-(1+fCr) * vRelativeVelocity);	// This is a vector now.denom_m = (b1->getInvMass() + b2->getInvMass());denom_1 = colNormal.DotProduct(globalCorePtr->mMath.FloatCrossProduct((b1->getColPoint().CrossProduct(colNormal))*b1->getInvInertia(), b1->getColPoint()));denom_2 = colNormal.DotProduct(globalCorePtr->mMath.FloatCrossProduct((b2->getColPoint().CrossProduct(colNormal))*b2->getInvInertia(), b2->getColPoint()));impulse /= (denom_m + denom_1 + denom_2);// Calculate changes in velocity for body1 and 2CVector2 deltaVel1 = impulse * b1->getInvMass();CVector2 deltaVel2 = impulse * b2->getInvMass();

Note: do not apply any of your current friction code.
From there you can extract the normal and the tangential components from your impulse. The tangential component being responsible for stopping motion on the collision plane (ie. friction).

##### Share on other sites
Thank's a lot for your help so far!
I just tried what you said (changed impulse to a vector)...
The result is more than funny :-)

Take a look: Click me, please!

Here's the code:
void CSimulator::ApplyImpulse( CRigidBody *b1, CRigidBody *b2, CVector2 colNormal ){	// Calculate rel. velocity	CVector2 vRelativeVelocity;	CVector2 v1, v2;	v1 = b1->getVelocity() + CVector2( -b1->getVelocityAng()*b1->getColPoint().y, b1->getVelocityAng()*b1->getColPoint().x );	v2 = b2->getVelocity() + CVector2( -b2->getVelocityAng()*b2->getColPoint().y, b2->getVelocityAng()*b2->getColPoint().x );	vRelativeVelocity = v1-v2;	float fCr = 0.5f; //Temporary	// Find impulse		OLD CODE	/*float impulse;	float denom_m;	float denom_1;	float denom_2;	impulse =  (-(1+fCr) * (vRelativeVelocity.DotProduct(colNormal)));	denom_m = (b1->getInvMass() + b2->getInvMass());	denom_1 = colNormal.DotProduct(globalCorePtr->mMath.FloatCrossProduct((b1->getColPoint().CrossProduct(colNormal))*b1->getInvInertia(), b1->getColPoint()));	denom_2 = colNormal.DotProduct(globalCorePtr->mMath.FloatCrossProduct((b2->getColPoint().CrossProduct(colNormal))*b2->getInvInertia(), b2->getColPoint()));	impulse /= (denom_m + denom_1 + denom_2);*/	CVector2 impulse;	float denom_m;	float denom_1;	float denom_2;	impulse =  (-(1+fCr) * vRelativeVelocity);	denom_m = (b1->getInvMass() + b2->getInvMass());	denom_1 = colNormal.DotProduct(globalCorePtr->mMath.FloatCrossProduct((b1->getColPoint().CrossProduct(colNormal))*b1->getInvInertia(), b1->getColPoint()));	denom_2 = colNormal.DotProduct(globalCorePtr->mMath.FloatCrossProduct((b2->getColPoint().CrossProduct(colNormal))*b2->getInvInertia(), b2->getColPoint()));	impulse /= (denom_m + denom_1 + denom_2);		// Calculate changes in velocity for body1 and 2	CVector2 deltaVel1 = impulse * b1->getInvMass();	CVector2 deltaVel2 = impulse * b2->getInvMass();		// Friction!?!?!?!  Crappy, cause it doesn't work as it should	CVector2 colTan = colNormal;	colTan.Ortogonalize();	CVector2 projVel1 = globalCorePtr->mMath.ProjectAOnB( &b1->getVelocity(), &colTan );	CVector2 projVel2 = globalCorePtr->mMath.ProjectAOnB( &b2->getVelocity(), &colTan );	CVector2 frictionForce = projVel1 - projVel2;	// Now update body 1	if( b1->getMass() != 0 )	{		// Change linear velocity		b1->changeVelocity( deltaVel1 );		// Change angular velocity		float deltaVelAng1 = (b1->getColPoint().CrossProduct(impulse*colNormal))*b1->getInvInertia();		b1->changeVelocityAng(deltaVelAng1);		// Apply stupid friction		//b1->changeVelocity( -frictionForce*0.1f );	}//end if	// Now update body 2	if( b2->getMass() != 0 )	{		// Change linear velocity		b2->changeVelocity( -deltaVel2 );		// Change angular velocity		float deltaVelAng2 = (b2->getColPoint().CrossProduct(impulse*colNormal))*b2->getInvInertia();		b2->changeVelocityAng(-deltaVelAng2);		// Apply stupid friction		//b2->changeVelocity( frictionForce*0.1f );	}//end if}//end ApplyImpulse

[Edited by - VanKurt on July 11, 2005 9:17:51 AM]

##### Share on other sites
I just checked some literature (not that I understood that much)...but it really seems as if impulse is a vector, not a scalar :-)

That leads me to two questions:

1) Why did everything work fine until now (without friction)?????
2) How do I have to change the code so that impulse becomes a vector? The suggestion from above didn't work (as already mentioned) ;-)

##### Share on other sites
Quote:
 Original post by VanKurtI just checked some literature (not that I understood that much)...but it really seems as if impulse is a vector, not a scalar :-)That leads me to two questions:1) Why did everything work fine until now (without friction)?????2) How do I have to change the code so that impulse becomes a vector? The suggestion from above didn't work (as already mentioned) ;-)

1) Because you were working on the magnitude of vectors. Wich was equivalent in this case. normal * velrel gives you the length of the normal component of velrel and once you had the length of the impulse (normal only) you used to multiply it by the normal vector again so you were back with a vector impulse as expected.

2) It should. The only reason I can see is that your relative velocity is reversed. Can you try vRelativeVelocity = v2-v1; instead of v1-v2?

Note: You can still work with a scalar when calculating the full impulse but it really doesn't make sense :).

##### Share on other sites
I run native windows and I don't see any boxes either.
Just grey, and strange small lines.

GeForce 6600 GT

##### Share on other sites
"The only reason I can see is that your relative velocity is reversed. Can you try vRelativeVelocity = v2-v1; instead of v1-v2?"

Nope, that made everything worse... :-D
This physics stuff can make you totally insane...can't think of anything else...ARGH!!!

##### Share on other sites
Quote:
 Original post by VanKurt"The only reason I can see is that your relative velocity is reversed. Can you try vRelativeVelocity = v2-v1; instead of v1-v2?"Nope, that made everything worse... :-DThis physics stuff can make you totally insane...can't think of anything else...ARGH!!!

I just noticed but, did you update this part of the code as well?
float deltaVelAng1 = (b1->getColPoint().CrossProduct(impulse*colNormal))*b1->getInvInertia();

As well as the reciprocal one for the other body in the pair.
You should now use the impulse directly (ie. CrossProduct(impulse)). I guess you did as it should not compile otherwise, but better safe than sorry.

##### Share on other sites
Ooops :-)
Hadn't changed that - but it compiled without problems nevertheless ^^

The sad news: everything's still messed up :-(
Ahhh, well... I guess I'll have to rewrite that whole crap...umph

##### Share on other sites
Quote:
 Original post by VanKurtOoops :-)Hadn't changed that - but it compiled without problems nevertheless ^^The sad news: everything's still messed up :-(Ahhh, well... I guess I'll have to rewrite that whole crap...umph

Did you try with both velocity directions? :)

##### Share on other sites
Ok let's hunt the bug in case you already tried both velocities.

impulse = impulse.DotProduct(colNormal) * colNormal;

Right after the:

impulse /= (denom_m + denom_1 + denom_2);

You should be back with your no friction code and it cannot fail unless you have a bug in your operators or vector code.

##### Share on other sites
Hey, thank's a lot b34r! Very nice that you're still helping me :-)

"impulse = impulse.DotProduct(colNormal) * colNormal;"
everyting's back to normal (as you predicted) ;-)

The new function (just for reference) looks like this:

void CSimulator::ApplyImpulse( CRigidBody *b1, CRigidBody *b2, CVector2 colNormal ){	// Calculate rel. velocity	CVector2 vRelativeVelocity;	CVector2 v1, v2;	v1 = b1->getVelocity() + CVector2( -b1->getVelocityAng()*b1->getColPoint().y, b1->getVelocityAng()*b1->getColPoint().x );	v2 = b2->getVelocity() + CVector2( -b2->getVelocityAng()*b2->getColPoint().y, b2->getVelocityAng()*b2->getColPoint().x );	vRelativeVelocity = v1-v2;	float fCr = 0.5f; //Temporary	// Find impulse	CVector2 impulse;	float denom_m;	float denom_1;	float denom_2;	impulse =  (-(1+fCr) * vRelativeVelocity);	denom_m = (b1->getInvMass() + b2->getInvMass());	denom_1 = colNormal.DotProduct(globalCorePtr->mMath.FloatCrossProduct((b1->getColPoint().CrossProduct(colNormal))*b1->getInvInertia(), b1->getColPoint()));	denom_2 = colNormal.DotProduct(globalCorePtr->mMath.FloatCrossProduct((b2->getColPoint().CrossProduct(colNormal))*b2->getInvInertia(), b2->getColPoint()));	impulse /= (denom_m + denom_1 + denom_2);	// New line!	impulse = impulse.DotProduct(colNormal) * colNormal;		// Calculate changes in velocity for body1 and 2	CVector2 deltaVel1 = impulse * b1->getInvMass();	CVector2 deltaVel2 = impulse * b2->getInvMass();	// Now update body 1	if( b1->getMass() != 0 )	{		// Change linear velocity		b1->changeVelocity( deltaVel1 );		// Change angular velocity		float deltaVelAng1 = (b1->getColPoint().CrossProduct(impulse))*b1->getInvInertia();		b1->changeVelocityAng(deltaVelAng1);	}//end if	// Now update body 2	if( b2->getMass() != 0 )	{		// Change linear velocity		b2->changeVelocity( -deltaVel2 );		// Change angular velocity		float deltaVelAng2 = (b2->getColPoint().CrossProduct(impulse))*b2->getInvInertia();		b2->changeVelocityAng(-deltaVelAng2);	}//end if}//end ApplyImpulse

What's next? :-)

##### Share on other sites
Quote:
 Original post by VanKurtHey, thank's a lot b34r! Very nice that you're still helping me :-)[...]What's next? :-)

No problem, that's what I'm here for when I'm not trying to get help myself ;).
Ok so it looks like the tangential impulse is causing troubles... Right now you have a full impulse that should bring the velocity of the collision point to 0 in a perfectly inelastic collision.

What you can try:

- Setting fCr to 0.f if not already just so that the results are clearer.
- Split the full impulse into it's tangential and normal components.

normalImpulse = impulse.DotProduct(colNormal) * colNormal;
tangentImpulse = impulse - normalImpulse;

The full impulse is then recomposed as impulse = normalImpulse + tangentImpulse * kPseudoFriction;

With kPseudoFriction = 0 you have no friction, everything should be like it is right now.

- Try ramping kPseudoFriction from 0 to 1 by small increments and see wether you can get anything meaningful at all.

From there we may be able to figure where the problem lies.

## Create an account

Register a new account

• ### Forum Statistics

• Total Topics
628356
• Total Posts
2982251

• 10
• 9
• 13
• 24
• 11