Sign in to follow this  

Smooth Animations

This topic is 2812 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi, i am trying to achieve really smooth animations under the following conditions:
  • vsync on or off
  • opengl or directx
  • windowmode or fullscreen
I have read everything i can find on the topic. Some suggest turning on vsync some suggest turning it off. Some say use fixed timesteps others say use a speedfactor. I have tried:
  • vsync on
  • vsync off
  • fullscreen
  • windowmode
  • both render APIs
  • double buffering
  • hires timers (windows)
  • ctimer
  • fixed time steps
  • dynamic time steps
All of my animations did not run really smooth. The best results (close to perfect) were achieved using fullscreen mode with vsync off. The most problematic case is windowmode with vsync on. Any helpful links or tips would really be appreciated. Some informations on my setup. I am currently rendering a none textured quad that moves on a straight line.

Share this post


Link to post
Share on other sites
like i said. i am trying to move a quad from 0,0,0 to 5,0,0 with a linear animation speed. the animation seems jerky (you can realise that espacially looking at the edges). i would make a video but fraps would probably disturb the results.
if you are not able to relate to the problem directly dont worry just give any information on the topic that comes to your head. links, keywords, anything...

i would especially like to hear how you take care of animation speeds.

thanks

Share this post


Link to post
Share on other sites
ok so you arent doing 2d sprite animation or 3d skeletal keyframed animation, you are just moving a box across the screen.

So i'm going to have to mind read you on this cause you didnt give us very much info but i think i know whats going on.

Ok, the problem is that you are moving the box a constant amount every frame (such as 10 units lets say), but frame rate fluctuates from frame to frame based on all sorts of factors outside of your control, which makes it so that some frames might be 15ms lets say, and others are 30ms, but both those frames have the box moving 10 units, which means that the box is actually changing how fast it moves across the screen as the frame time changes.

There is a solution though!

Basically what you need to do is measure how long your last frame was, and multiply your speed by that amount when moving it ever frame.

For example here's simplistic some pseudo code:



void Main(void)
{
DWORD dLastFrameTime;
DWORD dFrameElapsedMS;

//fake the first frame
dLastFrameTime = GetTickCount() - 15;

//move the box at this speed
float fBoxSpeed = 2.0f;

while(1)
{
dFrameElapsedMS = dLastFrameTime - GetTickCount();
dLastFrameTime = GetTickCount();

BoxMovementSpeed = (((float)dFrameElapsedMS) * fBoxSpeed);
MoveBox(BoxMovementSpeed);
}
}




Hopefully you understand the essence of that, but what that does is make it so that if the frame takes longer, it moves the box farther. If the frame takes less time, it doesn't move the box as far.

Make sense?

Share this post


Link to post
Share on other sites
This is a common question, there could be several things happening.

When you run in windowed mode, vsync is disabled and the framerate is unbounded. If your games update is linked with framerate or your interpolating motion on a frame by frame basis, the incremental movement vector is so small that any subtle 2ndary factors (cpu load on ur machine from background processes for instance) can result in large variance of the movement vector. Even though you may have +200fps, the large variance between frames can result in un-even movement.

Better to have a solid 60fps low variance than 200+fps with high variance.

Could be your not interpolating motion over time or your time interpolation has some subtle errors or side effects, that happens alot as well. Like above if your just taking the raw difference in time between frames, at high frame rates the variance can be very high. These large variance in time will then trickle down through the system and exhibit itself as slightly annoying jerky movement, even though you have high fps.

You mentioned that you tried fixed timesteps. Depending upon how you implement it this also can result in jerky movement. Just updating a fixed step every frame can result in jerky movement if your framerate itself is highly variable. For instance if your frame rate is say 60fps on average and but ever once and a while it drops down to 30fps, but only a few frames. This will exhibit itself as a stutter or slow motion when using non-time corrected fixed timesteps.

If you tried to time correct the fixed timestep method (ie multiple fixed steps to maintain close to realtime) this also can result in jerkyness, mostly due to how you implement it. If you keep a sum of time between frames and when the sum > fixed timestep time you do an update, this scheme can result in a periodic frame doubling where you get a occasional double update. This can appear as a periodic skipping.

Good Luck!

-ddn

Share this post


Link to post
Share on other sites
hi,
thanks for all the responses, especially the last one.
i probably did not put enough info in to the first post. i`ll try to elaborate:

- fixed time steps: i used the technique described in this link (which is probably more physics oriented but still should work just fine): http://gafferongames.com/game-physics/fix-your-timestep/

- dynamic time steps: very common approach use the time difference of each frame to move the quad with a dynamic speed (speed * frame_time)

- filtered time steps: i collected different frame times (for the last: 30, 60 or 100 fps) and averaged the result. frame_time = avg_frame_time

Since the last i moved the windows msg pump handling to the top of update loop which helped a bit. I am still not fully satisfied with the result.
Maybe i am just trying to hard and not much can be done running something in window mode. threading and multitasking could just interfere to much with the update loop. if i have time i`ll post some sample applications that could be used to compare my experiences with your observations.

@Atrix: i hoped that dynamic time steps was information enough so that you could imagine that thats exactly what i am doing.

Share this post


Link to post
Share on other sites
Ok, I don't have any links, but I will try my best to explain how I do it (Sorry for my English):

First, I use fixed time step. (60 fps, or 30). But I do not render 60 fps.

Every frame:

int numberOfFrameToUpdate = fixedTimeStepTimer.UpdateTimer();
while (numberOfFrameToUpdate--)
{
// Update your scene
}
// Render your scene


Then now, you have to find what is the remaining time before the next update. If your fixedTimeStepTimer.UpdateTimer() returns you one frame, but almost 2. You should try to find that percentage left (0 to 1).

Then in your update, you always keep track of the last position/matrix for every of your objects. And you lerp in your rendering.

This gives incredible smooth results.
Cons:
- Need to keep track of last frame variables all the time, for every animated things. (If you have a good entity system, you probably have only one place to add this ;))
- You are behind simulation a bit. So you might noticed delay in the inputs in some cases, like if you update at 30 fps instead of 60.

Share this post


Link to post
Share on other sites
Quote:
Original post by flery
Since the last i moved the windows msg pump handling to the top of update loop which helped a bit. I am still not fully satisfied with the result.

Post your message loop, there is a risk it's still not perfect. Where do you update the variables, and where do you render the graphics?

Here follows my message loop that I used a while ago, it works smoothly for me when I use accumulated fixed time steps in the "Update" call:


//run message loop until user quits
MSG msg;
bool bRun = true;

while (bRun)
{
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
{
bRun = false;
break;
}

TranslateMessage(&msg);
DispatchMessage(&msg);
}

if (bRun) //some app-functions need active window
{
gApp.Update();
gApp.Display();
}
}


Share this post


Link to post
Share on other sites


int DLL start(IApplication* app)
{
int argc = 0;
app->OnInit();

bool done = FALSE;

msw::Window* w = new msw::DX10Window();
//msw::Window* w = new msw::GLWindow();
w->create("F3 Test",1000, 1000, 32, false);
w->setPosition(0,0);
w->initRenderAPI();
w->show();


float t = 0.0f;
const float dt = 0.01f;

float currentTime = f3::util::time();
float accumulator = 0.0f;

while (!done)
{
HandleMsgPump(done, w);
float newTime = f3::util::time();
float deltaTime = newTime - currentTime;
currentTime = newTime;

accumulator += deltaTime;

while (accumulator>=dt)
{
app->OnUpdate();
t += dt;
accumulator -= dt;
}

if (w != NULL)
w->paint();

}
return 0;
}

void HandleMsgPump(bool& done, msw::Window* w)
{
MSG msg;

if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
{
if (msg.message==WM_QUIT)
{
done=TRUE;
}
else if (msg.message == WM_KEYDOWN)
{
switch (msg.wParam)
{
case VK_F4:
if (w->getFullscreen() == false)
{
w->setFullscreen(true);
}
else
{
w->setFullscreen(false);
}
break;
}
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}



thats the accumulator version
thanks for sharing Daivuk & Dim_Yimma_H

Share this post


Link to post
Share on other sites
This is my game loop and I get perfectly smooth animations in window mode, fullscreen, v-sync on and off.


// TICKS_PER_SEC is the update rate, I have it set at 25Hz
void run(void)
{
const int64_t timestep = tickfreq()/TICKS_PER_SEC; // TODO: calc once
static int64_t next_tick = 0;
int count = 0;
float a;

if (!next_tick) next_tick = tickcount();

while (tickcount() >= next_tick && count < MAX_FRAMESKIP) {
update();
next_tick += timestep;
++count;
}
a = (tickcount()+timestep-next_tick)/(double)timestep;
draw(a); // I use a to interpolate between previous and current state

glfwSwapBuffers(); // Window messages gets pumped here by glfw
}




Here is the main loop:

start = tickcount();
invfreq = 1/(double)tickfreq();
done = 0;
while (!done) {
done = !glfwGetWindowParam(GLFW_OPENED);
if (glfwGetKey(GLFW_KEY_ESC)) done = 1;
run();
if (framelimit > 0) {
while ((tickcount()-start)*invfreq < 1/((float)framelimit*1.2f)) Sleep(1);
while ((tickcount()-start)*invfreq < 1/(float)framelimit) ;
}
{
char str[128];
double fps = 1/((tickcount()-start)*invfreq);
sprintf(str, "fps: %.2Lf", fps);
glfwSetWindowTitle(str);
}
start = tickcount();
}



I try to check if v-sync is on, if it is I set framelimit to 0, otherwise I set it to 60 (or let the user set the limit).

Share this post


Link to post
Share on other sites
I've noticed that in my tests, regardless of the time-stepping scheme, the movement of translating polygons can appear to be un-smooth because of aliasing; especially at slower speeds, there are e.g sudden jumps as columns of pixels turn on/off when a square is translating horizontally.

IMO some sort of spatial and/or temporal anti-aliasing is needed if you want super-smooth movement of 2D polygons.

For spatial AA, you could try using GL_SMOOTH drawing, or FSAA/MSAA/CSAA/etc.

For temporal AA, AFAIK there is no "best" method for this, most people seem to either take a multisample approach (render the scene at multiple times between the previous and current state, using additive blending to accumulate) or a geometry-based approach (create fin/trail geometry based on velocity). The former approach breaks down under large movement (you can see the samples spaced out individually) and the latter is tricky to get working with arbitrary movements (i.e objects that are spinning as they translate). I know some 3D games use post-processing to achieve motion blur, the same approach should be applicable to 2D.. right?

Share this post


Link to post
Share on other sites
i compared the fps rates between ogl and dx10 (forcing on vsync with driver settings for opengl and using presentation interval for dx)
left = current fps, right = average framerate

Open GL:

[ 1] FPS: 180.49 60.0014
[ 1] FPS: 49.9521 60
[ 1] FPS: 49.9453 60.0016
[ 1] FPS: 50.0262 60
[ 1] FPS: 50.0125 60.0009
[ 1] FPS: 68.9501 59.9518
[ 1] FPS: 182.647 60.0087
[ 1] FPS: 49.9819 60.0031
[ 1] FPS: 49.9827 60.0371
[ 1] FPS: 49.9964 60.0022
[ 1] FPS: 50.0501 60.0021
[ 1] FPS: 68.5235 59.9519
[ 1] FPS: 184.542 60.0013
[ 1] FPS: 50.0373 60.0028
[ 1] FPS: 49.8867 59.9981
[ 1] FPS: 50.0339 60.0006
[ 1] FPS: 49.7818 59.9869
[ 1] FPS: 68.5379 59.9526




DX10:

[ 1] FPS: 62.4125 59.9392
[ 1] FPS: 58.9586 59.9273
[ 1] FPS: 61.1321 59.9424
[ 1] FPS: 59.8128 59.9511
[ 1] FPS: 58.5937 59.9124
[ 1] FPS: 61.2086 59.9301
[ 1] FPS: 59.316 59.9293
[ 1] FPS: 59.6863 59.9094
[ 1] FPS: 61.215 59.9425
[ 1] FPS: 58.8876 59.9327
[ 1] FPS: 60.4721 59.9283
[ 1] FPS: 59.7629 59.9638
[ 1] FPS: 60.3515 59.9465
[ 1] FPS: 59.1618 59.9042
[ 1] FPS: 60.4933 59.943
[ 1] FPS: 60.2376 59.9611
[ 1] FPS: 59.5459 59.9379
[ 1] FPS: 60.2561 59.9274
[ 1] FPS: 60.0822 59.9298
[ 1] FPS: 59.4795 59.9531
[ 1] FPS: 60.7249 60.0393
[ 1] FPS: 58.9693 60.02




As you could expect the animation looks much smoother in directx than it does with opengl. Is that a driver issue? Should I try to handle frame limitation by myself? I thought the driver would know best when the monitor is expecting the next frame.

its really weird its exactly every 6th frame that spikes.

[Edited by - flery on April 3, 2010 8:49:46 AM]

Share this post


Link to post
Share on other sites
after some profiling i found out that SwapBuffers(HDC) performs in very uneven ways. this is the reason for the varying frame rates. i have yet to find a way to fix that.

Share this post


Link to post
Share on other sites
Quote:
Original post by flery

its really weird its exactly every 6th frame that spikes.


A frame is rendered every 20ms (50fps) when it should be rendered every 16.6ms (60fps). Then, every 6 frames it catches up (5ms/180fps) to maintain 60fps average.

What happens if you comment out the actual drawing so that it just draws empty screen? Excluding a bug in driver it leaves the incorrect or too heavy usage of OGL which causes the spikes.

Assuming that the timing measured is correct.

The only thing where 50Hz vs. 60Hz comes to mind would be NTSC vs. PAL, but I don't see how this could matter here.

Share this post


Link to post
Share on other sites
i only timed the swap buffer command and it is the root of the problem. drawing an empty scene (or no scene at all, just swap buffers) has the same effect. managing the frame rate by myself seems to solve this problem. if someone has a nicer solution please tell.

Share this post


Link to post
Share on other sites
Could you explain what you mean by "managing the frame rate by myself"? Do you just mean no-vsync? Sorry if this is obvious.. it's not clear to me how you would ever NOT be managing the frame rate yourself!

Share this post


Link to post
Share on other sites
Yes, i ment no v-sync. Turning on V-Sync leads to the driver managing the frame rate with blocking. Disabling vsync and using a max fps value is not the exact same behaviour i would asume, but at least i get decent animations.

with a bit more profiling i saw weird behaviour using wglSwap instead of SwapBuffers... i'll post a graph later. Anyone else experiencing that?

Share this post


Link to post
Share on other sites

This topic is 2812 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

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