Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Strange Movement with Fixed Timestep  (Read 13192 times)

0 Members and 1 Guest are viewing this topic.

CasualKyle

  • Newbie
  • *
  • Posts: 13
    • View Profile
    • Email
Strange Movement with Fixed Timestep
« on: August 11, 2016, 08:02:20 am »
So the movement in my game isn't smooth. It looks like every tenth of a second the game freezes for a very short period of time then continues along until it freezes again.

You can see here as the rectangle moves, it stops for a short while then continues along.



Here is my code for updating and rendering the game:

float dt = 1.0 / 60.0f;
float accumulator = 0.0f;

while (window.isOpen())
{
        float frameTime = clock.restart().asSeconds();
        accumulator += frameTime;

        while(accumulator >= dt)
        {
                pollEvents();
                updateStates(dt);
                clearInput();

                accumulator -= dt;
        }

        window.clear();
        drawStates(window);
        window.display();
}
 

Is my code flawed in someway and is this behavior a result of it? Or should this create smooth movement and thus the problem is with something else?
« Last Edit: August 11, 2016, 08:52:00 am by CasualKyle »

Mr_Blame

  • Full Member
  • ***
  • Posts: 192
    • View Profile
    • Email
Re: Strange Movement with Fixed Timestep
« Reply #1 on: August 11, 2016, 01:36:14 pm »
I should better use window.setFramerateLimit

CasualKyle

  • Newbie
  • *
  • Posts: 13
    • View Profile
    • Email
Re: Strange Movement with Fixed Timestep
« Reply #2 on: August 11, 2016, 09:15:07 pm »
I should better use window.setFramerateLimit

I've experimented with this function before and if it set it to the match the frame rate I've implemented in my code it has no visual impact which would make since because it just checks to see if an amount of time has passed before displaying the contents.

I've decided to experiment a little more with it though. Here's what I changed the code to:

window.setFramerateLimit(60);

while (window.isOpen())
{
    pollEvents();
    updateStates(dt);
    clearInput();

    window.clear();
    drawStates(window);
    window.display();
}

So after making this change I noticed that the movement is the same, it's not smooth. This tells me that the code I wrote in the first post is probably fine and that the issue is elsewhere. I figured maybe it's my computer so I ran the application on a different less powerful computer and strangely the movement is smooth! Now that I think about it this issue started happening when I applied the windows 10 anniversary update to my computer. The graphics drivers are up to date so I have absolutely no clue why this would be happening. Does anyone have any ideas?

Hapax

  • Hero Member
  • *****
  • Posts: 3351
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Strange Movement with Fixed Timestep
« Reply #3 on: August 12, 2016, 03:35:35 am »
Fixed Timestep creates a reliable and regular update for physics and logic. It doesn't, however, fix the refresh rate of the window. This is decided by the OS; if it would prefer to do something else, your window will have to wait.
Therefore, each frame shown isn't guaranteed to be perfectly regular and, in some cases, not at the exact time you expect a frame - it could be part way.
Frame interpolation can help solve this visual artifact. It's the very last part in the Fix Your Timestep article. I commented about this here recently and there is a small accompanying video to that comment showing the difference. See the comment here (also includes a link to Fix Your Timestep article).
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

CasualKyle

  • Newbie
  • *
  • Posts: 13
    • View Profile
    • Email
Re: Strange Movement with Fixed Timestep
« Reply #4 on: August 12, 2016, 08:49:45 am »
Fixed Timestep creates a reliable and regular update for physics and logic. It doesn't, however, fix the refresh rate of the window. This is decided by the OS; if it would prefer to do something else, your window will have to wait.
Therefore, each frame shown isn't guaranteed to be perfectly regular and, in some cases, not at the exact time you expect a frame - it could be part way.
Frame interpolation can help solve this visual artifact. It's the very last part in the Fix Your Timestep article. I commented about this here recently and there is a small accompanying video to that comment showing the difference. See the comment here (also includes a link to Fix Your Timestep article).

