erincatto / box2d

Box2D is a 2D physics engine for games
https://box2d.org
MIT License
8.28k stars 1.54k forks source link

changes in r186 create problems in b2RevoluteJoints with limits 0,0 #310

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
What steps will reproduce the problem?
1. Create a pole made up of rectangles linked by b2Revolute joints with default 
limits on
2. Try to bend the pole

What is the expected output? What do you see instead?
- Expected: pole returns to straight (all joints return to reference angle) 
after being bent
- What I see: after large bends, pole returns to original shape ridiculously 
slowly (like, 10 seconds). 

What version of the product are you using? On what operating system?
- C++ Box2d 2.2.1 latest

Please provide any additional information below.
- Have narrowed this down to r186 changes 
- specifically: in 2.1.2, if I remove the "Handle large detachment" segment 
from b2RevoluteJoint.cpp, it exactly reproduces the behaviour from 2.2.1
- I'd suggest that the optimization that involved removing this code from the 
new version has generated a bug.

Original issue reported on code.google.com by bfo...@gmail.com on 31 May 2013 at 11:13

GoogleCodeExporter commented 9 years ago
Here's a picture of the behavior

Original comment by bfo...@gmail.com on 31 May 2013 at 11:26

Attachments:

GoogleCodeExporter commented 9 years ago
The revolute limits are not meant to act like springs. If you apply large 
forces to violate the limits then the solver can get stuck. Can you change your 
simulation so the pole doesn't get distorted? If you want the pole to bend, 
please use b2WeldJoint.

Original comment by erinca...@gmail.com on 28 Oct 2013 at 5:52

GoogleCodeExporter commented 9 years ago
I have springs that need to be incompressible though (think of a flexible pole 
rather than an actual spring) so the weld joints aren't appropriate, and anyway 
they are way too weak if the pole needs to support anything, even with a 
ridiculous number of simulation steps.

I guess another joint type is needed.

If you're interested to see the use case, I have a video of the game at 
http://vimeo.com/m/76771268

Original comment by bfo...@gmail.com on 31 Oct 2013 at 12:40

GoogleCodeExporter commented 9 years ago
Thanks, I watched the video. Looks awesome.

I'm guessing you are using many segments for a single pole.

I recommend using two segments and a single weld joint. Use quadratic 
interpolation for the rendered pole. This should be quite stiff and still 
produce nice curves.

The problem with the issue you filed is that I removed a hack and you want me 
to add the hack back because it helped in a situation where the model isn't 
stable. Lets see if we can get the model stable first.

Original comment by erinca...@gmail.com on 31 Oct 2013 at 5:24

GoogleCodeExporter commented 9 years ago
I already do some quadratic interpolation to keep the number of segments low, 
but I can't bring it down to a single weld joint. It's a nice idea, but there 
are lots of small reasons that this is not a workable approximation:

- people would notice that the collisions were not matching the pole (I promise 
you, in a competitive sporting game they would be bothered by it, too)
- the pole would not allow players to 'vault' in the same way because it would 
not get enough friction to launch until the entire end segment was laying flat 
on the ground. Even with the friction set very high, box2D bodies do not 
generate enough resistive force when sliding if there is only one point of 
contact. 
- players need to be able to run along each other's poles, even when they're 
bent. The angle discontinuity in your suggested solution would create an 
impassable barrier halfway along the pole, much of the time.
- I suspect, but am not sure, that the spring force of a single joint would 
never be high enough to simulate actual pole vaulting. I suspect that when a 
real pole springs back after being bent, we're seeing a superposition of force 
from a large number of 'springs', which would not have the same linear force 
relationship as your single spring. (But it is a long time since I got my 
physics degree and that could be wrong)

To be honest, I'm not expecting you to revert the change in the code (for the 
reasons you gave), and I'm also not expecting you to add a new constraint 
overnight. But I think this case probably does indicate the need for a new 
joint type. There will be many cases where people need joints that are 
incompressible in terms of distance but stiff and flexible in terms of angle 
(diving boards, thin swords, skyscrapers, etc etc) and at present we just don't 
see any of these objects simulated using physics in any game, anywhere. We 
can't just insist that every game fakes it with two bodies and one weld joint.

