Jump to content
  • Advertisement
Sign in to follow this  
Zzet

The mystery of the see-saw bouncing polygon

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

Well, I have a 2D collision system working great (major thanks to oliii!), however I have one particular problem...actually, I won't describe it, i'll show you: http://www.zen111944.zen.co.uk/vids/weirdbouncing_xvid.avi (1.82MB, XviD) Basically this problem occurs whenever a polygon of 5 or more edges comes to rest on an immovable object. Friction is about 0.2 and elasticity is really low at 0.1, and the masses are all quite low. I have a theory that if the bounds of the polygon on the collision plane are beyond that of the interval used for calculating contacts, it can cause this to occur, but I confess I don't know how to proceed if that's true. Any help is appreciated, and apologies for creating a new thread about this instead of continuing my old one, but it's quite a different problem I think!

Share this post


Link to post
Share on other sites
Advertisement
How are you responding to collisions? Are you applying impulses to contact points, or something else? Bouncing shapes is actually a pretty common problem for collision response on immobile objects, especially for impulse based methods, but that it would only occur on many-sided polygons seems odd.

Share this post


Link to post
Share on other sites
The reason why it breaks for objects with more than 5 sides is because at that point, it takes a relatively small amount of force to cause the object to roll (think octagon vs. triangle). This bouncing is there on the triangles, but it is below the threshold determined by the way the objects is shaped.

How are you resolving collisions? How are you calculating the moments of inertia for the objects? this is important information to know if we are going to help you.

Share this post


Link to post
Share on other sites
Each time a contact occurs, the velocity of the point of contact on each object is calculated and the response given as an impulse appropriate to the friction/elasticity/inertia/mass. Inertia for each polygon is pre-calculated and stored as a variable, and never changes. Could this be the problem?

In the example video above, each shape is created and in doing so, the inertia is calculated along with the inverse inertia (used in the actual calculation). The method I use:


private void calculateInertia()
{
float denom = 0.0f;
float numer = 0.0f;
int Anum = poly.vertices.length;

for(int j = Anum-1, i = 0; i < Anum; j = i, i ++)
{
Vector P0 = poly.vertices[j];
Vector P1 = poly.vertices;

float a = Math.abs(P0.getCrossProduct(P1));
float b = (P1.getDotProduct(P1) + P1.getDotProduct(P0) + P0.getDotProduct(P0));

denom += (a * b);
numer += a;
}
inertia = (mass / 6.0f) * (denom / numer);
if (inertia > 0.0001f) { inverseInertia=1/inertia; }
else { inverseInertia = 0.0f; }
}




poly refers to the polygon I use to display the shape, which has an array of vertices (position vectors). inertia and inverseInertia are member variables.

I grabbed this from a forum post explaining about inertia; unfortunately I forget which one. Should the inertia be calculated each time for the collision point?

Share this post


Link to post
Share on other sites
Your method of calculating intertia looks sound, so that's not the problem, and you shouldn't need to recalculate it every frame or when there is a collision (because there is only one rotational axis in 2D).

Can you explain more explicitly how you are resolving collisions, specifically with how you calculate the relative velocity at the point of contact, as well as the impulse determination.

There is also a posibility that this might have something to do with the point/normal you are supplying the collision response system. How are you doing that? also, do you allow for multiple contact points between two objects (such as when an edge rests on an edge).

Share this post


Link to post
Share on other sites
There are more or less two methods that govern the entire response in my code. The first calculates the impulse, the second applies it to the object.

The first method; impulse calculation given two physics-responding objects (AbstractPhysicsObject a and b), a relative contact point on each of those objects (Vector aContact and bContact) and the minimum translation vector that is basically the normal of the collision (Vector N).


public static void collideBodies(AbstractPhysicsObject a, AbstractPhysicsObject b, Vector aContact, Vector bContact, Vector N)
{
Vector N = Nun.getDivide((float) Math.sqrt(Nun.getDotProduct(Nun)));

Utilities.log("A contact="+aContact+" B contact="+bContact+" N="+N);
//contact points are already relative to the centre of mass
Vector Ra = aContact;
Vector Rb = bContact;

//velocities at the contact point
Vector Va = a.velocity.getAdd(Ra.perp().getMultiply(a.angularVelocity));
Vector Vb = b.velocity.getAdd(Rb.perp().getMultiply(b.angularVelocity));
Utilities.log("A contact velocity="+Va+" B contact velocity="+Vb);

//relative velocities
Vector V = (Va.getSubtract(Vb));
float vn = V.getDotProduct(N); //velocity along normal, or impact velocity
Utilities.log("Relative impact velocity = "+V+" ...along normal = "+vn);
if (vn > 0.0)
{
//objects moving away from eachother
Utilities.log("Objects are moving away, no collision.");
return;
}

//collision impulse
float numer = -(1.0f+ Constants.ELASTICITY)*vn;
float denom0 = (a.inverseMass + b.inverseMass);
float denom1 = (a.inverseInertia * Ra.getCrossProduct(N) * Ra.getCrossProduct(N));
float denom2 = (b.inverseInertia * Rb.getCrossProduct(N) * Rb.getCrossProduct(N));
float i = numer/(denom0+denom1+denom2);
Vector Ir = N.getMultiply(i); //vector collision impulse
Utilities.log("Collision impulse = "+Ir);

//friction impulse
Vector Vt = V.getSubtract(N.getMultiply(vn)); //velocity projected in plane of collision
Vector If = Vt.getMultiply(-Constants.FRICTION/(a.inverseMass+b.inverseMass)); //friction impulse
Utilities.log("Friction impulse = "+If);

//add total collision impulse
Vector I = (Ir.getAdd(If));
Utilities.log("Final collision impulse = "+I);

//apply impulses
a.addImpulse(aContact,I);
b.addImpulse(bContact,I.getReverse());
}



The second method called addImpulse basically affects the object according to the impulse and location of application on the object:


public void addImpulse(Vector P, Vector J)
{
//linear velocity change
velocity = velocity.getAdd(J.getMultiply(inverseMass));
//angular velocity change
angularVelocity = angularVelocity + P.getCrossProduct(J)*inverseInertia;
}



An edge coming into contact with an edge results in at least one point being inside another polygon, so whatever happens the world contact point is averaged and ends up being in the middle of the overlap of the two objects. So if a square moves into a square edge to edge, the minimum translation vector is the result of averaging the two points (or four, if the squares line up exactly).
However, if an edge penetrates a large edge, the smaller object's points are calculated then the average of those is projected onto the collision edge of the larger object. This is what is happening with the blue square in the video, which might explain why it bounces initially. However it doesn't explain (to me at least) why the square and triangle come to rest, and the hexagon doesn't :)

Share this post


Link to post
Share on other sites
I think your problem might be that you don't allow more than one contact point for an edge-edge collision. What you need to do is to see if the colliding edges are almost parallel. You can do this by taking the cross product of the two vectors defining the direction of the egdes. If the magnitude of that vector is less than a certain value (0.001 for example), then you must generate two contact points. This is necessary for stable resting contact.

Another factor is the way that you are generating contact points. Instead of just generating a single point that is the "average" contact point, try just generating 2 contact points, one for each object. For instance, in a vertex-edge collision, the point on object 1 would be the vertex, and the point on object 2 would be the projection of the vertex on the edge. This will make it so that the angular impulse will be correct. I do this in my engine and it works well.

Other than that, your impulse code looks correct. I think you really need to focus on allowing more than one contact point at a time.

Share this post


Link to post
Share on other sites
How can I ignore advice given thrice? :D I'll give it a shot, many thanks!

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!