Jump to content
  • Advertisement
Sign in to follow this  
Lolmen

Contact solver, physics goes crazy :D

This topic is 3864 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

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 this post


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


Link to post
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 this post


Link to post
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 this post


Link to post
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 this post


Link to post
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 this post


Link to post
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 this post


Link to post
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.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!