I looked at your video and it appears the same issue is happening with me so I implemented interpolation but unfortunately the issue is still there. Here is a minimal code example which is also on github:

main.cpp
#include "State.h"

int main()
{
        sf::RenderWindow window(sf::VideoMode(1500, 1000), "Timestep Testing");
        window.setKeyRepeatEnabled(false);

        State state;

        sf::Clock clock;
        float dt = 1.0f / 60.0f;
        float accumulator = 0.0f;

        while(window.isOpen())
        {
                sf::Event event;
                while(window.pollEvent(event))
                        if(event.type == sf::Event::Closed)
                                window.close();

                accumulator += clock.restart().asSeconds();

                while(accumulator >= dt)
                {
                        state.update(dt);
                        accumulator -= dt;
                }

                float interp = accumulator / dt;

                window.clear();
                state.draw(window, interp);
                window.display();
        }

    return 0;
}

State.h
#pragma once

#include "SFML\Window.hpp"
#include "SFML\Graphics.hpp"

class State
{
public:
        State();

        void update(float timeStep);
        void draw(sf::RenderWindow& window, float interp);

private:
        sf::RectangleShape rect;
        sf::Font font;
        sf::Text fps;
        sf::Text dps;
        sf::Clock clockUpdate;
        sf::Clock clockDraw;
        int frames;
        int draws;
        sf::Vector2f pos;
        sf::Vector2f lastPos;
};

State.cpp
#include "State.h"

State::State() : rect(sf::Vector2f(100.0f, 100.0f))
{
        font.loadFromFile("lucon.ttf");
        fps.setFont(font);
        dps.setFont(font);
        fps.setPosition(10.0f, 0.0f);
        dps.setPosition(10.0f, 30.0f);
        frames = -1;
        draws = -1;
}

void State::update(float timeStep)
{
        if(clockUpdate.getElapsedTime().asSeconds() >= 1.0f) {
                fps.setString("FPS: " + std::to_string(frames));
                frames = 0;
                clockUpdate.restart();
        }

        frames++;

        sf::Vector2f d;

        if(sf::Keyboard::isKeyPressed(sf::Keyboard::Key::W))
                d.y = -1;

        if(sf::Keyboard::isKeyPressed(sf::Keyboard::Key::S))
                d.y = 1;

        if(sf::Keyboard::isKeyPressed(sf::Keyboard::Key::A))
                d.x = -1;

        if(sf::Keyboard::isKeyPressed(sf::Keyboard::Key::D))
                d.x = 1;

        lastPos = pos;

        pos += 150.0f * d * timeStep;
        rect.setPosition(pos);
}

void State::draw(sf::RenderWindow& window, float interp)
{
        if(clockDraw.getElapsedTime().asSeconds() >= 1.0f) {
                dps.setString("Draw Calls: " + std::to_string(draws));
                draws = 0;
                clockDraw.restart();
        }

        draws++;

        window.draw(fps);
        window.draw(dps);

        sf::Vector2f posInterp = pos * interp + lastPos * (1.0f - interp);
        rect.setPosition(posInterp);
        window.draw(rect);
}

I'm getting a solid 60 frames per second and around 800 draw calls per second but the movement is still noticeably jittery. I also noticed that if I comment out the following code from main.cpp the issue goes away and the movement is buttery smooth.

sf::Event event;
while(window.pollEvent(event))
        if(event.type == sf::Event::Closed)
                window.close();

It appears that calling window.pollEvent() is causing the movement to be jittery.

K.F

  • Jr. Member
  • **
  • Posts: 55
    • View Profile
    • Email
Re: Strange Movement with Fixed Timestep
« Reply #5 on: August 12, 2016, 11:01:15 am »
Looks smooth to me when I compile it. Maybe a Driver, or a GPU global settings issue?

Hapax

  • Hero Member
  • *****
  • Posts: 3351
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Strange Movement with Fixed Timestep
« Reply #6 on: August 12, 2016, 12:19:45 pm »
If the event loop is slowing down your window, it could be that the window is receiving too many events from the OS. Maybe something is causing it to do that.

