Sign in to follow this  
raigan

Uniform gravity at different framerates

Recommended Posts

hi, I'm trying to get gravity in a new simulation to resemble what it was in an old simulation. The problem is that the old simulation was written without regard for units, both simulations are running at different rates, and in general I'm a bit unclear about how to approach this sort of conversion. The old simulation was run at 25ms/frame (40fps), and did this:
acc = 0.8;         //this is in "pixels per frame" units
vel += acc;
pos += vel;
The new simulation runs at 16ms/frame (60fps), and does this:
acc = X;           //this is in "pixels per second"
vel += acc*deltaT; //deltaT is 1/60
pos += vel;
(Both simulations are using a fixed timestep.) Can anyone explain how I might go about determining the value of X above? Or better, how might I to do the following (if such a thing is possible)?: (a) convert gravity from a specific simulation into a "framerate agnostic" value (b) convert a "framerate agnostic" value into an equivalent specific value for a given framerate I feel like exp or log or something should have something to do with it, but instead of fumbling around I figured I'd defer to your better knowledge :) thanks, Raigan

Share this post


Link to post
Share on other sites
I think you mean this, since distance traveled equals velocity x time traveled.

acc = X; //this is in "pixels per second"
vel += acc*deltaT; //deltaT is 1/60
pos += vel*deltaT; // <--- added "*deltaT"

This is called the symplectic Euler integration algorithm. A more accurate algorithm is this SUVAT equation based on Newton's equations of motion:

acc = X;
vel += acc*deltaT;
pos += vel*deltaT + 0.5*acc*deltaT*deltaT;

http://en.wikipedia.org/wiki/Equations_of_motion

Cheers,
Mike

Share this post


Link to post
Share on other sites
Acceleration is measured in "pixels/frame^2" or in "pixels/s^2". The simple conversion says that 0.8 pixels/frame^2 = 0.8 pixels/frame^2 * (40 frame/s)^2 = 1280 pixels/s^2. Now you can convert back to 60 fps if you want, and you get 32/9 = 0.3555556.

Because you are using Euler integration, the results won't be identical (they can't be). If you want to match the distance dropped in one second, you should multiply 0.8 by 40*39 instead of 40*40. But these effects are small enough that you probably don't care.

Share this post


Link to post
Share on other sites
@h4tt3n: Thanks -- actually this is an error in my code, not just in transcription.. previously I was doing everything in per-frame rather than per-second units, and it's hard to tell exactly where there are implicit "multiply by 1"s in the code.

@alvaro: Awesome, that makes perfect sense, thanks so much! :)

Concerning "the results won't be identical (they can't be)": in both cases, won't a particle with a starting velocity move along the same curved trajectory? The different frame rates between simulations will result in a different piecewise-linear approximation of the curve. So, the same underlying curve, but different sets of sampled points on the curve. Is this wrong/mistaken?

TBH I have very little formal understanding of integration :(

Share this post


Link to post
Share on other sites
Small correction of my code sample, sorry for the inconvenience. Pick either of these instead of what I first wrote.


acc = X;
vel += acc*deltaT;
pos += vel*deltaT - 0.5*acc*deltaT*deltaT; // minus not plus


or this one:


acc = X;
pos += vel*deltaT + 0.5*acc*deltaT*deltaT; // pos first then vel
vel += acc*deltaT;


cheers,
Mike

Share this post


Link to post
Share on other sites
The problem is that you are using delta time in your calculations which is causing your calculations to give different results each run,

What you need to do is move to something called "Fixed Time Step"

here's what you do...

Instead of having your function look like below:


void CPhysicsSimuation::UpdatePhysics(float fDeltaTime)
{
m_vPos += m_vSpeed * fDeltaTime;
}




what you want to do is something like this...


void CPhysicsSimuation::UpdatePhysics(float fDeltaTime)
{
m_fTimeBucket += fDeltaTime;

while(m_fTimeBucket > 0.15f)
{
m_fTimeBucket -= 0.15f;
m_vPos += m_vSpeed * 0.15f;
}
}




In the example above it's only moving a single object but what you would want to do in that while loop is update ALL objects once.

Hopefully you can see how this works and makes sense to you.

There are some other considerations for trying to make a simulation play back deterministically but this is the biggest one so you are on your way (:

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this