Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » I'm Just so Close (more Physics)

This thread is locked; no one can reply to it. rss feed Print
 1   2 
I'm Just so Close (more Physics)
Anomie
Member #9,403
January 2008
avatar

I've been having trouble with collision detection/response in my spring system, but I think I finally found a solution. James Lohr previously suggested that I use a method to find a reference point in each object made of springs, so that any point attached to the same object would know which side of a line segment (ground, something like that) to rest on.

It occured to me that no spring should ever penetrate another in my system, and so I can find the appropriate resting side of a point by simply checking for a point it's attached to. In my head, this should work with any closed shape built of springs, and with any rope, as long as at least one point on the rope is fixed in the environment. (If a rope were lying on a resting surface, all of the connected points could pass through the ground at the same moment.)

The way I implemented this was to - first of all - change my collision testing function to accept springs (rather than points), so as to test pairs of connected points. Then, after my old collision checking, I find the direction of both points from the line segment (before and after velocity). If I find that point 1 (after velocity) has moved to a side of the line opposite point 2 (before velocity), I move point 1 to the point of collision between the line segment that is testing for collision, and the line segment formed between the two points I'm testing. The same is reversed for the case of point 2 moving over the line.

And uhm... It doesn't work. Doesn't really make a difference at all.

I'm soooo close to having this thing working, and I've been wracking my brain on this - with no results.
My (awkwardly-hacked-together-during-sudden-bursts-of-thought) implementation:

1// p1 and p2 are the first and second points of the spring that is checking for collision
2// (not the spring being checked FOR collision). 'spring' is a pointer to a spring object
3// passed to the function. 'pos' is a vector belonging to all points for position, while
4// 'vel' is for the velocities. Both are accessed by x() and y().
5 
6 float a = spring->p1->pos.x() - p1->pos.x(),
7 b = spring->p1->pos.y() - p1->pos.y(),
8 c = p2->pos.x() - p1->pos.x(),
9 d = p2->pos.y() - p1->pos.y();
10 
11 // Point 1's direction from the line
12 float dir1a = (a*d)-(b*c);
13 if(dir1a >= 0) dir1a = 1;
14 else dir1a = -1;
15 
16 a = spring->p1->pos.x() + spring->p1->vel.x() - p1->pos.x();
17 b = spring->p1->pos.y() + spring->p1->vel.y() - p1->pos.y();
18 
19 // And after velocity
20 float dir1b = (a*b)-(b*c);
21 if(dir1b >= 0) dir1b = 1;
22 else dir1b = -1;
23 
24 a = spring->p2->pos.x() - p1->pos.x();
25 b = spring->p2->pos.y() - p1->pos.y();
26 
27 // Point 2's direction
28 float dir2a = (a*d)-(b*c);
29 if(dir2a >= 0) dir2a = 1;
30 else dir2a = -1;
31 
32 a = spring->p2->pos.x() + spring->p2->vel.x() - p1->pos.x();
33 b = spring->p2->pos.y() + spring->p2->vel.y() - p1->pos.y();
34 
35 // And after velocity
36 float dir2b = (a*d)-(b*c);
37 if(dir2b >= 0) dir2b = 1;
38 else dir2b = -1;
39 
40 // If point 1's direction is different from point 2's (after veloctiy)
41 // And if this point isn't attached to the spring that's checking for collision
42 // Move point 2 to the point of collision between the line segment (spring)
43 // And the line between points 1 and 2.
44 if( dir1a != dir2b && spring->p2 != p1 && spring->p2 != p2)
45 if(spring->p2->checked == false && spring->p2->mass > 0)
46 {spring->p2->checked = true;
47 
48 x3 = spring->p2->pos.x();
49 y3 = spring->p2->pos.y();
50 
51 x4 = spring->p1->pos.x();
52 y4 = spring->p1->pos.y();
53 
54 ua = ( (x4-x3)*(y1-y3) - (y4-y3)*(x1-x3) ) /
55 ( (y4-y3)*(x2-x1) - (x4-x3)*(y2-y1) );
56 
57 ub = ( (x2-x1)*(y1-y3) - (y2-y1)*(x1-x3) ) /
58 ( (y4-y3)*(x2-x1) - (x4-x3)*(y2-y1) );
59 
60 if((ua > 0 && ua < 1) && (ub > 0 && ub < 1))
61 spring->p2->pos.x( x1 + ua*(x2 - x1) );
62 spring->p2->pos.y( y1 + ua*(y2 - y1) );
63 
64 }
65 // An effort to keep the system from repeatedly updating particles
66 // attached to more than one spring.
67 spring->p2->checked = true;
68 
69 // If point 2's direction is different from point 1's (after veloctiy)
70 // And if this point isn't attached to the spring that's checking for collision
71 // Move point 2 to the point of collision between the line segment (spring)
72 // and the line between points 1 and 2.
73 if( dir2a != dir1b && spring->p1 != p1 && spring->p1 != p2)
74 if(spring->p1->checked == false && spring->p1->mass > 0)
75 {spring->p1->checked = true;
76 
77 x3 = spring->p2->pos.x();
78 y3 = spring->p2->pos.y();
79 
80 x4 = spring->p1->pos.x();
81 y4 = spring->p1->pos.y();
82 
83 ua = ( (x4-x3)*(y1-y3) - (y4-y3)*(x1-x3) ) /
84 ( (y4-y3)*(x2-x1) - (x4-x3)*(y2-y1) );
85 
86 ub = ( (x2-x1)*(y1-y3) - (y2-y1)*(x1-x3) ) /
87 ( (y4-y3)*(x2-x1) - (x4-x3)*(y2-y1) );
88 
89 if((ua > 0 && ua < 1) && (ub > 0 && ub < 1))
90 spring->p1->pos.x( x1 + ua*(x2 - x1) );
91 spring->p1->pos.y( y1 + ua*(y2 - y1) );
92 }
93 spring->p1->checked = true;

