Spring Dampning and NaN Errors

Topics: Developer Forum
Mar 1, 2010 at 5:42 AM

Hey guys, been a while.  I FINALLY got the opportunity to download the latest bits of code.  And by latest I mean the one on the Downloads page from back in November.  Anyway!

I was toying around with the WPF samples and managed to get the NaN error while goofing around with the Collision Categories demo.  I would use the big X prop to make the little balls tunnel into the walls.  Then after attempting to drag the balls out of the wall, they would spaz and the program would crash.  This then made the thought come to mind that this only seems to happen to me when springs are involved, and of course, the mouse spring is a FixedLinearSpring.  Using this epiphany, I decided to step myself through the spring controller code.  As as soon as I got to the dampning part, I felt something fishy was going on...  So I figured just to satisfy that hunch, I'd override some of numbers that the spring code crunches and specify that "_dampningForce" is always 0.0.  I go back to the demo, jam some balls into the walls, drag 'em out, and nothing!  I balls popped out and continued to follow my cursor.  I wasn't able to reproduce the NaN errors. (At least not in that demo.  I admit it's late and I haven't put a whole ton of research into this...) After that I figured I'd try stepping myself through that code keeping track of values in Notepad.  Surely enough, that dampning stuff can cause the force being applied to increase exponentially. (Of course smaller update timesteps would cause it to be a little more tolerant, but not everyone can just double their framerates.)

Here are the values I used when I manually debugged that code:
WorldAnchorPoint = (0,0)
BodyAnchorPoint = (10,0) // Relative to world.
BodyVelocity = (1000,0) // Some outside force causes the object to reach a high velocity.  Nothing especially unusual.
BodyMass = 0.1 // Same as demo.
SpringConstant = 20 // This is what the demo uses.
DampningConstant = 10 // Demo, again.
_restLength = 0

Stepping through the code, the following variables are set.  Listed in order of being set.
_difference = (10,0)
differenceMagnitude = 10
_differenceNormal = (1,0)
SpringError = 10
_springForce = 200
_temp = (10000,0) // First part of dampning calculation.
_dampForce = (10000,0)
_force = (-10020,0) // Seems kinda high...

That _force is then sent to ApplyForceAtLocalPoint.  If the body has a mass of 1 and the timestep is rather large, that definitely looks explosive.  So let's figure what the next frame will look like, assuming the timestep was 0.1. (10 updates per second.)

BodyAnchorPoint = (-892,0) // It was just zooming to the right and now it's on the left?
BodyVelocity = (-9020,0) // !? Please verify what I'm calculating here, I'm just doing it in my head.

Running the spring code again should then produce a force in the hundred-thousands, then millions, and eventually infinity.  That infinity then goes into some matrix operations and congratulations, it's a NaN! (Inf * 0 = NaN)

So now I'm curious.  I figure the whole DampningContsant thing is just a way to keep the spring from pulling things in too quickly.  Does it serve any other purpose?  Is that functionality already handled by LinearDrag?  Should the dampning only lower the force the spring applies rather than the velocity of the the body itself?

I didn't see any spring-related code in the repository for 3.0, so maybe you haven't implemented them.  Therefore I couldn't check if you were still using Dampning.  Let me know if there is any validity to what I've posted, 'cause that would be awesome if I did something right for once.  No surprise if I'm wrong somewhere though.

~Yota

Apr 27, 2010 at 4:28 AM

I've ran into this problem as well and have seen other posts about this on the forum. Does anyone have any suggestions on recommended values for a linear spring and accordingly mass? Thanks!

Apr 27, 2010 at 4:38 PM
Edited Apr 27, 2010 at 4:41 PM

The general suggestions have been to just try and keep speed low, making physics updates more frequent, and not letting the mass of different bodies vary too much.  With my finding here, that may not be necessary.  Try setting the DampningConstant of the spring controller to 0, and let me know if that solves anything.  I forgot to actually test this when I was doing all that testing a month ago, but I'm fairly sure setting that to 0 will have the same effect as commenting out that part of the physics code. (Aside from lowering processor costs.)

May 1, 2010 at 3:45 AM

@Yota: I'll definitely give those suggestions a try. Thanks a lot!