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

gravity, right formula, rounding problem

Started by ^cyer Oct 15, 2000 at 6:21 PM 12 replies 800+ views
Original Post
^cyer
^cyer
hello, hello i use formula from physics book ..u know x = x + v*elapsedtime...etc...game is fast and it is locked on the refresh rate of monitor, but problem is that if i run game on 60hz and then on 100hz and then i jump with 2d hero i get difference about 4 pixel for a given accelerating(-1340) and velocity at start is 1200, i got even more problems bcos i used INT all around, now u use DOUBLE and round that to integer just before i need a whole int... like this.. //all are double y = y + elapsedtime*v + 0.5*(-1340)*elapsedtime*elapsedtime; v = v + elapsedtime-(-1340); then one int yfromjump = yfromjump + int(y); then i draw using yfromjump for y can u help ? sorry for bad ass english
baskuenen
baskuenen
v = v + elapsedtime-(-1340);
should be
v = v + elapsedtime*(-1340);
But this is probably a typing error.

-1340 is a strange gravity force. Is 9.8 too slow, or isn''t your time measured in seconds?

It should work fine, since you''re only using int''s for drawing. I''m not sure what you''re getting at. Maybe you can copy paste some of the sourcecode you can find at this link. Hope it helps...
- Bas


^cyer
^cyer
hello again baskuenen or sth,
yes that was a typing mistake...ok,
your tutorial is good and i want to do the same thing, i use the same formula etc, ahm, what did u think time measured in second, i use QueryPerformanceCounter every loop and then i do like this:
//beging of the program
QueryPerformanceFreq...i get from this freq. then i do 1/thisfreq and store it like in ''timerFreq''.
QuerPerforamceCounter...
//in main loop
ElapsedTime = (LastTime - ThisTime)*timerFreq;
LastTime=ThisTime;

//in use ElapsedTime then in formula i mentioned about in first post, whats that story about measuring in seconds?...

thanks for you answer,
my english is very shi** indeed
Eric
Eric
I don''t know exactly what you''re getting at, either, but your equations don''t look right to me.

Specifically, you have:

new position = position + velocity*time + 0.5*accel*time*time

(time = elapsed time). The position on the RHS should be your *initial* position, and the velocity on the RHS should be your *initial* velocity. But I take it you''re executing this code every frame, so both of those values are changing.

If I were you, I would just do this every frame:

v -= 1340*time;
y += v*time;
(and then the yfromjump thing)
^cyer
^cyer
hello,
if i use Eric formula its little better,
but if i run in 60hz and then in 100hz i get 2 pixel error,
so the error is still here,probably its little better because this formula doesnt use so much multiplication, anyway what can i be doing wrong i dont know...its driwing me crazy
grhodes_at_work
grhodes_at_work
quote:
Original post by ^cyer

hello,
if i use Eric formula its little better,
but if i run in 60hz and then in 100hz i get 2 pixel error,
so the error is still here,probably its little better because this formula doesnt use so much multiplication, anyway what can i be doing wrong i dont know...its driwing me crazy


I'll give you a detailed explanation for what could be happening to cause your 2/4 pixel error. (There may be other implementation errors that I don't know about that could be causing problems.) I know you are using QueryPerformanceCounter to determine elapsed time. I am certain that the value of elapsedtime is different when you run at 100Hz vs. 60Hz. You can do some profiling to check this.

I feel certain that the error of 2/4 pixels that you describe is not a mystery. It is simply because of the different values of elapsedtime and the characteristics of the way you are doing your simulation (in mathematical terms it is called finite difference integration).

