Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Separating Axis Theorem - Point of Collision

Credits go to Stas B. and Thomas Harte for helping out!
This thread is locked; no one can reply to it. rss feed Print
Separating Axis Theorem - Point of Collision
Fishcake
Member #8,704
June 2007
avatar

I'm using the Separating Axis Theorem (SAT) for collision detection in my physics engine. It's working perfectly, but now I need to know the point of collision between the two rigid bodies. Is there a way to find it? ???

Paul whoknows
Member #5,081
September 2004
avatar

You could calculate the center of mass of both bodies and then calculate the collision between them.

____

"The unlimited potential has been replaced by the concrete reality of what I programmed today." - Jordan Mechner.

Stas B.
Member #9,615
March 2008

Umm... You take your axis of minimal overlap, project the first polygon on it, find the point(s) with the biggest dot product results, then do the same with the second but find the points with the smallest dot product results. Those are the points you're looking for, more or less.

Thomas Harte
Member #33
April 2000
avatar

As you're almost certainly aware, if two rigid bodies are overlapping then there is no single point of collision — there's an entire patch.

First of all, are you in 2d or 3d? For SAT to work you have to use convex bodies, so presumably that's exactly what you're doing?

My solution (as used by the little physics demonstration on my members.allegro.cc page, linked in my sig; check out the top entry on 'Directionless Pointers') was to calculate the minimum separation vector of the two bodies (i.e. the smallest amount that they can both be moved so as to no longer overlap), apply that and then use the final point at which the two are touching as a contact point. If the end result was that there was an edges of contact, I handled that by doing the calculations for a single contact point, located in the centre of the line.

The easiest way to get minimum separation is to work out the Minkowski sum of the two objects and find the quickest escape route. That's pretty trivial for convex shapes in 2d (as in my little physics thing), but relatively hard for non-convex and 3d shapes.

So, the exact solution from here depends on the type of shape you're dealing with. Any hints?

Stas B.
Member #9,615
March 2008

Now that I think of it, I was wrong... What I suggested would result in a whole bunch of points, some of which are useless. I'll need to think about it for a few minutes.

Fishcake
Member #8,704
June 2007
avatar

Quote:

First of all, are you in 2d or 3d? For SAT to work you have to use convex bodies, so presumably that's exactly what you're doing?

Yes, I'm in 2D and all my shapes are going to be convex.

Quote:

My solution (as used by the little physics demonstration on my members.allegro.cc page, linked in my sig; check out the top entry on 'Directionless Pointers') was to calculate the minimum separation vector of the two bodies (i.e. the smallest amount that they can both be moved so as to no longer overlap), apply that and then use the final point at which the two are touching as a contact point. If the end result was that there was an edges of contact, I handled that by doing the calculations for a single contact point, located in the centre of the line.

The easiest way to get minimum separation is to work out the Minkowski sum of the two objects and find the quickest escape route. That's pretty trivial for convex shapes in 2d (as in my little physics thing), but relatively hard for non-convex and 3d shapes.

Wow, that's a lot of stuff. My brain is too tired to read it. :P I think I'll go and check your demo first, then I'll return to read this.

Stas B.
Member #9,615
March 2008

