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

Author Topic: Image of Sprite Skipping on Screen  (Read 14120 times)

0 Members and 1 Guest are viewing this topic.

Kondie

  • Newbie
  • *
  • Posts: 14
    • View Profile
Re: Image of Sprite Jittering on Screen
« Reply #15 on: February 17, 2018, 07:01:56 am »
So, I decided to try my hand at implementing interpolation, courtesy of this fellow: http://www.koonsolo.com/news/dewitters-gameloop/, to see if that could be the issue.

It definitely made things smoother, but I actually think there is a problem with the performance of setTextureRect for sf::Sprite objects. This picture is almost buttery smooth when using the stars.setPosition line, but switching to stars.setTextureRect yields the exact same jittering as shown in the gifs above:

Quote
#include <SFML/Graphics.hpp>
#include <SFML/Window.hpp>

#include <iostream>

int main() {

   sf::RenderWindow window(sf::VideoMode(900, 600), "SFML");

   //window.setVerticalSyncEnabled(true);
   window.setFramerateLimit(144);
   //window.setFramerateLimit(60);

   // Background //
   sf::Texture background;
   if (!background.loadFromFile("tileable_space.jpg"))
      exit(1);
   background.setRepeated(true);
   sf::Sprite stars(background);

   sf::Clock clock;

   float xspeed = 0, yspeed = 0;

   const int TICKS_PER_SECOND = 50;
   const int SKIP_TICKS = 1000 / TICKS_PER_SECOND;
   const int MAX_FRAMESKIP = 5;

   int loops;
   float next_game_tick = clock.getElapsedTime().asMilliseconds();
   float interpolation;

   float posx = 0, posy = 0;
   //int window_x = window.getSize().x, window_y = window.getSize().y, background_x = background.getSize().x;
   while (window.isOpen()) {

      sf::Event event;
      while (window.pollEvent(event)) {
         switch (event.type)
         {
         case sf::Event::Closed:
            window.close();
            break;
         case sf::Event::Resized:
            window.setView(sf::View(sf::FloatRect(0.f, 0.f, event.size.width, event.size.height)));
            break;
         }
      }

      loops = 0;
      while (clock.getElapsedTime().asMilliseconds() > next_game_tick && loops < MAX_FRAMESKIP) {

         if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right)) {
            xspeed = 5;
         } else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left)) {
            xspeed = -5;
         } else xspeed = 0;

         if (sf::Keyboard::isKeyPressed(sf::Keyboard::Up)) {
            yspeed = -5;
         } else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Down)) {
            yspeed = 5;
         } else yspeed = 0;
         
         posx += xspeed;
         posy += yspeed;

         next_game_tick += SKIP_TICKS;
         ++ loops;

      }

      interpolation = (float) (clock.getElapsedTime().asMilliseconds() + SKIP_TICKS - next_game_tick)
                  / (float) SKIP_TICKS;

      stars.setPosition(posx + (xspeed * interpolation), posy + (yspeed * interpolation));
      //stars.setTextureRect(sf::IntRect(std::fmod(posx, background.getSize().x), std::fmod(posy, background.getSize().y), 900, 600));


      window.clear();
      window.draw(stars);
      window.display();

   }

}

Is there some information I'm missing about performance degradation from the use of the setTextureRect command? Is it best to avoid it for scrolling backgrounds? I changed the last two parameters of its IntRect to be fixed just to make sure that the screen size request wasn't somehow causing the skipping. At this point, the cause of the performance degradation is beyond my scope, and it appears to be something within SFML.
« Last Edit: February 17, 2018, 09:14:37 pm by Kondie »

Ceylo

  • Hero Member
  • *****
  • Posts: 2325
    • View Profile
    • http://sfemovie.yalir.org/
    • Email
Re: Image of Sprite Skipping on Screen
« Reply #16 on: February 17, 2018, 11:47:24 am »
Did try to run your example but I miss "tileable_space.jpg", can you provide it?
Want to play movies in your SFML application? Check out sfeMovie!

dmitry_t

  • Newbie
  • *
  • Posts: 17
    • View Profile
Re: Image of Sprite Skipping on Screen
« Reply #17 on: February 17, 2018, 11:57:14 am »
For this code:
Quote
#include <SFML/Graphics.hpp>
#include <SFML/Window.hpp>

int main() {

   sf::RenderWindow window(sf::VideoMode(900, 600), "SFML", sf::Style::Titlebar | sf::Style::Resize | sf::Style::Close);

   //window.setVerticalSyncEnabled(true);
   //window.setFramerateLimit(144);
   //window.setFramerateLimit(60);

   int refresh_rate = 60;

   // Background //
   sf::Texture background;
   if (!background.loadFromFile("stars_square.png"))
      exit(1);
   background.setRepeated(true);

   sf::Sprite stars(background);

   float posx = 0;
   float currentspeed = 0;
   float picture_speed = 30;
   // ---------- //

   sf::Clock clock;
   float current_time = clock.getElapsedTime().asSeconds();
   float frame_time = 0;

   while ( window.isOpen() ) {

      sf::Event event;
      while (window.pollEvent(event)) {
         switch (event.type)
         {
            case sf::Event::Closed:
               window.close();
               break;
            case sf::Event::Resized:
               window.setView(sf::View(sf::FloatRect(0.f, 0.f, event.size.width, event.size.height)));
               break;
               
         }
      }

      float new_time = clock.getElapsedTime().asSeconds();
      frame_time = new_time - current_time;
      current_time = new_time;

      stars.setPosition(posx, 0);

      posx = std::fmod(posx + (picture_speed * frame_time), background.getSize().x);

      window.clear();
      window.draw(stars);
      window.display();

   }

}