(And I attached the rest of that file (which has become a grotesque monster), just in case...)

So...can anyone help me out?

______________
I am the Lorax. I speak for the trees. I speak for the trees for the trees have no tongues.

kenmasters1976
Member #8,794
July 2007

I'm having myself my share of problems with springs right now. I don't think I can help you, but I'll be waiting for a demo of your spring system.

Anomie
Member #9,403
January 2008
avatar

Oh, everything was going really well...the springs are fantastically elegant (in my opinion) for representing...pretty much anything... Even the collision detection/response was going fine until... Gravity...

Totally wrecked the thing. It doesn't play well with my infinitely small points and lines. 80% of the time I've spent working on this system, I've just been attempting to deal with the monkey wrench that gravity threw at me.

______________
I am the Lorax. I speak for the trees. I speak for the trees for the trees have no tongues.

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

Gravity shouldn't be too bad , just add the acceleration of gravity to all the particles in your system , find out how much force it causes according to their mass , calculate resultant counter-forces from fixed points and tension in connected objects , sum all the forces on each object , calculate their accelerations and then you can find their new positions. Geez , it's so simple , cmon. ::)::) (Just kidding)

Quote:

It doesn't play well with my infinitely small points and lines.

What are you using the tiny points and lines for? Also , how are you simulating ropes? Are they a collection of connected springs to propagate tension along the points of the rope?

Anomie
Member #9,403
January 2008
avatar

Oh, the problem isn't with the gravity itself, it's just that the gravity causes undesirable reactions all over the place. (like, for instance, my points falling through lines that they should be resting on)

Quote:

What are you using the tiny points and lines for?

I want the points and springs to be used to make objects, so...I want them to be as non-object-like as possible? Like atoms connected by some mysterious cosmic force.

Quote:

Also , how are you simulating ropes? Are they a collection of connected springs to propagate tension along the points of the rope?

Yeah, just like that little rope demo I posted here. I wouldn't really be implementing it... But...when the user's building, either they make closed shapes or 'ropes', right?

______________
I am the Lorax. I speak for the trees. I speak for the trees for the trees have no tongues.

Stas B.
Member #9,615
March 2008

