Skip to main content
GameDev.net gamedev.net
🔒 Locked

[UPD US keyb friendly + method selection] Some new physics... demo inside.

Started by b34r Jun 20, 2005 at 12:57 AM 74 replies 12.2k views
Original Post
b34r
b34r
Hi there, These last few weeks I went back to the physic code I started some months ago (>6) and you maybe remember my thread about it. Well, I've been reading a lot of things ever since and I improved it quite a lot so here it is. This is DirectX8 and it uses triadic operator without checking for support (Geforce2MX has it) so I suppose it should work almost everywhere. Comments are more than welcome, if people are interested I can post a kind of what worked/what didn't about the various tricks I tried to make it more stable. The most interesting thing being that it actually is almost a bare implementation. Most tricks I used to use (sticky col, time warp) where in fact not useful or would even cost some stability when used. So it's impulse based with normal Euler integrator and close to no damping, 32 iterations max, largest mass ratio in scenes is 1/10 all under standard Earth gravity, scales are corrects so, for example, the books are small and light. The previous version couldn't stabilise one book of this size on the ground at 150hz \:. There's a lot of drifting going on at 75hz and I've started studying how to solve contact points simultaneously because it definitively is the key to more stability. The problem being that my maths really are not up to the task so far. You may find some setup too stable and that's due to the activation threshold being too large. Simultaneous contact solving should allow to reduce that threshold so stacks can deactivate and activate as expected. I also have some ideas on how to improve the reactivation heuristic that would require that I maintain a list of sleeping contact wich I do not have now... Oh and yes, I still only have OBB/OBB collision (well with contact support) so I really need to add some more of these... [Edited by - b34r on June 23, 2005 2:02:40 AM]
Praise the alternative.
mengha
mengha
That was good :)

One thing that was strange though is your controls:
Q = Strafe Left
D = Strafe Right
Z = Forward
S = Backward

Wouldnt doing WSAD be a better idea?
Programmer16
Programmer16
The physics in that were awesome (good graphics too.) Keep up the good work!
b34r
b34r
Quote:
Original post by mengha
That was good :)

One thing that was strange though is your controls:
Q = Strafe Left
D = Strafe Right
Z = Forward
S = Backward

Wouldnt doing WSAD be a better idea?


Arg, sorry about that... Damn :( sorry for all non-french keyboard layout users... I thought Windows would map the VK_ flags.
Praise the alternative.
b34r
b34r
Quote:
Original post by Programmer16
The physics in that were awesome (good graphics too.) Keep up the good work!


Thanks [smile] I plan to!
Praise the alternative.
MrRowl
MrRowl
That's really really good :)

I'd be very interested to read more info about your implemtation, if you're able to post it.

Edit: Ah yes - just realised what your original thread was - the one that made me go and write jiglib!! Looks like I have some more work to do to catch up again :)
b34r
b34r
Quote:
Original post by MrRowl
That's really really good :)

I'd be very interested to read more info about your implemtation, if you're able to post it.

Edit: Ah yes - just realised what your original thread was - the one that made me go and write jiglib!! Looks like I have some more work to do to catch up again :)