I'm getting a solid 60 frames per second and around 800 draw calls per second
How? If you are drawing 60 frames per second and drawing three things per frame, you should be getting 180 draw calls per second.
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

Mr_Blame

  • Full Member
  • ***
  • Posts: 192
    • View Profile
    • Email
Re: Strange Movement with Fixed Timestep
« Reply #7 on: August 12, 2016, 02:02:19 pm »
Oh, in your draw function you are calling std::to_string which returns a newly allocated string a think, that allocating something very frame may cause lagging as I experienced it myself.

Hapax

  • Hero Member
  • *****
  • Posts: 3351
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Strange Movement with Fixed Timestep
« Reply #8 on: August 12, 2016, 04:22:11 pm »
you are calling std::to_string [...] [e]very frame [...] may cause lagging as I experienced it myself.
Using std::to_string every frame is absolutely fine. How else are you expected to display the latest scores, times etc.?
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

Demir

  • Newbie
  • *
  • Posts: 22
    • View Profile
    • Email
Re: Strange Movement with Fixed Timestep
« Reply #9 on: August 12, 2016, 06:20:58 pm »
Quote
Using std::to_string every frame is absolutely fine. How else are you expected to display the latest scores, times etc.?

I'm not sure

may be sprintf (considered unsafe) function instead of to_string.
« Last Edit: August 12, 2016, 06:39:39 pm by Demir »

CasualKyle

  • Newbie
  • *
  • Posts: 13
    • View Profile
    • Email
Re: Strange Movement with Fixed Timestep
« Reply #10 on: August 12, 2016, 09:29:16 pm »
I'm getting a solid 60 frames per second and around 800 draw calls per second
How? If you are drawing 60 frames per second and drawing three things per frame, you should be getting 180 draw calls per second.

Sorry, I meant that the state.draw() function is getting called about 800 times per second. This doesn't seem irregular to me because since state.draw() is inside the while(window.isOpen()) loop it's going to get lots and lots of calls basically as fast as the CPU can do it.

When I run the minimal application on a different less powerful I get again a solid 60 frames per second and about 400 calls to state.draw() per second which would make since seeing that it's got a Pentium processor and my main computer has a core i7. (I know the CPU isn't everything and if you want the full specs of each computer I can give them to you.) And the movement is smooth. So I don't know I feel like the issue isn't with the code.

Okay so here is how I can get the movement to be smooth:
sf::Event event;
while(window.pollEvent(event))
    if(event.type == sf::Event::Closed)
        window.close();
  • Restart my computer. Yes, when I restart my computer the movement is smooth but at the end of the day when it's time for me to work on the project the jitteryness comes back. So I restart  my computer and everything is fine but the next day after I get home from work and decide to do some development at the end of the day I have to again restart it.


I said this before but this only started happening after I applied the Window 10 anniversary update to my computer which was August 1st if I remember correctly. I've ran the Intel Driver Update Utility  and it does not return back that the graphics drivers are not up to date.
« Last Edit: August 12, 2016, 09:30:58 pm by CasualKyle »

Hapax

  • Hero Member
  • *****
  • Posts: 3351
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Strange Movement with Fixed Timestep
« Reply #11 on: August 12, 2016, 09:38:50 pm »
If you're getting 800 draw calls per second and you're calling it once per frame, you're getting (internally) 800 frames (or ticks/cycles) per second. That is, the interpolation is not interpolating between the previous "seen" position and the current position but the previous position at the previous frame. This pretty much removes the effect for which interpolation is used so try limiting your framerate (something like 60-80) or activating v-sync (but not both). I think this is not a very good explanation so I apologise. Anyway, your logic should probably be running higher that the speed of the refresh/frame rate.
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

CasualKyle

  • Newbie
  • *
  • Posts: 13
    • View Profile
    • Email