You wrote:
Quote
Still produces the same skipping.

But the move direction is different from original. The stars here do not cover the whole screen. This makes me unsure.
The following is obviously missing in the code (setting the texture rect to make it larger than the texture and setting the origin to make the sprite covering the whole screen when it moves right):
Quote
    stars.setTextureRect({
        0,
        0,
        2 * window.getSize().x,
        2 * window.getSize().y});
    stars.setOrigin(window.getSize().x, 0);

Unfortunately I cannot load the proof videos, so you have to believe :)
« Last Edit: February 17, 2018, 12:00:35 pm by dmitry_t »

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Image of Sprite Skipping on Screen
« Reply #18 on: February 17, 2018, 03:30:02 pm »
Although I'm not fully certain whether or not it'll fix the problem specified, in the original code, I would suggest taking the clear/draw/display out of the update frame loop and only doing it once per "window.isOpen" cycle. This way the draw rate is not firmly glued to the update frame, which is the point of the type of loop you are using. It also allows events to be processed every draw frame instead of when every update frame has finished (it could be multiple draw frames).
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

Kondie

  • Newbie
  • *
  • Posts: 14
    • View Profile
Re: Image of Sprite Skipping on Screen
« Reply #19 on: February 17, 2018, 03:52:30 pm »
@hapax If you look at my most recent code post, that's exactly what I've done. So, does nobody else get skipping from the setTextureRect version of that code? Could be a driver issue.

@dimitry I understand that, and I believe that was due to something with timing, which is why I implemented the interpolation to smooth things out, which worked for the most part.
« Last Edit: February 17, 2018, 03:56:01 pm by Kondie »

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Image of Sprite Skipping on Screen
« Reply #20 on: February 17, 2018, 04:06:52 pm »
You're right. I was looking at the more recent post but it was by someone else and was a quote of something earlier. Sorry.

Tested your most recent code. Seems to be rather okay. It's a little bit "wobbly" but isn't too bad - certainly very little in the way of jerkiness as shown in your original gif.
I noticed that you said that that one is okay though because it uses position instead of texture rectangle, right? One thing to note is that a sprite's texture rectangle is integer only so will always be a little less smooth for movement. Also note that because of float rounding/truncating, this could, I suppose, cause a little stutter as it sticks to one pixel for two updates and then jumps two (or three?) in the next. Might be why it looks a little worse using texture rectangle.
It's possible to use floats for textures when using vertex arrays so maybe you will want that. This 'issue' is also why I used float texture rectangles for my sprite types in Selba Ward.
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

Kondie

  • Newbie
  • *
  • Posts: 14
    • View Profile
Re: Image of Sprite Skipping on Screen
« Reply #21 on: February 17, 2018, 08:17:48 pm »
So, one thing to comment about your statement there about int vs float is that the jittering isn't just the background jumping forward. If you look at the gif, it literally moves 1 step back, then 2 steps forward. I had a statement implemented to tell me if the previous position was ever less than the current, and it only triggered when the modulus operator set in.

Regardless, I took your advice and implemented the scrolling background into a quad. It exhibits the exact same jittering behavior as before. Here is the code that I made:

Quote
#include <SFML/Graphics.hpp>
#include <SFML/Window.hpp>