Ahah, no way you don't need to catch up. Jiglib is very nice and stable, I also saw you implemented polymesh collision, that's nice! It's on my todo list because box/box is getting very limited [smile]. I'll try to sum up some details of my implementation no problem, that's just fair seeing how your various posts helped me so far. Later then.
Praise the alternative.
b34r
b34r
Ok, big one incoming...
Some of the things that had the greatest impact on stability were:

  • Contact determination. I'm using the SAT for overlap determination. I simply collect both OBB extremities along the overlap normal and perform feature clipping from there to determine a contact feature set. Simply changing the way I defined extremities from farthest along the normal' to 'inside the offending OBB' gave a major stability increase. This is the modification that made the more difference so far.
  • Allow some amount of interpenetration. That is, completely ignore contacts when the penetration amount is below a given threshold (in the demo 1.0mm). Now when the penetration correcting impulse kicks in, instead of having it resolve the penetration completely, have it resolve the penetration minus epsilon (i'm using half the penetration tolerance). This is a standard method when dealing with thresholds to have a 'neutral' zone in order to avoid oscillating around the threshold boundary. However, I really didn't expect it to have much impact in this case and I honestly don't really get why it helps so much.
  • Deactivation/activation heuristic: As Mr.Rowl says it, this one is easier said than done. I can't recap all the heuristics I tried but the simplest the better (as usual?) and for what its worth the current algorithm goes like this:

    When inactive, wake up if:

    • (1) In colliding contact with a body whose velocities are above the activation threshold (16x sleep threshold in the demo) or (2) if after the solver pass the body velocities are above the activation threshold. Note: The activation threshold is a two-edged sword. When a very large activation threshold is used it can make arbitrary large stacks stable but also prevent correct reactivation in many cases (see my plans for a possible fix to this large activation threshold and activation problem). The (1) point can be omitted and relying only on the post-solver test kinda works. Bodies are indeed woke up but the initial response is flawed since the initial overlap occurs with a sleeping body the active body's velocities will most likely be completely cancelled and the sleeping body will receive no impact at all. This is very dependent on my implementation however so YMMV.
    • Contact vanishes. Detecting when a contact between two bodies vanishes is fairly easy if you have the previous update contact list handy when starting a new update. Just check that each contact in the list are still touching. If not, wake up the contact body pair. Note: I currently do not store sleeping contacts so I could (and should) miss some reactivation since two inactive bodies are not considered by the overlap tests (and so no contact pair is stored). What's helping here is the penetration tolerance that guarantees that in most cases after reactivation and the first position update the newly activated bodies will still be in contact. This should fail sometimes but in practice does not so I didn't bother fixing it until now. I have an idea on how to easily fix that (not sure how it will look tho :)) wich would involve delaying the position update for one update on reactivation so that the collision engine has time to register the contact with sleeping positions.


    When active, go to sleep if:

    • If velocities are below the sleep threshold for 'n' updates and there is a colliding contact with at least one inactive body.
      Requiring a contact makes sure that active bodies with very low velocities do not go to sleep while mid-air. Requiring a contact with an inactive body avoids up/down deactivation in stacks wich is very bad. Very bad since a body velocity must go back above 16 times the sleep velocity to reactivate, bottom bodies in large stack would often get caught between two deactivated bodies and slowly crawl out of the stack in search for more room to rest (this problem can be seen in Meqon maybe for different reasons tho). This also helps against overly stable stacks. In the demo, for example, the Jenga stacks are too stable but when the top of the stack is woke up in an non-equilibrium position it will collapse while it could incorrectly go back to sleep if the sleep order was not enforced. Requiring a colliding contact (as opposed to a resting or separating one) makes sure that when a contact vanishes and causes a reactivation, the reactivated body does not incorrectly go back to sleep. Not requiring a colliding contact would be a problem as we allow some penetration and, for example, in a sleeping stack where the bottom body is removed all sleeping bodies are in resting/separating collision with a sleeping body directly above them (re-edit: no it makes sense [smile]).


Some of the things that had potential but were in fact causing more problems than they would solve:

  • Buffering impulses and processing them after a solver pass. It avoids erratic bounce on face/face contacts and as a derived benefit increases stacks stability. However, as Mr.Rowl (again :)) states it on his website the combined impulse (well at least by naively averaging force and torque) is incorrect. A moderate stack of boxes will go up and down as the impulses fail to stop the stack from collapsing and the penetration impulse kicks back in, this no matter how much iterations are took. It also badly prevent disturbed stacks from going to sleep efficiently (eg: shooting on the pyramid in the demo would most of the time entirely wake up the stack and take several seconds to deactivate when it not would fall down due to the base crates crawling out). I'm however convinced that solving impulses simultaneously for each body will increase the demo current stability by a great deal as the main source of stack instability right now is the jittering induced by the sequencial (yet quasi-randomized) processing of the contacts. This should also help a lot when running less updates per second.
  • No sleep delay but an equilibrium check. This works incredibly well and feels very robust, it's a shame I couldn't solve the one big quirk I encountered. The algorithm went like this, when item velocities goes below their threshold perform a check on the current contact set. If more than 2 contacts, not lying on the same line, can be found then go to sleep. It works 90% of the time... and especially not in stacks (doh! :(). As there are contacts both above and under stacked bodies that do not lie on the same line any stack will go to sleep immediatly even while falling. Of course I tried for a while to add some more heuristics to filter the bad cases but got some pretty bad headaches so left it where it was. Note: Heuristics needs to be modified on a per body basis. Obviously a sphere only requires 1 contact to go to sleep while a two-sphere composite object will use the same heuristic as a box.
  • Time warping, well I believe that's how it is called (see Mr.Rowl's website for a description of the method). Very efficient at removing bad bounces caused by too large penetration correction but starts stopping bodies before they actually get in contact and I have better results both in stability and plausability without it.
  • Sticky contacts, good to artificially improve stacks but prevents fast deactivation as stacked bodies are not free enough to move out of offending positions.
  • Shock propagation and variant. Brilliant for large stacks but also makes them way too stable. Mr.Rowl's modification, not to update angular velocity during the shock propagation, helps solving the over-stability issue a bit but I do not feel like the cost in plausability is worst the stability and increase in complexity unless you're making buildings or alikes ;). I also tried a pseudo shock propagation wich is not activated in the demo where an extra solver iteration is taken with all active bodies set to the same mass. This seems to work okay but I didn't test it that much so far. A variant, that I did not test, would be to only take the first iteration of the solver with different mass and all following ones with equal masses, this should be ugly though...
  • Activation resillience. I tried to make the activation threshold dynamic so that when a body goes to sleep the activation threshold is set to 128xsleep threshold than gradually goes down to sleep threshold. This worked to some extends, it give a nice effect were any activation will propagate through all contacts but didn't really help with either stability or activation problems.
  • Filtering gravity. When things are stacked and settling down what really makes things unstable is the gravity so I tried a great deal of on-contact gravity filtering but they all had some kind of drawbacks that didn't justify the (sometime major) increase in stability.