Anyway... my game works ok with the old hacked Box2D code. I don't have some 
nice benefits like CCD and I did have to port over some bugfixes you applied in 
later releases, but that's ok. So I'm not so much worried about this game, but 
about games that myself and others will make in the future.

FWIW, I had good success with an earlier Flash prototype of this game, which 
used NAPE. In that engine, you can apply a rotational constraint that doesn't 
affect position, and combine it with a distance constraint (that doesn't affect 
rotation). Since they are more or less orthogonal in terms of their influence 
on the bodies, they don't conflict and explode. I guess I've come to see the 
Box2D Revolute Joint as a higher-order constraint, and the engine is missing 
the lower-order one. Call it an AngleJoint or something. The Revolute Joint is 
more intuitive for beginners but there aren't many upsides for experienced guys.

Original comment by bfo...@gmail.com on 31 Oct 2013 at 1:14

GoogleCodeExporter commented 9 years ago
Oh, I'll also add another piece of evidence: complex self-supporting ragdolls. 
I made the game CLOP (http://www.foddy.net/CLOP.html) at first using Box2D, but 
then I had to abandon it and use NAPE. The horse ragdoll has enough joints that 
I just couldn't get the simulation stable in Box2D. In NAPE, each joint has one 
of those angle and distance constraint pairs... this way, the muscles of the 
horse do not contribute to instability in the position of the body parts.

(And - I did watch the 'how do I stop my constraints exploding' session you ran 
at GDC, and I'm pretty sure I wasn't just setting up or running the simulation 
badly).

I hope you won't think 'well, go and use NAPE then'. Box2D is by far the more 
popular and mature API, and it's on every platform and will soon be the backend 
for nearly every indie game made in Unity. It's super important that it can 
handle as many cases as possible.

Original comment by bfo...@gmail.com on 31 Oct 2013 at 1:21

GoogleCodeExporter commented 9 years ago
Good physics engine usage is just as important in games as the physics engine 
itself. I recommend looking at my GDC2012 presentation on ragdolls. 
https://code.google.com/p/box2d/downloads/list

If you are causing constraints to be highly violated then your model is not 
suited to the quality/performance trade-off in use. You either have to increase 
the solver iteration count or improve the model.

The weld joint is what you should be using. Setting the revolute limit to 0,0 
is equivalent to a weld joint with 0 hertz, but less efficient. How many 
segments are you using?

Did you see the walker demo in the testbed? This is quite stable. It's all in 
the modeling. It would possible to create the horse with the right technique. 
Look at all the stuff irresistible force has made: http://www.iforce2d.net/

Original comment by erinca...@gmail.com on 3 Nov 2013 at 6:48

GoogleCodeExporter commented 9 years ago
Hmm, ok. I tested it again - if I use a weld joint I can't ever seem to get it 
stiff enough, even set to 0Hz, but at least it doesn't spazz out. Maybe I'll 
make some tweaks to the correction code and see if I can replicate, if it will 
be more efficient it's probably worth doing.

My model isn't anything crazy. It's just 12 rectangular polygons connected with 
a single joint between each pair. I totally agree that good physics engine 
usage is as important as the physics engine itself, but I honestly have tried 
literally dozens of configurations for this game and I had very little success 
so far doing things the 'right' way with weld joints.

Original comment by benn...@foddy.net on 3 Nov 2013 at 8:46

GoogleCodeExporter commented 9 years ago
Actually scratch that, the weld joint in 2.1.2 has the same 'handle large 
detachment' code as the revolute joint, so my test doesn't prove anything. I 
can't prove it in the short term, but when I was using 2.2.1 I found the weld 
joints were even less stable than the revolute joints for this use case.

I'll go and try to implement the weld joints with 2.2 or 2.3 again but I'm not 
at all optimistic that this is going to work.

Original comment by benn...@foddy.net on 3 Nov 2013 at 8:50

GoogleCodeExporter commented 9 years ago
Then maybe you want to look at the loads you place on the pole. Are they from 
heavy bodies? You need to make sure the mass ratios aren't too high. The 
ragdoll presentation would apply in that case.

From you forum post it looks like you have around 10 segments. Can you get away 
with less?

Original comment by erinca...@gmail.com on 3 Nov 2013 at 8:54

GoogleCodeExporter commented 9 years ago
There is a heavy load on the end of the pole, I guess: the player. If the 
player isn't heavy, he can't bend a flexible pole enough to vault with it, so 
this is an 'inflexible' requirement of the design. I do understand that this is 
one of the stated weaknesses in the engine though, listed right there in the 
manual, so it's hardly a surprise if this generates problems. I guess my point 
in starting this thread was just to say that my simulation works (with weld or 
revolute joints) in 2.1.2 and it doesn't work with any revision after that.

I wound up using 12 segments. Experimenting with it just now, I found I can 
increase the stiffness of the pole sufficiently to allow me to use Weld joints 
if I go down to 10 segments. This is a pretty good win since I save CPU cycles 
both by using Welds and by removing 2 segments. But I still suspect the model 
will fail if I upgrade my Box2D above 2.1.2. I'll try it later and see.

Original comment by benn...@foddy.net on 3 Nov 2013 at 9:29

GoogleCodeExporter commented 9 years ago
So you made the guy heavy to distort the constraint that is supposed to be 
rigid.

How about making the guy less heavy and then using a flexible weld joint (hertz 
> 0)? For that pole I would use start with a hertz of around 10 and a damping 
ratio of 0.2.

Original comment by erinca...@gmail.com on 3 Nov 2013 at 10:01

GoogleCodeExporter commented 9 years ago
Ok, part of the problem is that I'm not using the term 'rigid' the way you are. 
I don't mean 'infinitely rigid' I am trying to produce a strong, but flexible 
pole. The guy is heavy just like a real human being who uses his mass and 
inertia to flex a pole. I used roughly realistic numbers for the density of the 
various objects.

Sorry if this is frustrating from your end, I'm really not trying to be a pain. 
In my earlier experiments, I found that in 2.2+ a flexible weld joint was way 
too weak no matter what figures I used for the frequency and damping ratio. But 
I'll make a fork with the upgraded engine and then come back with more data and 
open a new issue if necessary (since this is not anything to do with the issue 
I reported)

Regarding the original issue: I'm pretty sure that the post-2.2 behaviour of 
the revolute joints is a problem for the engine, EVEN IF I follow your advice 
and completely abandon them for the purposes of this game. They should not deal 
with distortion by getting stuck in the distorted position, and then gradually 
returning over the course of ten or more seconds. Or at least, I don't see the 
upside of giving them this behaviour. It seems like it would generate a lot of 
hard-to-debug simulations wherein a revolute joint somewhere was getting 
'broken' but not in a visible or catastrophic way. If they're going to 'break' 
to avoid constraint explosions, it would be better if they came properly back 
to life when the constraining objects or forces were removed.

Original comment by benn...@foddy.net on 3 Nov 2013 at 10:29

GoogleCodeExporter commented 9 years ago
Please try all of the following with recent C++ code:
- lower the mass of the player body
- reduce the number of segments
- use a soft weld joint of with damping ratio of 0.5, hertz of 20.
- use a time step no bigger than 1/60
- use at least 20 velocity iterations
- make sure the pole is at least 2 units in length
- increase the thickness of the pole. You can do this without affecting 
collision by using additional fixtures that have their collision filter set to 
not collide. Make sure the mass is symmetric about the axis of the pole.

Original comment by erinca...@gmail.com on 3 Nov 2013 at 10:45

GoogleCodeExporter commented 9 years ago
Ok. It'll take me a little while though because of the changes to the codebase.

Original comment by benn...@foddy.net on 4 Nov 2013 at 2:38

GoogleCodeExporter commented 9 years ago
Closing. This is a tuning issue.

Original comment by erinca...@gmail.com on 4 Apr 2014 at 4:22