int main() {

   sf::RenderWindow window(sf::VideoMode(900, 600), "SFML");

   //window.setVerticalSyncEnabled(true);
   window.setFramerateLimit(144);
   //window.setFramerateLimit(60);

   // Background //
   sf::Texture background;
   if (!background.loadFromFile("tileable_space.jpg"))
      exit(1);
   background.setRepeated(true);

   sf::VertexArray quad(sf::Quads, 4);
   
   // Defining the 4 points on the screen
   quad[0].position = sf::Vector2f(0, 0);
   quad[1].position = sf::Vector2f(window.getSize().x, 0);
   quad[2].position = sf::Vector2f(window.getSize().x, window.getSize().y);
   quad[3].position = sf::Vector2f(0, window.getSize().y);

   sf::Clock clock;

   float xspeed = 0, yspeed = 0;

   const int TICKS_PER_SECOND = 50;
   const int SKIP_TICKS = 1000 / TICKS_PER_SECOND;
   const int MAX_FRAMESKIP = 5;

   int loops;
   float next_game_tick = clock.getElapsedTime().asMilliseconds();
   float interpolation;

   float posx = 0, posy = 0;
   while (window.isOpen()) {

      sf::Event event;
      while (window.pollEvent(event)) {
         switch (event.type)
         {
         case sf::Event::Closed:
            window.close();
            break;
         case sf::Event::Resized:
            window.setView(sf::View(sf::FloatRect(0.f, 0.f, event.size.width, event.size.height)));
            break;
         }
      }

      loops = 0;
      while (clock.getElapsedTime().asMilliseconds() > next_game_tick && loops < MAX_FRAMESKIP) {

         if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right)) {
            xspeed = 5;
         } else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left)) {
            xspeed = -5;
         } else xspeed = 0;

         if (sf::Keyboard::isKeyPressed(sf::Keyboard::Up)) {
            yspeed = -5;
         } else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Down)) {
            yspeed = 5;
         } else yspeed = 0;

         posx = std::fmod(posx + xspeed, background.getSize().x);
         posy = std::fmod(posy + yspeed, background.getSize().y);

         next_game_tick += SKIP_TICKS;
         ++loops;

      }

      interpolation = (float)(clock.getElapsedTime().asMilliseconds() + SKIP_TICKS - next_game_tick)
         / (float)SKIP_TICKS;

      quad[0].texCoords = sf::Vector2f(posx, posy);
      quad[1].texCoords = sf::Vector2f(posx + background.getSize().x, posy);
      quad[2].texCoords = sf::Vector2f(posx + background.getSize().x, posy + background.getSize().y);
      quad[3].texCoords = sf::Vector2f(posx, posy + background.getSize().y);

      window.clear();
      window.draw(quad, &background);
      window.display();

   }

}

If it works perfectly fine for you, I'm absolutely defeated here.

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Image of Sprite Skipping on Screen
« Reply #22 on: February 17, 2018, 10:02:14 pm »
Okay.

One thing I want to mention is that setting the framerate to match your graphics card refresh rate doesn't mean that it will necessarily match that rate. The framerate is often just a little less than the given limit. This could be causing some of the artifacts you are seeing as there will be a doubled frame here and there.

However, the weird thing here is that, although it looks like it's going backwards before skipping forwards, it never really does; it's just the way our eyes interpret the delay/jump.
I've just checked your gif frame-by-frame for you and at no point does it go backwards. In fact, it looks really smooth apart from two seemingly double-sized jumps.

The jumps could be causes by system delays, frame-rate mismatch or something else entirely. There is no 'true solution' but interpolation should alleviate the jumps.
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

Kondie

  • Newbie
  • *
  • Posts: 14
    • View Profile
Re: Image of Sprite Skipping on Screen
« Reply #23 on: February 18, 2018, 12:27:27 am »
After a few hours of troubleshooting in IRC it seems that this issue is with setTextureRect on some Nvidia cards (1060, 1070, and MX150 confirmed). The code works fine on many other machines. I'll be taking fallahn's suggestion, and implementing a scrolling background through OpenGL shaders, but I do believe the setTextureRect issue should be looked into.

@Hapax to clarify, interpolation only solved the jumps in some cases. Switching to fullscreen with interpolation caused them to return.
« Last Edit: February 18, 2018, 12:31:51 am by Kondie »

Phanoo

  • Full Member
  • ***
  • Posts: 136
    • View Profile
Re: Image of Sprite Skipping on Screen
« Reply #24 on: February 22, 2018, 02:54:18 pm »
That's strange. Did you tried to completely remove setTextureRect and use VertexArrays instead ? You should be able to achieve the same result, you just set the texture rect by directly modifying vertex struct members instead of calling the function
« Last Edit: February 22, 2018, 03:00:07 pm by Phanoo »

Kondie

  • Newbie
  • *
  • Posts: 14
    • View Profile
Re: Image of Sprite Skipping on Screen
« Reply #25 on: February 24, 2018, 05:51:38 am »
Actually Fallahn helped me with a little shader, and it looks like scrolling the texture in OpenGL still had issues. Extremely odd. It definitely performed better in more cases, but still wasn't stopping the jittering.

Overall, what I found was that certain video mode settings helped. For example, restricting the window to v-sync while in fullscreen mode stopped the jittering. And setting the framerate to that of my monitor while in windowed helped as well. The best performance was achieved in fullscreen v-sync with no noticeable jittering after playing around in it for quite some time. Disabling threaded optimization was also a necessity to entirely preventing this skipping for me. Note that this was all after interpolation was added as well, as without it, I did notice that the jittering would happen.

Hope this helps anyone who comes across this issue in the future. In the end I was still able to go with SFML, and I highly recommend it. Some of the best documentation, cleanest code, and most helpful forums I've seen out there. :)

Update: 10/27/2018

An update many months in advance for anybody who comes across this issue in the future, this video here was very helpful:

To summarize, it looks like this is just a problem with dual monitor setups where the refresh rate is greater than 60 hz in Windows 10 (or Windows 7 with Aero). As I've gotten further into my engine, I decided to spend some time researching this topic in hopes that I would find a solution, but I have not. Fullscreen definitely seems to lessen the issue significantly, and sometimes the disabling multi-threading as mentioned in here helped as well. But completely getting rid of the jittering doesn't seem to be possible in this kind of setup. Still works perfectly fine on my laptop @ 60 hz though.
« Last Edit: October 27, 2018, 08:43:28 pm by Kondie »