Re: Strange Movement with Fixed Timestep
« Reply #12 on: August 13, 2016, 08:25:18 am »
If you're getting 800 draw calls per second and you're calling it once per frame, you're getting (internally) 800 frames (or ticks/cycles) per second. That is, the interpolation is not interpolating between the previous "seen" position and the current position but the previous position at the previous frame. This pretty much removes the effect for which interpolation is used so try limiting your framerate (something like 60-80) or activating v-sync (but not both). I think this is not a very good explanation so I apologise. Anyway, your logic should probably be running higher that the speed of the refresh/frame rate.

I did some more research, looked at your implementation with your Kairos timing library, changed my code and still didn't notice a change. Then I just downloaded your library altogether and used the timeStepExample.cpp example. I changed the timestep to be 1 / 30 because updating the physics 5 times a second made the circle move 250 * (1 / 5) = 50 pixels each physics update which is quite a jump. Anyway after doing that and experimenting with the interpolation and extrapolation and I can tell you that it doesn't make the movement smooth on my computer.

Sorry the dimensions are so big. Here's the link.


Here's what I conclude from messing around with your application. There is cyclic behavior with how the circle moves: It's smooth then a freeze, smooth then a freeze, smooth then a freeze, etc. The cycle seems to repeat about once every fith of a second. And the only line of code I changed was this: timestep.setStep(1.0 / 30.0);. Now it's hard to tell the difference but when I turn interpolation on, the movement between the freezes does look smoother, however the freezes are still there.
« Last Edit: August 13, 2016, 08:28:37 am by CasualKyle »

Hapax

  • Hero Member
  • *****
  • Posts: 3351
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Strange Movement with Fixed Timestep
« Reply #13 on: August 13, 2016, 12:54:28 pm »
I may be seeing things but it looks like "Time passed" is stuttering when the circle does. This would suggest that the window itself is being delayed.
I guess the most important (you might think it's too obvious) but required unasked questioned is:
Is this on a release build or does it only occur during debug builds?

There was no need to change the timestep in that example to 1/30 from 1/5; you can toggle between 1/5 and 1/60 by pressing Space. The resulting timestep information text in the title bar is showing 1/60 because it's expecting either 1/5 or 1/60 so chooses one. tl:dr; Use the example as is and press Space  :P

Just so you know, the 1/5 is there to show just how much interpolation does. Running at 1/5 with interpolation switched on has motion that is as smooth as 1/60 with interpolation on.  ;)
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

CasualKyle

  • Newbie
  • *
  • Posts: 13
    • View Profile
    • Email
Re: Strange Movement with Fixed Timestep
« Reply #14 on: August 13, 2016, 10:39:36 pm »
There was no need to change the timestep in that example to 1/30 from 1/5; you can toggle between 1/5 and 1/60 by pressing Space. The resulting timestep information text in the title bar is showing 1/60 because it's expecting either 1/5 or 1/60 so chooses one. tl:dr; Use the example as is and press Space  :P

Just so you know, the 1/5 is there to show just how much interpolation does. Running at 1/5 with interpolation switched on has motion that is as smooth as 1/60 with interpolation on.  ;)

Oh okay I didn't notice the code that changed the time step to 1/60 when the space bar is pressed and yeah, using interpolation while the time step is 1/5 sure does show you how beneficial interpolation can be.

I may be seeing things but it looks like "Time passed" is stuttering when the circle does. This would suggest that the window itself is being delayed.
I guess the most important (you might think it's too obvious) but required unasked questioned is:
Is this on a release build or does it only occur during debug builds?

It does look a little like the "Time passed" is stuttering when the circle does in the gif. But when it's running on my computer the "Time passed" doesn't stutter. I think it just didn't record the application as well as it runs. And as for the question of if there's a difference with it running on a release vs a debug build. No there is not, I get the same stuttery movement regardless of if it's a release or debug build.

Could be valuable information: Like with my application commenting out this code in your example makes the issue go away:
sf::Event event;
while(window.pollEvent(event))
{
        ...
}