From my experience, handling bodies during collision detection as a set of points and lines is really a pain in the butt.
I'm guessing you're just doing line intersection checks?
If your collision detection handling is static, you'll obviously miss a lot of collisions.
If it's dynamic, you'll probably be able to detect collisions, but how to resolve them is not always obvious, with special cases to consider.
I would recommend you to handle anything you can as polygons.
Try implementing SAT (Separating Axis Theorem), for example.
It would be more simple and efficient for polygonal objects, and if you extend it for dynamic collision detection, (which isn't really that hard), you'll be able to correctly handle separate lines and points as well.

[EDIT]

Consider these cases:
evilvu0.png
In the top case, the collision would just be missed.
You could pretend that it's the horizontal line that's moving with '-v' towards the vertical and handle the case, but you'd have to detect that.

In the bottom illustration, you see plenty of intersection points but it's not so obvious what to move where.

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

Is this a typo in your code?

        // And after velocity
  float dir1b = (a*b)-(b*c);

Isn't that supposed to be the dot product of the two vectors like the previous one (the assignment of dir1a)?

Also , you could simplify those direction checks a little :

  float dir1a = (a*d >= b*c) ? 1 : -1;
// instead of
  float dir1a = (a*d)-(b*c);
  if (dir1a >= 0) dir1a = 1;
  else dir1a = -1;

It only gets rid of the subtraction , but it does the same thing anyway.

Anomie
Member #9,403
January 2008
avatar

Quote:

In the top case, the collision would just be missed.

Well...it'd catch the collision, but nothing would happen...but that's just because I still haven't gotten around to having the point impart force on springs they collide with. Soon as that's handled (which is something I need to do anyway...any two moving objects smacking into each other will behave awkwardly in my system at the moment), it'll work.

Quote:

In the bottom illustration, you see plenty of intersection points but it's not so obvious what to move where.

Yeah, that'd work just fine. Each point would get properly deflected, and the springs would do the rest.

Quote:

Is this a typo in your code?

Yeah! I'd have been mad as hell if that was the problem... But strangely, it didn't seem to make a difference, really...hmm...

Quote:

Also , you could simplify those direction checks a little ...

Well...that's handy! It seems like I've seen something like that somewhere... It tests (a*d >= b*c) for true or false, and gives the first or second value based on the result, right?

[edit] Actually... I don't think it'd catch that top collision... I should change the checks to make them use relative velocity, rather than absolute velocity. That'd fix it, I think.

______________
I am the Lorax. I speak for the trees. I speak for the trees for the trees have no tongues.

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

Yes , the a?b:c operator returns b if a is true and c if a is false. Although I wonder what the > operator actually does for floats.

Quote:

and so I can find the appropriate resting side of a point by simply checking for a point it's attached to

Won't that let the other end pass over the line as much as the length of the distance between the points though?

    /___
   /

I seem to get the impression that you're not checking all moving points for collisions but only one part of each object?

OnlineCop
Member #7,919
October 2006
avatar

You may look at some 2D and 3D engines. Since they deal with most of the stuff the programmers on a.cc deal with, especially with your kind of math and spring collisions, they may be worth a look.

Anomie
Member #9,403
January 2008
avatar

Quote:

Won't that let the other end pass over the line as much as the length of the distance between the points though?

The idea is that...when the two points are just hanging out, not colliding, they both have the same direction from the line. If one of them crosses, it can check itself against at least one of the points it's attached to to find which side of the line it should actually be on. If point1 (after adding velocity) is on the opposite side of the line, compared to point2 (before velocity), then point1 crossed the line during the last update, and needs to be placed back on the line. (in the case of a totally unattached rope, the entire thing may cross the line at the same time, ruining my idea...)

Quote:

I seem to get the impression that you're not checking all moving points for collisions but only one part of each object?

I'm actually checking each point several times. I'm checking every spring, and in any closed shape the endpoint of one spring will be the start-point of another, so on and so on. Especially in my cube, with it's cross-struts. (This is why I used that spring->p2->checked = true; bit.)

Quote:

You may look at some 2D and 3D engines.

I thought those were both rigid-body engines...? I was considering seeing if I could ask this person some questions. It looks like they made just what I want to make.

[edit] Woooah, Bullet's got cloth and soft-body stuff! I'm sure it's still polygon-based, though...

______________
I am the Lorax. I speak for the trees. I speak for the trees for the trees have no tongues.

Stas B.
Member #9,615
March 2008

Well, you see, relative velocity is great, but it basically means that you have to treat one object as static, and the other object as moving with the relative velocity.
The problem is that you have to chose which object would be the moving one correctly, or you'll get nonsensical collision information.
As for the first example I gave (with the polygon), sure, your system would handle it, but it would look more ridiculous the more rigid the body is.

[EDIT]

Some more bad cases:
http://img502.imageshack.us/img502/5980/evil2cy7.png
Sure, you could work around it, but it wouldn't be very fast, nor very elegant.
Been there, done that, it's just not worth the burden.

Anomie
Member #9,403
January 2008
avatar

Quote:

it basically means that you have to treat one object as static, and the other object as moving with the relative velocity.

Let's say spring1 is the spring that is checking for collision (as in 'Hey, what's colliding with me?') and it accepts spring2 as the springs it's checking for a collision with. (as in 'Hmm...is spring2 going to run into me?') I figured it would work fine if I always treat spring1 as the static object, and spring2 as the dynamic one. I'd check every single spring's relationship with every other spring, (as in spring1 vs. spring2 and spring2 vs. spring1) but when it comes to collision response, I'd just use the absolute velocities for both.