Next things to try in order to increase stability:

  • Find an efficient way to store original delta position (at deactivation time) between an active and an inactive body so that it is possible to wakeup body if the delta gets too big. This should allow for much higher activation threshold while still waking up stacks when a body is slowly removed from the bottom of the stack.
  • Multiple contact processing...

Another nasty hack wich somehow increased stability but not that much, so the demo is not using it, is to blend the current body velocities with the previous state ones in place of standard damping. The drawback is that it bias speeds and collision feedback, really not nice. However it does really help the integrator as it blur out sudden changes in velocity. A blend coefficient of 0.8 (nv = nv * 0.8 + ov * (1 - 0.8)) does not impact too much on the realism and used to provide a nice improvement in the earlier stages of my simulator.

About speed, its full C++ with no special optimisations, using a sweep and prune ala OPCODE with insert sort. Not much more really :). I also discovered with some of the later test scenes that my renderer is awfully slow at rendering large number of small objects.

If you need more details, do not hesitate to ask.

edit: Added 2 hack I tested.

[Edited by - b34r on June 20, 2005 5:08:36 AM]
Praise the alternative.
Structure
Structure
All I can say is fantastic!

Keep up the good work, I find these posts very intresting….
[happy coding]
b34r
b34r
Quote:
Original post by Structure
All I can say is fantastic!

Keep up the good work, I find these posts very intresting….


Thanks ;) I'll add more of the things I tried to the lists as I recall them...
Praise the alternative.
_swx_
_swx_
Can you describe more in depth how you find the contact points after clipping, and exactly how it's different from the standard approach?
Erik Rufelt
Erik Rufelt
Very nice!

I'm kinda wondering how this is possible though:

It didn't fall =)
Wan
Wan
Very nicely done! I know it's not a game, but I could play this for hours. [smile]

I actually managed to get one stuck onto the "wall". Apparently it moved one of the blocks in the tower back a little and got stuck between the cubes surrounding it. What are the odds? [grin]

b34r
b34r
Thanks everyone,

Quote:
Original post by Erik Rufelt
Very nice!

I'm kinda wondering how this is possible though:

It didn't fall =)


Yes indeed [smile] I got some of these back already. The settings are a bit too aggressive in the demo it seems. Somebody called that LeCorbusier Physics... I guess it fits [smile].

Well to be honest I just spotted a really awfully major bug in my code wich led to partially wrong impulse generated so I'm fixing everything right now and I'll post some update as soon as it's done because I expect that it should allow to lower the threshold quite a bit. I got intrigued by the fact that boxes seemed to be slightly sliding when rotating on an edge and indeed they are, wich is not normal at all.

Quote:

Original post by _swx_
Can you describe more in depth how you find the contact points after clipping, and exactly how it's different from the standard approach?


I'm not sure wether it differs from the standard approach or not as I don't know what the standard approach is [smile] but let's say you have two OBB/OBB contacts one of the OBB edge is inside the other OBB. But one of the point of the edge has a penetration depth of 0.0001mm while the other is 1mm deep. With the approach I used in earlier versions I would not have performed an edge/face clipping but a point/face clipping as I would select extreme features along the normal penetration and not features in overlap with the other box. Not sure if it's more clear, sorry.

As a side note I'm not using per contact depth, I tried that but it didn't give any benefits.

Quote:

Original post by WanMaster
What are the odds?


I did manage that too [wink].
Praise the alternative.
MrRowl
MrRowl
Quote:
Original post by b34r
As a side note I'm not using per contact depth, I tried that but it didn't give any benefits.


Can you clarify - e.g. for a box/box collision do you just store one penetration depth, or do you store a penetration depth along with each contact point?

I do the former, and I think it's why I get bad behaviour for small boxes.

Also, can you confirm you're not using any "shock propogation"?

Thanks - Danny
billy_zelsnack
billy_zelsnack
rockin. i am always surprised that there are not more good custom physics demos out there by now.
very unhelpful and/or unfriendly
b34r
b34r
Quote:
Original post by MrRowl
Can you clarify - e.g. for a box/box collision do you just store one penetration depth, or do you store a penetration depth along with each contact point?

I do the former, and I think it's why I get bad behaviour for small boxes.

Also, can you confirm you're not using any "shock propogation"?

Thanks - Danny


Yep, I only store a penetration along the normal. I thought the same as you especially for small boxes but it turned out that it really didn't help. But don't take my word at it because I might have done something wrong [smile] however I kind of triple-checked everything out of desesperation and it seemed I had correct values and no substantial stability increase.

Yes, no shock propagation but 32 iteration max. In fact, if I strip out the deactivation/activation heuristic code it's just the basic:

- Collect external forces,
- Collect overlaps,
- Solver (classic, n iterations over the contact list, impulse sequentially processed (one to the right, one to the left to minimize drift)),
- Update position,
*repeat*

But as I said earlier I have a pretty bad drift at 75hz (even at 200hz it is still considerable) so deactivation comes handy but I really need to either:

- Find a way to filter the drift. For this I tried to store vel_linear before processing impulses, storing the impulses AND modifying vel_linear. By the end of the loop get the sequential delta_vel_linear = vel_linear - prv_vel_linear and use the average impulse direction and the sequential delta_vel_linear length to make a hopefully non-drifting linear velocity impulse that is sufficient to cancel velocity but to no luck. It worked but looked like the hack it was, not bad but worst than straight sequencial impulse [smile].
- Simultaneously process contacts for each item.

I however have no bouncing and this is, as far as I can tell, only due to the penetration correction stuff I mentioned in the large post... Well at least simply solving penetration brings the bouncing back.
Praise the alternative.
b34r
b34r
Quote:
Original post by billy_zelsnack
rockin. i am always surprised that there are not more good custom physics demos out there by now.


Thanks [smile], I guess it partly is because, while highly rewarding even when partially working, physics are a very frustrating thing to do. It's not hard (I'm only talking about what I did so far mind you, it certainly can get very hard [wink]), it's just really unforgiving and boring to code.
Praise the alternative.
b34r
b34r
I updated the RAR with a fixed exe. If you ask me it's way better, impulses were completely off completely screwing up the physics... I also reduced some thresholds to reduce the number of depressing screenshots [wink] so some stacks are not as tall as before and deactivation may take a bit more time to come.

Ah yeah the crates can now get stuck very easily between two planks of the shelf... I'll have to filter that case, I have some ideas already but it's really getting late.
Praise the alternative.
John Schultz
John Schultz
Good job! Impulse physics engines look great. Nice rigid impacts.
2000+ boxes at 6-10Hz is good performance (P4 3.2).

How high can you get with a single stack? I can get around 400 (but have to relax the system to keep running reasonably fast, decreasing quality, though it remains relatively stable). This is in a full game environment, with terrain, sound running, etc. I use general convex hulls; not as fast as optimized boxes (three planes and three distances, etc.). I track all contacts (and depths)... While iteration helps with higher stacks, it's possible to get stable, rigid stacking with smaller stacks and no iteration (8-16, etc.).

You can improve on impulse averaging by using weighting: sum the impulses and rescale using the relative contribution of momentum in the direction of each contact: intuitively and physically accurate. This is one of the methods I used my "Energy Accurate" physics demo: accurate enough to run for weeks without drift, etc.

If you line objects up on the ground, can you push such a box contact group around?

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.