So, Thomas, you used the final point at which the two polygons are touching as a contact point? No way, that's brilliant. ;D
And if the guy says his SAT is working perfectly, I guess he uses convex shapes and already knows how to find the axis of minimum overlap.
Anyway, I think what the guy wants to know is how to find the final point(s) at which the two are touching.
What you need to do is what I suggested in my previous post. You might get either three points, or four. (Or two, in some rare cases. I wouldn't bother with that.)
If you get two points (point vs. point collision), you just take one of them.
If you get three points (point vs. edge collision), you discard the two which are located on the same polygon.
If you get four points (edge vs. edge collision), there will obviously be two inner points and two outer. You take the inner two.
I've just tried it and it seems to work. O_o

Thomas Harte
Member #33
April 2000
avatar

Oh, I explicitly used the Minkowski Sum. The Minkowski Sum is the shape that would be formed if you took a stamp in the shape of one of the objects and printed it at every point contained in the other object. So, e.g. the Minkowski Sum of a rectangle and a circle is a bigger rectangle with rounded corners.

If you want to be formal then suppose A is made up of the collection of points {(x, y) s.t. (x, y) is inside object A} and B is made up of {(u, v) s.t. (u, v) is inside object B} then their Minkowski sum is made up of {(x+u, y+v} s.t. (x, y) is inside object A and (u, v) is inside object B}.

For objects A and B, what I actually use is the Minkowski Sum of A and -B. -B is the shape formed when you take every point (x, y) in B and reposition it at (-x, -y). Which, because of the way that basis vectors work, is the same thing as rotating B by a half circle. But thinking of it as (-x, -y) is more instructive.

If you calculate the sum of A and -B then you can use it to do an overlap test on A and B. Just check if the point (0, 0) is inside the sum. If it is then obviously there is at least one (x, y) that has the same value as at least one (u, v). So there is at least one place where the both the objects lie on top of each other.

If you move object A by (m, n) then the points (x+u, y+v) turn into (x+m+u, y+m+v). So movements on A directly move the sum by the same amount. Movements on B mov the sum of A and -B by the opposite amount.

Therefore, the shortest amount that you can move A to separate it from B is whatever the shortest vector is from (0, 0) to a point on the outside of the Minkowski Sum. Or you can move A by half the vector and B by half the vector in the other direction. Or whatever you want along those lines.

The "Convex Minkowski Sum Demo" on my page is possibly worth checking out here. It lets you manipulate the shape of two objects, shows you their sum and keeps them separated. Also, I think it's Allegro-based.

It uses a really simple winding algorithm. For each face of A, find the point of -B that is furthest in front of it when B is positioned on either endpoint of the face. Then move that face out by that much. That'll leave gaps where the corners of A were. Fill them in by using faces from B, with B positioned on the corner.

Specifically, if face 1 connects to face 2 at vertex q on object A, vertex n of object B is furthest in front of face 1 and vertem m is furthest in front of face 2 then add to the sum:

  • a face that is equivalent to face 1, moved back or forth along its normal so that it crosses over vertex n when B is positioned on an endpoint of face 1

  • the faces from B that run between vertices n and m, as they would appear if B was positioned at vertex q

  • a face that is equivalent to face 2, moved back or forth along its normal so that it crosses over vertex m when B is positioned on an endpoint of face 2

It's maybe easier to think of graphically. Imagine taking object B and tracing round the outside of object A. Obviously the bit that sticks out furthest when going round the edges will print of the top of all the bits that are further inside. And at the corners you'll be left with whatever part of the outline of B normally falls between the sticky out bits.

Obviously if the shapes weren't convex then the answer would be more complicated.

Anyway, that gives you the sum without any difficult arithmetic — it's really just a sorting problem. Assuming the objects overlap then from that you can find the quickest escape vector from (0, 0) using normal 'distance to plane' stuff. Then you can push the objects apart.

A neat side effect is that when you're building the sum, each side is effectively the combination of a point from one object and a face from the other. When the objects are separted, that point will be in contact with that face.

Testing for face to face rubbing just means detecting when the sum has two faces in a row with the same normal. It's definitely not worth worrying about at first and can probably be ignored indefinitely.

EDIT: or use Stas B's approach for a pretty good approximation. This stuff gets harder in 3d, because it's harder to figure out what geometry to fill in at the corners. The best solution I've yet come up with is to duplicate lots of geometry at vertices and do a quickhull (minimum convex hull algorithm) on all that. This is partly related to the way that I've never managed to think of a better way to determine which faces of a convex 3d object are visible from a certain angle without testing every single one of them. Probably some people who are smarter, have read more or have thought about it for longer have some solutions to that sort of thing. I'm pretty sure it boils down to the fact that the faces of a convex 2d object are trivial to sort 'by normal', but the faces of a convex 3d object aren't. At least to me. So, waffle over, key point: approximations that map well to 3d are worth thinking about too.

Stas B.
Member #9,615
March 2008

Hmm... That's actually quite interesting.
But what do you mean by "a pretty good approximation" at the end of your post?
The results from my approach seem quite exact to me. Am I missing something?

Thomas Harte
Member #33
April 2000
avatar

Quote:

Hmm... That's actually quite interesting.
But what do you mean by "a pretty good approximation" at the end of your post?

I was confused by your suggestion to take points from both objects and idiotically incorporated the need to find a collision normal into my thoughts, because I'd started thinking about rigid body dynamics and not what the original author was asking.

I think our suggestions end up being pretty much the same thing if you add the fact that the axis of minimum overlap is actually a plane normal for one of the objects. Then the point you're looking for is the one from the other object that penetrates most deeply into that.

I'm not sure why you'd collect points from both objects. Probably I've misunderstood?

EDIT: oh, if you want to test for point to point collisions separately to point to edge collisions with the Minkowski Sum solution, just test whether the escape vector exists through a vertex of the sum. And then obviously use the escape vector itself as a collision normal, if you need one.

Stas B.
Member #9,615
March 2008

I need points from both polygons because I don't know which polygon has the point and which has the edge (in the point vs. edge case). In some edge vs. edge cases, you'd get two contact points, one from the first object, one from the second. I don't see any way around finding the closest features on both polygons and filtering the needed ones.

[EDIT]

This is slightly off-topic, but I was wondering if...
When a collision occurs, if we ignore rotations, we can calculate the reflected velocities to get a collision response... Now, if I used the changes in velocities and the time-delta to work out the force needed to cause those changes, could I convert it into a torque and use it to make the objects rotate correctly? (Or at least in a seemingly-correct way?)

Thomas Harte
Member #33
April 2000
avatar

Quote:

I need points from both polygons because I don't know which polygon has the point and which has the edge (in the point vs. edge case)

Surely whichever polygon owns the edge with the normal that provides the axis of minimum overlap is the one that supplies an edge, and specifically it supplies that edge?

EDIT:

Quote:

I don't see any way around finding the closest features on both polygons and filtering the needed ones.

Obviously you mean other than through the Minkowski Sum?

Stas B.
Member #9,615
March 2008

HAHAHAH. Oh my god. Of course. I'm so dumb. ;D
But there's still the edge vs. edge case.

[EDIT]

Never mind...
You're right. There's absolutely no need to check points on both objects.
I think I need a good sleep. :-/

[EDIT 2]

You DO have to find points on the 2nd object in edge vs. edge cases where one of the shapes has parallel edges (like a box) because sometimes you'd end up with one contact point on one object and another one on the other, but the point on the 2nd object won't be essentially one of the points you used to generate the normal.
If it doesn't make sense to you, so you'll either have to test for yourself or just trust me.
So yeah, if you know you have an edge vs. edge case, find points on both objects.

Fishcake
Member #8,704
June 2007
avatar

Hmm...I think I'm going to try using the Minkowski Sum. It seems interesting. :) I'll try to make a demo from it, so that I can understand how to use it. I think it's quite complicated, judging by the length of your post. :o

Stas B.
Member #9,615
March 2008

That's crazy. :o
It would take you about 10 minutes of coding to find your contact points with your current SAT system.
Well, have fun.

Fishcake
Member #8,704
June 2007
avatar

I've finally finished the demo, which I have already posted in the depot. I had problem understanding Thomas Harte's algorithm of calculating the minkowski sum polygon, so I just used the Monotone Chain algorithm to produce a convex polygon from the set of points produced from the minkowski sum of two polygons.

Go to: