fixed timestep with smooth rendering

Started by
3 comments, last by Bow_vernon 10 years, 3 months ago

Hi, I got a few issues with my game frameworks, and I can't find the best solution to the problem.

Here's a long story short of my problem:

-my framework use fixed timestep updates (the physics engine require this)

-the "rendering" information (animation states, rotation, position) is also updated in the update(float t) function, which is called every n ms (fixed timesteps)

-the render() function then renders the game based on all "rendering" information

However, with "low" tickrate (20 Hz, 25 Hz), it looks soo jittery. I can't handle it. here's how the main loop looks (pseudo code)


int run()
{
  float lasttick=get_ticks()*0.001, curtick, dt=1.0/20; //it's 20 Hz update rate
  float accum=0.0f;
  while(running)
  {
    curtick=get_ticks()*0.001;
    accum+=curtick-lasttick;
    lasttick=curtick;

    while(accum >= dt)
    {
      do_input();
      simulate(dt);
      accum-=dt;
    }

    render();
  }
  return 0;
}

result? incredibly stable physics simulation (for now I merely do spring rope simulation, and when I used variable timesteps, it sometimes ASSPLODE! but fixed it now thanks to fixed timesteps).

However, the rendering is a bit "jerky", I could understand this since I only update their position every 50 ms, which is insufficient to trick my eyes into thinking that it's moving fluidly instead of jumping abruptly. How does one usually solve this?

Advertisement

Hi, I got a few issues with my game frameworks, and I can't find the best solution to the problem.

Here's a long story short of my problem:
-my framework use fixed timestep updates (the physics engine require this)
-the "rendering" information (animation states, rotation, position) is also updated in the update(float t) function, which is called every n ms (fixed timesteps)
-the render() function then renders the game based on all "rendering" information

However, with "low" tickrate (20 Hz, 25 Hz), it looks soo jittery. I can't handle it. here's how the main loop looks (pseudo code)


int run()
{
  float lasttick=get_ticks()*0.001, curtick, dt=1.0/20; //it's 20 Hz update rate
  float accum=0.0f;
  while(running)
  {
    curtick=get_ticks()*0.001;
    accum+=curtick-lasttick;
    lasttick=curtick;

    while(accum >= dt)
    {
      do_input();
      simulate(dt);
      accum-=dt;
    }

    render();
  }
  return 0;
}
result? incredibly stable physics simulation (for now I merely do spring rope simulation, and when I used variable timesteps, it sometimes ASSPLODE! but fixed it now thanks to fixed timesteps).

However, the rendering is a bit "jerky", I could understand this since I only update their position every 50 ms, which is insufficient to trick my eyes into thinking that it's moving fluidly instead of jumping abruptly. How does one usually solve this?

There's only two real ways to fix physics updates, honestly you should have your physics at a fixed timestep even if other update functions use variable time, it's not that hard, you just accumulate time and have the physics run one update step after a certain amount of time has accumulated.

But yeah, the only real options are: a. dial up the update rate, this really shouldn't be a problem and is probably the preferred way, maintaining like 60 hz or even higher of physics updates shouldn't be that rough as long as its consistant.

B. the only other way I know if is to use interpolation, essentially what you do is your physics will always be a step ahead of the rendering, for instance if you have a box falling straight vertical and its at say, 10y, and its going to be at 6y after 1 second, you can interpolate between those value by keeping the previous value and the current one, then rendering will basically "catch up" the box between its previous and current position, so it will never actually be where it "physically" is, but at the rate it updates, that isn't really a problem. i.e. at .25 seconds the box will be at 9y, then 8y, then 7y, so on.

It's not that challenging but it adds extra complexity, its a tradeoff that lowers the work the cpu has to do simulating physics while still looking smooth and plausible.

http://gafferongames.com/game-physics/fix-your-timestep/

Applies to any kind of graphical game really, 2d or 3d.


But yeah, the only real options are: a. dial up the update rate, this really shouldn't be a problem and is probably the preferred way, maintaining like 60 hz or even higher of physics updates shouldn't be that rough as long as its consistant.

Totally agree. 20-25hz seems awfully low for updates. In my project, I do updates at 100hz with a framerate of 45-60hz (which I do not control).

Are you giving back anytime to the cpu every time you update?

View my game dev blog here!

@thok, yes it's very low indeed. I merely want to test it since there's an iphone game that do 20Hz ticks with smooth graphics. I read that somewhere on a devblog but can't remember its URL @_@

@Solid_Spy, no, I don't use sleep() at the main loop.

Btw guys, I've fixed it. It's working good now! basically I just use the remaining frametime to update the "render data". the downside is that for every object I have to make a copy of its position and orientation, then use the remaining frametime to do interpolation. Now it's smooth as silk! Can't believe it, it runs as if I use variable timesteps, but with the stability of fixed timesteps. I can even do 10 Hz without any jittery at all. However the simulated rope settles down longer that way :p

Anyway here's the change I made to the framework:


int run()
{
  float lasttick=get_ticks()*0.001, curtick, dt=1.0/20; //it's 20 Hz update rate
  float accum=0.0f;
  while(running)
  {
    curtick=get_ticks()*0.001;
    accum+=curtick-lasttick;
    lasttick=curtick;

    while(accum >= dt)
    {
      do_input();
      simulate(dt);
      accum-=dt;
    }

    //now the frametime value could be anywhere between 0 <= frametime < dt
    //inside the update_render_data(), I only use simple integration to update object's render_pos and render_orientation. nothing else ;)
    //render_pos = pos + vel * frametime;
    update_render_data(frametime);
    render();
  }
  return 0;
}

This topic is closed to new replies.

Advertisement