Lets look at an example. Let elapsedtime = 1/50 = .020. I choose this because it is twice the time step as 1/100 and is useful for an example. Suppose the current velocity and position are both initially zero. Then (using Eric's suggested approach):

First time step (the current time is = 0.02 seconds)

v -= 1340*time = 0 - 1340*0.02 = -26.8 when current time = 0.02s
y += v*time = 0 - 26.8*0.02 = -0.536 when current time = 0.02s

Now lets look at the case when elapsedtime = 1/100 = 0.01:

First time step (current time is 0.01 seconds):

NOTE: you CANNOT compare this time step with the first time step from the elapsedtime = 1/50 case, since the "current" time is not the same. Here current time is 0.01 seconds vs. 0.02 seconds above, and the velocity and position *should* be different---its correct that they are different!

v -= 1340*time = 0 -1340*0.01 = -13.4 when current time = 0.01s
y += v*time = 0 - 13.4*0.01 = -0.134 when current time = 0.01s

Second time step (current time is 0.02 seconds):

NOTE: *this* time step----the second time step using elapsedtime = 1/100 can be compared to the FIRST time step using elapsedtime = 1/50 above, since they both correspond to the same "current" time of 0.02 seconds----we'd LIKE the results to be the same!

v -= 1340*time =-13.4-1340*0.01= -26.8 when current time = 0.02s
y += v*time =-0.134-26.8*0.01= -0.402 when current time = 0.02s

Now you see that the velocity is the SAME as the first time step above----that is good. But the position is DIFFERENT, which is the behavior you're seeing in the 2 pixels or 4 pixels difference.

So, you can see that you *WILL* get different results if your value of elapsed time changes. It just works out in the formulas! No mystery.

But, you might ask "Why?". I think you don't want the whole theory of truncated Taylor series expansion, which is the theoretical basis for what you're doing with your formulas. So I'll give you the short answer. As long as acceleration is constant, velocity will grow as a linear function of time---and no matter what value of elapsedtime you use the velocity will be correct. If acceleration changes, the velocity will not grow as a linear function of time and it will start to deviate depending on changes in elapsedtime. The position y will be correct for any value of elapsedtime ONLY WHEN THERE IS ZERO ACCELERATION. For any nonzero acceleration, position is not a linear function in time and there will be errors that are different for different values of elapsedtime----this could be what you are seeing in your program.

How to correct this? You could reduce the 2/4 pixel error by using a more accurate integration technique. This can be done fairly easily---requires a bit more storage and would eat a few CPU cycles, but it can be done. It might reduce the error to 0 pixels or only 1 pixel, but in the mathematics some error would still be there. Unfortunately, it takes too much explanation to go over that here.

There are basically two ways to *guarantee* you'll get exactly the same results regardless of refresh rate when simulating physics. The first way is to use the same values of elapsedtime regardless of CPU speed, refresh rate, resolution, number of colors, etc. That's a bit tricky. Really tricky. You don't want to just hard code your value of elapsedtime because then the animation will run across the screen twice as fast on a CPU that is twice as fast, half as fast on a CPU that is half as fast. So this first approach is not practical. The second way is to use exact solutions when you know them, rather than finite difference integration. You'll still get different positions when elapsedtime is different, but the results will be identical whenever the current time matches between machines running at different refresh rates and that is the best you can ask for.

Actually, there's a third way that can work, if you're willing to accept some limitations. Calculate the solution up front and store it in a resource file. Then, as the game runs, just load the result for each time step from the resource file. Use linear interpolation if you need an intermediate result. Allows less flexibility, but it could give you the same motion within a pixel or less regardless of refresh rate, CPU speed, etc.

And yet a fourth way.... Don't use physics at all. Just create an animation path and play it back the same every time.

As for using seconds vs. performance counts, I think your formula above actually calculate the time in milliseconds, which is fine although seconds may be more intuitive. I would *strongly* recommend that you represent velocity, acceleration, and position in some real-world units such as meters/second, meters/(second^2), and meters. You should use values that are intuitive rather than obscure. I personally consider physical motion properties measured in pixels to be obscure and difficult to debug. Your mapping can simply be to say that your screen is 10 meters wide and 8 meters tall, or something like that. Simple conversion to be sure, but more intuitive. And of course you need to be using floating point numbers.

I know the answer was long, but I hope it helps!

Graham Rhodes
Senior Scientist
Applied Research Associates, Inc.
email: grhodes@sed.ara.com

Edited by - grhodes_at_work on October 16, 2000 1:54:54 PM
Graham Rhodes Moderator, Math & Physics forum @ gamedev.net
punkfloyd
punkfloyd
I dopn''t know the requirements for your engine but I am positive many 2d games actually do not use the real acceleration calculations (btw your original formula x+= v*t + a*t*t/2; v+=a*t *is* absolutely correct. The simpler Eric''s formula is also correct but it is just a less-precise approximation of the full thing)

Anyhow, in many 2D games they seem to use precalculated tables of values. This way they can always fine tune their falls and other animations and make sure they always end up exactly where you intend them to. This also solves the problem that humans usually perceive the motion not as a completely smooth process but as a sequence of "keyframes" with inbetween motion. "Physically correct" simulations often tend to miss these because they fall between frames. An example:
Consider an animation of a bouncing ball. If you do it physically correct then you will get situations when at the beginning of a frame a ball is stilla bove the ground and is moving downward while at the end of the frame it has already bounced and is now above the ground moving upward. Because of this the player will see a ball bouncing *above* the ground level. This is visually unacceptable even tho it is physically perfect. You have to tweak it so it looks right.
This can be either by some heuristic formulas (force the character onto the floor, when he is nearby) or by precalculating the animation.

OD


^cyer
^cyer
hello again,
i am amazed how many people tryed to help me, so one big thanx goes to all of youI read all post and i think i will use that knowledge in the future, about my problem, i solved it, it was mixture of as i said before that i used int and not double(rounding problem) but then still the problem was there, after a few hours i saw that i have wrong formula, instead of x = x + v*elapsed+0.5*a*elapsed*elapsed i had x = x + v*elapsed +0.5*a*elapsed (notice that i didnt do elapsed^2)..after i fixed that it works perfectly on all monitor freq. that i tryed (60,75,85,100,120...) it jumps the same amount,
thank you again for your support,
bye

^cyer
Eric
Eric
Punkfloyd, I see now, cyer's original equations are correct, in fact more correct than mine, as you say. It's odd, I've always seen acceleration/velocity/position done using the simpler equations I've listed. It seems like the only possible drawback of the more accurate equation is that you need to track your net acceleration every frame in order to be able to plug it in. I don't know if this is of interest to anyone else, but lemme' just guess at how this would work:


p = whatever;
v = 0;
game loop{
a = 0; // reset net acceleration each frame

// during input-handling
if(accel key is down){ a += player_direction * PLAYER_ACCEL; }

// during collision
if(collision occurred){ a += ???; }
// Crap, that won't work. The acceleration from a collision is
// not constant over the entire frame, and it should be
// independendent of frame-rate. Maybe just leave it out, and
// modify velocity directly, like this?
if(collision occurred){ v += normal_force_or_whatever; }

// other stuff...
a += gravity;
a -= v * AIR_RESIST; // where AIR_RESIST is a percent value

// and then...
p = p + v * delta_time + 0.5 * a * delta_time * delta_time;
v = v + a * delta_time;
}


Also, Graham, I would like to learn about the more accurate integration techniques you mentioned... not so much for this type of simulation, but in situations where you're modeling springs or cohesion, I know the system will tend to blow up if your frame-rate is not high enough, and I understand that a more accurate integration technique will allow these systems to run at lower frame-rates. Unfortunately I haven't found a resource that relates these other techniques to physics simulations... any suggestions?

Edited by - Eric on October 16, 2000 6:55:35 PM
baskuenen
baskuenen
If you would use
    y = y + vt

You're only approximating because this v changes over time. You can say above equation draws a straight line from startpoint of frame to end point.

We need a parabole, 2nd degree equation like



    y = y + vt + ½at2


This ½at2 is the result form that integrated a thing



Edited by - baskuenen on October 17, 2000 3:11:17 AM
grhodes_at_work
grhodes_at_work
quote:
Original post by Eric
Also, Graham, I would like to learn about the more accurate integration techniques you mentioned... not so much for this type of simulation, but in situations where you''re modeling springs or cohesion, I know the system will tend to blow up if your frame-rate is not high enough, and I understand that a more accurate integration technique will allow these systems to run at lower frame-rates. Unfortunately I haven''t found a resource that relates these other techniques to physics simulations... any suggestions?

Edited by - Eric on October 16, 2000 6:55:35 PM


Eric,

As for frame-rate/time step, there are some methods that will eventually blow up at *any* frame-rate (no matter how high) that is less than infinite. For example, the explicit Euler technique (the simplest technique possible----one that some people actually use) will not be stable and will blow up if there is *any* springiness to the system. It cannot be made stable by increasing frame rate in this case. Also, the Runge-Kutta methods that people love so much can be unstable even for very very high frame-rates/time steps when there are very stiff springs in the system (e.g., stiff springs used to enforce rigid body constraints). It does help to know something about the numerical methods as you design a level or a model. That''s actually a focus area of some research I''m doing over the next several months.

Actually, I gave a talk at the XGDC conference in late September on exactly this subject. And I''ve submitted a proposal to do a similar talk at GDC in March. The XGDC material will be online soon (at the xgames3d.com site, link to X.G.D.C.) as a Powerpoint presentation and simple sample programs. The XGDC stuff covers too much really, including stability for continuum problems, but it does give some details on selecting a good, stable integration scheme. There''s just not enough in that material on how to IMPLEMENT the techniques. GDC talk will focus on implementation and examples with some theory as background material. One of the gamedev.net people has said that they''ll publish the GDC material online if it doesn''t actually get accepted to GDC or gamasutra. We''ll see. I''m considering starting this out *very* soon with an introduction (on gamedev) to what finite differences are all about and how they relate to relatively simple physics, such as the problem ^cyer described.

If you''re interested I can give you a couple of good references on numerical methods and stability. But I''ll warn you that they have a fluid dynamics twist and to make the jump to something like game physics/dynamics simulation requires a bit of thought. My talks kind of do the association for you and are not presented from a fluid dynamics point-of-view.

Let me know if you want the references.



Graham Rhodes
Senior Scientist
Applied Research Associates, Inc.
Graham Rhodes Moderator, Math & Physics forum @ gamedev.net
Eric
Eric
Graham, thanks for your response. Using springs for rigid body simulation is, in fact, what I had in mind. I will wait for the XGDC material to come online (and maybe I''ll hear your talk at GDC, if my IGF entry scores me a ticket ). I''d also appreciate the references related to fluid dynamics, though as you say they may be somewhat incomprehensible to me.
grhodes_at_work
grhodes_at_work
quote:
Original post by Eric

Graham, thanks for your response. Using springs for rigid body simulation is, in fact, what I had in mind. I will wait for the XGDC material to come online (and maybe I''ll hear your talk at GDC, if my IGF entry scores me a ticket ). I''d also appreciate the references related to fluid dynamics, though as you say they may be somewhat incomprehensible to me.


The references on numerical methods are below. Although the books are sort of "CFD" books, some of the chapters focus purely on numerical methods----selection of integration scheme and the stability and accuracy of the schemes. This stuff is *not* just for fluids. The first book is (I find) actually fairly easy to read as long as you know a bit of calculus. It may take a while, though. The second book is a bit more obscure, but unfortunately is more important for your purposes. I''d check these out of a local college/university library before buying, since they can be expensive and may even be out of print (due to low demand for this type of book). The XGDC presentation is *nearly* ready to go----I just had a few minor corrections to make, and I want to produce a PDF version instead of Powerpoint.

The tricky thing about using a fluid dynamics book to get ideas for numerically simulating rigid body problems is that the fluid dynamics books talk about simulation of Partial Differential Equations (PDE''s) while rigid body problems are governed by Ordinary Differential Equations (ODE''s). (By the way, PDE''s show up in soft body dynamics.) The XGDC stuff will talk about a "characteristic equation" with "complex roots" or "eigenvalues". These "eigenvalues" are exactly the same as "the eigenvalue spectrum of the space discretization" (terminology used in the book by Hirsch). Just do a replacement when reading the second book and some of the trickiness will go away.

The good news is, once you understand all this, it isn''t *that* hard to use it. And (I believe) it can be automated with a standalone tool----something that I hope to produce in my current IR&D project. Kind of a helper tool for implementing game physics, maybe a wizard that will spit out a shell of C code for doing the integration with a scheme that is good for the game of interest.

Using springs to enforce rigid body constraints is easy to code, but has the disadvantage of making a wider "spectrum of eigenvalues of the space discretization." Specifically, you''re going to be adding some high frequency "eigenvalues" that make it tricker to simulate in a stable manner. That boils down to making stricter limits on time steps/frame rates. With care, you can choose an integration method that allows the use of larger time steps/slower frame rates and is still stable. And *THAT* is what I''m trying to promote. Do NOT just blindly use a Runge Kutta method (which is NOT universally stable as most game physics programmers assume). Never use Euler Explicit (which is always unstable when there are springs). Choose something that is best for your problem. You''ll get better and more satisfying performance, and with a bit of up front work you can save tons of frustration and hair pulling trying to figure out why it blows up. I believe you can save time in the long run.

Tannehill, John C., Dale A. Anderson, and Richard H. Pletcher, "Computational Fluid Mechanics and Heat Transfer: Second Edition", Taylor and Francis, 1997. - chapters 2, 3, and to some extent 4, with chapter being most important for understanding numerical integration

Hirsch, Charles, "Numerical Computation of Internal and External Flows: Volume 1, Fundamentals of Numerical Discretization", John Wiley & Sons, 1988. - chapters 10 and 11 have discussions related to stable time integration of *ordinary* differential equations (ODE''s), which are the types you see in rigid body dynamics.

Check out www.xgames3d.com->link to X.G.D.C. from time to time to look for my XGDC presentation.

Good luck!




Graham Rhodes
Senior Scientist
Applied Research Associates, Inc.
Graham Rhodes Moderator, Math & Physics forum @ gamedev.net
Eric
Eric
Cool, thanks.

Topic Locked

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

Sign in to reply to this topic.