0
101 Apr 08, 2009 at 04:49

Hi all, I’m looking for a new approach to this animation math algorithm.

This approach is time line based and not relevant to the current frame. The reason for the change is that I need to be able to set FPS on the fly. If I do that in this case the frames will jump. I would expect a FPS change from 30 to 50 to jump, but this function will go nutz even if the frame rate is changed by one in some cases especially going down ( 30 to 29 ).

here is the code.

const s32 lenInMs = abs(s32( (EndFrame - StartFrame) / FramesPerSecond));
if (FramesPerSecond > 0.f) //forwards...
{
return StartFrame + ( (timeMs - BeginFrameTime) % lenInMs) * FramesPerSecond;
}


BeginFrameTime is set in the constructor
BeginFrameTime = os::Timer::getTime();

timeMs is the current Timer::getTime();

What I think I need here is a way to return currentFrame + one “vector” of movement. I have the currectFrame but I cant seem to get the math right. This way, when the FPS changes it just increase rather then jumping around. As I said its ok if the change to FPS is a great amount, that is understandable.

I had a few methods to this but I’m out of ideas, its just not working as I hoped, can any one take a stab at this?

#### 4 Replies

0
167 Apr 08, 2009 at 05:02

Let me just see if I understand this correctly. You have an animation that is authored in terms of frames, which goes from StartFrame to EndFrame (these are frame counts)? You want to be able to adjust FramesPerSecond while the animation is playing and have it respond continuously?

Assuming that is correct, I think the problem is when FramesPerSecond changes, the *current* frame of the animation is not maintained. For instance, if FramesPerSecond is initially 30 and we are 5 seconds into the animation, we will be on frame 150. If we then change FramesPerSecond to 29, then we will jump back to frame 145, which could cause a noticeable pop.

The most elegant solution is probably to maintain a variable that indicates which frame the animation is in, and increment this variable every time you run your update code based on the amount of time passed since the last update. The variable should be float so that it can handle partial animation frames; you round it to integer if necessary when deciding which animation frame to actually display.

0
101 Apr 08, 2009 at 16:41

Reedbeta, you understand this correctly. There is a member variable called CurrentFrameNr. This variable is always the frame I’m on and is also updated via the return from above. As I stated I would like to do what you suggest.

“What I think I need here is a way to return currentFrame + one “vector” of movement.”

But the problem I have is calculating the unit or vector or section of time.. How much to move? This is where I’m stumped. Of course I need to calculate this from the FPS( actually its when it comes in to the function milliseconds ) Time_inl and begin in mil ( timeMs , BeginFrameTime ) and length_in_mil(lenInMs ). But so far I have not nailed it down right.

0
167 Apr 08, 2009 at 16:54

You need to calculate the time (in milliseconds, say) since the last update. That means you need to record the time of each update and keep it in a variable so it can be used in the next update. Then just increase the frame count by FramesPerSecond * TimeSinceLastUpdateInMs / 1000. As mentioned the frame count will probably need to be a float.

You can come up with this formula by looking at the units. You want a number of frames, so you must multiply FramesPerSecond by a time in seconds; by definition that will give you a number of frames. A time in seconds is of course a time in milliseconds divided by 1000.

0
101 Apr 08, 2009 at 19:57

I kind of crossed that thought, so there would not be a way to calculate a unit based on this information, and I would have to do an old and new and get the difference? I guess I’ll give that a try.

Ok here is what I came up with. Let me know if you see a flaw. So far it seems to be doing the job.

const s32 lenInMs = abs(s32( (EndFrame - StartFrame) / FramesPerSecond));
if (FramesPerSecond > 0.f) //forwards...
{
CurrentFrameNr += (timeMs - lastTime) * FramesPerSecond ;

lastTime = timeMs;
if ( CurrentFrameNr >  (EndFrame) ) CurrentFrameNr -= (EndFrame - StartFrame); //if we over shot the end frame back it up to the begining.
return CurrentFrameNr;
}