# Contact solver, physics goes crazy :D

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

## Recommended Posts

I try to fastly implemet some sort of ball physics for 2d case. And because I'm not so Enstein in physics, I don't know how exactly I suppouse to solve that when I also have angular velocity... Maybe someone who has write that know where I have the bug? Code listed below... [Edited by - Lolmen on February 14, 2008 9:59:43 AM]

##### Share on other sites
it's often a sign problem. Try without the last part of the collision response first and just the overlap test, then with the dynamic response, without rotational components, then with rotational components.

##### Share on other sites
The separation works just fine, same for rotational and not.
Dynamic test without rotational components it's same, and balls doesn't doing something like staple or glue (usually sign problem), they just explodes from each other like have tons of energy. (impulses problem)

Because I'm not physician and try it out by slides from Erin Catto, I'm don't usderstand much and not see how else I can avoid problem.

##### Share on other sites
Why not use Erin Catto's excellent Box2d library?

http://www.box2d.org/

Edit: BTW, a "physician" is a doctor of medicine, "physicist" is the word you want.

##### Share on other sites
Using box2d doesn't make me independent and it's not exactly what I'm need.
btw it takes time to learn all stuff to manage objects or writing wrappers.
It's also I think not too smart to use library just for 10 balls physics :D

##### Share on other sites
So finally I rewrite it to make more flexibly and clear, but still dunno what potencially can be wrong here...

void ResolveCollision( CCircle *A, CCircle *B, contact_t info ){	// compute contact in local space	Vector ra = info.position - A->GetOrigin(); // circles have one contact point	Vector rb = info.position - B->GetOrigin();	// compute velocities	Vector va = A->GetVelocity() + ra.Perp() * A->m_flAngularVelocity;	Vector vb = B->GetVelocity() + rb.Perp() * B->m_flAngularVelocity; 	// relative velocity at contact	Vector dv =  vb - va;		Vector N = info.normal; // collision normal	float vn = dv.Dot(N);		float m1 = 1.0f / A->GetMass();	float m2 = 1.0f / B->GetMass();	float m = (m1 + m2);		// separation        // overlaps? I'm using sweep vs static test	if( vn > 0.0f || info.entire_range ) // both boolean test mark overlapping	{		Vector D = N * info.separation; // use penetration depth		D *= 0.5f; // penetration relaxing? :D		Vector D0, D1;                // should I count rotations and velocities here?		if (m1 > 0.0f)		{			D0 = D * (m1 / m);			A->SetOrigin( A->GetOrigin() + D0 );		}		if (m2 > 0.0f) 		{			D1 = D * (m2 / m);			B->SetOrigin( B->GetOrigin() - D1 );		}	}		float friction_s = A->GetCOF() * B->GetCOF();	float elasticity = A->GetCOR() * B->GetCOR();	Vector J = ( ( elasticity * vn ) * N ) * friction_s;	A->m_vVelocity += J * (m1/m);	B->m_vVelocity -= J * (m2/m);	A->m_flAngularVelocity += Cross(ra, J) / A->m_flInertia;	B->m_flAngularVelocity -= Cross(rb, J) / B->m_flInertia;}

It's works and I think it works fun, not sure how much it's correct, but I'm doesn't seen anything what annoys me, but something still unnatural.

[Edited by - Lolmen on February 14, 2008 10:11:53 AM]

##### Share on other sites
A->m_vVelocity += J * (m1 / m2);B->m_vVelocity -= J * (m2 / m);

supposed to be m1/m?

##### Share on other sites
Yep, but that not fix crazy spinning stuff...

##### Share on other sites
One guy told me that the problem is in computing the "Normal Impulse"
and probably because of absence "Tangential Impulse".
But, how can I calculate and apply them right?

Oliver, maybe you can help me?

Thanks for every one in advance.

##### Share on other sites
there were too many errors, so should be easier for me to directly fix the code...

void ResolveIntersection( CCircle *A, CCircle *B, contact_t info ){	// we have penetration	if(info.separation > 0.0f)	{		float ma = 1.0f / A->GetMass();		float mb = 1.0f / B->GetMass();		float m = (ma + mb);				// EDIT: for consistency with relative velocity, 		// normal should be pointing from A centre towards B centre.		// so that in both cases, A is the reference body, B is the acting body.		// you should have to swap the normal around.		Vector PA = A->GetOrigin();		Vector PB = B->GetOrigin()		assert(info.normal.dot(PB - PA) > 0.0f); // should always be true				float relaxation = 0.5f;		Vector D = (info.normal * info.separation) * relaxation; // spearation vector			// separation vectors		Vector DA = D * (ma / m);		Vector DB = D * (mb / m);				// separate		A->SetOrigin( PA - DA );		B->SetOrigin( PB + DB );	}}void ResolveCollision(CCircle *A, CCircle *B, contact_t info){	// intersection relaxation	ResolveIntersection(A, B, info);	// compute contact in local space	// EDIT: contact points should be one for each body, especially when you have intersection.	Vector ra = info.positionA - A->GetOrigin(); // circles have one contact point	Vector rb = info.positionB - B->GetOrigin();	// compute velocities	Vector va = A->GetVelocity() + ra.Perp() * A->m_flAngularVelocity;	Vector vb = B->GetVelocity() + rb.Perp() * B->m_flAngularVelocity; 	Vector v =  vb - va;	// relative velocity at contact	Vector n = info.normal; // collision normal		// impact speed	float vn = v.Dot(n);	// objects are seperating. do not compute a collision and friction impulse.	if (vn > 0.0f) 		return;		float ma = 1.0f / A->GetMass();	float mb = 1.0f / B->GetMass();	float m  = (ma + mb);	float ia = A->m_flInertia;	float ib = B->m_flInertia;		// EDIT : more accurate representation fo the combined friction, although not accurate enough.	float elasticity = (A->GetCOR() + B->GetCOR()) * 0.5f;	// calculate collision impulse	float ta		= ra.cross(info.normal); // 'a' term	float tb		= rb.cross(info.normal); // 'b' term	float c			= vn / (m + (ta*ta)*ia + (tb*tb)*ib); // final impulse		// collision impulse	Vector C = (c * elasticity) * n;		// friction impulse (0 by default).	// EDIT : compute friction impulse separately	Vector F(0, 0);		if(1)	{		// average friction		float friction = (A->GetCOF() + B->GetCOF()) * 0.3f;				// direction for friction.		n = info.normal.Perp();		if(vab.dot(n) > 0.0f) n *= -1.0f; // flick around if wrong direction.			float vn		= v.Dot(n);			float ta		= ra.cross(n);		float tb		= rb.cross(n);		float f			= vn / (m + (ta*ta)*ia + (tb*tb)*ib);				// friction impulse		F = (f * friction) * n;	}	// combined impulse.	Vector J = C + F;	// EDIT : error with the unit consistency	A->m_vVelocity -= J * ma;	B->m_vVelocity += J * mb;	// EDIT : error with the unit consistency	A->m_flAngularVelocity -= Cross(ra, J) * ia;	B->m_flAngularVelocity += Cross(rb, J) * ib;}

try that. The signs should be consistent now, as well as the units and values. For sign checks, paper and pen usually best.

I've marked with EDIT tags important things.

1. 1
2. 2
Rutin
23
3. 3
4. 4
5. 5
khawk
14

• 9
• 11
• 11
• 23
• 11
• ### Forum Statistics

• Total Topics
633653
• Total Posts
3013158
×