With the relative velocities, both those cases would be handled just fine...I think. I don't see why they wouldn't. It might not be terribly fast, but it'd be just as elegant as what I've got going now.

If you haven't looked at the code, it might be important for me to mention that the 'line-line collision' check I use is actually between the line segment checking for collision and every single point. (the second line is between the point's position before and after velocity)

______________
I am the Lorax. I speak for the trees. I speak for the trees for the trees have no tongues.

Stas B.
Member #9,615
March 2008

Doing silly redundant tests would solve one problem, but introduce a new one:
In some cases, you'd get conflicting results and you'll have to chose which one to use.
Just look at the picture above and imagine doing the check the other way around like you suggest.
Anyway, I'm getting sort of tired of showing you why your system is flawed.
Have fun killing the FPS of your program while still getting incorrect collision data. :P

[EDIT]

This is how I see it:
{"name":"evil3ol4.png","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/0\/d\/0df48a657431dd33797dc8459cd3bbe1.png","w":442,"h":252,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/0\/d\/0df48a657431dd33797dc8459cd3bbe1"}evil3ol4.png
Two different results...
Perhaps I'm just stupid and I'm misunderstanding your idea?
Could you illustrate?

Anomie
Member #9,403
January 2008
avatar

Quote:

... your system is flawed.

Definitely. But all I've got to go on is what I can come up with, because the only alternative I've heard - or been able to find - is to model everything as rectangles and spheres. (which seems like a real big leap from 'Simpleville' to 'Complicated-land') Would doing polygon vs. sphere collision really be that much faster than doing my line tests twice? (and besides, since I pass my collision function the whole spring object, I can just test for collisions between 'spring1's points against 'spring2' right in the same check...so I don't really need the two collision passes for everything)

Quote:

... getting incorrect collision data.

The only 'collision data' I really get is just whether or not the two things collided. Everything else I figure from the current variables of the points involved. (still need to find a way for points to impart force to springs, though...I don't know what complications that'll bring into focus)

[edit]Oh, oh, oh...here...
http://www.allegro.cc/files/attachment/595503

______________
I am the Lorax. I speak for the trees. I speak for the trees for the trees have no tongues.

Stas B.
Member #9,615
March 2008

Time steps have been taken into account.
The picture shows the line in the current frame and the arrow tips show where it's gonna be in the next frame.
Think it's improbable that an object would move that much during one frame?
They do it all the time.
Plus, this problem comes in many variations... The velocity needed to wreck havoc on your program would depend on things like object size and line angle.

P.S.:
Yes, using SAT would be much, much faster, and more reliable.
You don't treat each point or line as a sphere or rectangle or what ever.
Your points ,and lines make polygons so you do polygon vs. polygon tests.
And if you have some lines that stand alone (like rope segments), SAT can handle them just fine the same way it handles polygons.
And it's really not a complicated concept, nor is it complicated to implement.
SAT should be faster than what you're currently doing even in the worst-case scenario, but since objects are more likely not to collide than to collide, a separating axis could very quickly be found and you'd know right away that the objects don't collide.
The idea is basically that if you find an axis, project the objects on it and their projections don't overlap, this axis separates the objects and they can't collide.
There could be infinitely many such axes, but you only need to check a handful:
To be precise, the normal of each side of each polygon is a potential separating axis.
Doing the projection merely requires a dot product, and the overlap test is a small 'if' statement.
In the worst case, you'd have to check every potential axis and if none of them separate the objects, they're colliding, but if the objects don't collide, you quickly find a separating axis and terminate the test.
With your algorithm, you'd have to check every line against every line no matter what.

Anomie
Member #9,403
January 2008
avatar

Indeed, that appears to be a better plan!

Quote:

And if you have some lines that stand alone (like rope segments), SAT can handle them just fine the same way it handles polygons.

Would I be able to do all is my individual segments like this? I don't want to have to separate all my potential objects into polygons.

______________
I am the Lorax. I speak for the trees. I speak for the trees for the trees have no tongues.

Stas B.
Member #9,615
March 2008

If you really don't want to treat every object as a whole, I guess you could treat them as sets of line segments and still use SAT, but you'd lose some of its important advantages, plus, you'd have to tweak it a bit and make the collision detection dynamic.
In fact, I had a soft body demo somewhere around where I used thin rectangles instead of line segments to make the soft body, because I was too lazy to code a dynamic SAT.
Rectangles have some area so they're less likely to just pass through each other between frames, so static checks worked fine, but if I had my jelly object to move at high speed, it would pass through other jelly objects. (But not through the map geometry, which is thick.)
I guess it all boils down to this:
If your system works fine for you in normal situations, and you don't need something fool-proof, don't bother... What you're doing should work for small time steps, medium velocities and for bodies that aren't too rigid.
Dynamic SAT would be fool-proof and not TOO hard to implement, plus, if you ever decide to use polygons in another project, you'd have something convenient and efficient ready for use. (It would surely be useful for the conventional types of games that use polygons to represent the world and bounding areas of entities, like a side-scroller...)

Anomie
Member #9,403
January 2008
avatar

In what sense is it not dynamic? And what advantages would I be losing?

______________
I am the Lorax. I speak for the trees. I speak for the trees for the trees have no tongues.

Stas B.
Member #9,615
March 2008

Your algorithm is dynamic. But the simple, straight-forward implementation of SAT is not dynamic in the sense that it doesn't take velocities into account, just handles overlaps. Static tests work just fine for polygons at reasonable velocities, they'd work fine for line-vs-polygon, too, but not for line-vs-line cases.
If you use dynamic SAT and treat your objects as a set of segments, you can't use that nice early-out option of finding one separating axis that separates the two objects, but you'd have to treat each segment as an object and check every segment against every other segment, which is kinda what you're doing now... But at least it would be fool-proof. (And probably still somewhat faster.)

[EDIT]

Found that soft body demo.
I'll attach it. ;D
In case you're wondering, it doesn't use any springs at all. I use a more stable technique. :P

Anomie
Member #9,403
January 2008
avatar

Will circle(point, given some size) vs. line not be workable in the same way as line vs. polygon? The only things I ever actually test for are collisions with points hitting lines.

[edit]I've seen that before! Huh...wonder where... No springs?

______________
I am the Lorax. I speak for the trees. I speak for the trees for the trees have no tongues.

Stas B.
Member #9,615
March 2008

No, it would work perfectly fine...
It's just that when you check a whole object against another whole object, you can find one separating axis and quit checking those objects.
If you divide your objects into parts like line segments and points, you'd have to treat each line segment and point as a separate object, that is, you'd have to find a separating axis between every two segments before you know the objects aren't colliding.
It would be like doing polygon-vs-polygon in the worst-case scenario.

[EDIT]

Maybe you've seen it at the Depot?
I posted it there a while back.
And no, no springs. Just soft stick constraints for surface tension and real pressure calculations for inner pressure. (That is, I use infinitely-stiff "springs", and every time the length of the springs is illegal, I just change the positions of the points to change it back, then work out the velocities from the changes in position. I can make the springs appear "soft" and springy by not putting the points in the correct positions right away, but dragging them a bit in that direction.)

[EDIT 2]

There's no much point discussing SAT... If you want to, read about it a bit, to understand the principle, then decide if you need it or not.

Anomie
Member #9,403
January 2008
avatar

In your opinion, would it be worth the effort of finding a method of dynamically recognizing complex convex or concave polygons full of cross-struts (which really don't need to be checked for collision) to avoid the inefficiency of that method? (the system runs very fast as it is, but I haven't gotten to the point where I can check on the demand of complex polygons interacting)

______________
I am the Lorax. I speak for the trees. I speak for the trees for the trees have no tongues.

Stas B.
Member #9,615
March 2008

Oh, damn, I forgot...
SAT works only for nice, convex shapes.
And you probably want something that works with any arbitrary shapes.
I'm an idiot. :-/
You can still just do your line\segment tests using dynamic SAT, because it would be fool-proof and somewhat faster.
To be honest, I now realize my points were somewhat moot... If your objects won't be moving too fast and you just want to get things done quick, I guess you better stick to what you have now.

Anomie
Member #9,403
January 2008
avatar

What I have now really doesn't work any better than it did before I turned it into a huge monster, so if SAT is faster and cleaner than what I have now, I'll try it.

______________
I am the Lorax. I speak for the trees. I speak for the trees for the trees have no tongues.

 1   2 


Go to: