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

Author Topic: Scrolling view causes tiles to blur/flicker [SOLVED]  (Read 4898 times)

0 Members and 1 Guest are viewing this topic.

Trinity

  • Newbie
  • *
  • Posts: 10
    • View Profile
Scrolling view causes tiles to blur/flicker [SOLVED]
« on: August 27, 2017, 06:46:23 pm »
Hello,

I'm currently loading tilemaps from Tiled using https://github.com/fallahn/sfml-tmxloader and it works as expected. However when the view moves with the player the tiles in the loaded tilemap appears to blur/flicker which from my understanding is caused by rounding issues related to the view and the nearest tiles?

The issue can be seen in the following video: https://www.youtube.com/watch?v=PQ4SpWTb_xQ&feature=youtu.be

I read that there is an implementation fix for this with SelbaWard, but I just don't want to just change my system just yet if there might be a solution for the current setup. Has anyone encountered this problem and know of any possible solutions?  :)
« Last Edit: August 30, 2017, 01:19:02 pm by Trinity »

Martin Sand

  • Newbie
  • *
  • Posts: 23
    • View Profile
    • Email
Re: Scrolling view causes tiles to blur/flicker
« Reply #1 on: August 27, 2017, 07:31:43 pm »
I am sorry. I watched the video several times but could not see the issue.
What is your current game loop? Do you have a fixed time step with delta time per frame?

Trinity

  • Newbie
  • *
  • Posts: 10
    • View Profile
Re: Scrolling view causes tiles to blur/flicker
« Reply #2 on: August 27, 2017, 08:02:58 pm »
I had a little hard time myself to see the issue but it is there if you don't watch in fullscreen and are aware of the issue. And yes I have fixed time step as well having v-sync enabled.

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 10800
    • View Profile
    • development blog
    • Email
Re: Scrolling view causes tiles to blur/flicker
« Reply #3 on: August 27, 2017, 08:20:54 pm »
First step would be to round the view's position to interger positions
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Trinity

  • Newbie
  • *
  • Posts: 10
    • View Profile
Re: Scrolling view causes tiles to blur/flicker
« Reply #4 on: August 27, 2017, 08:32:05 pm »
Alright, that seems to have fixed the problem partly, by using the following code before setting the view:

m_view.setCenter(sf::Vector2f(std::round(m_viewPosition.x), std::round(m_viewPosition.y)));

Although it seems like the player sprite is not so smooth anymore, might be related to the fact that the viewpostion is based on the player's position?

if (player.getPosition().x > (float)WIDTH / 2.f)
        m_viewPosition.x = player.getPosition().x;

if (player.getPosition().y < (float)HEIGHT / 2.f)
        m_viewPosition.y = player.getPosition().y;

« Last Edit: August 27, 2017, 08:46:51 pm by Trinity »

Hapax

  • Hero Member
  • *****
  • Posts: 3346
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Scrolling view causes tiles to blur/flicker
« Reply #5 on: August 28, 2017, 01:16:53 am »
Rounding the positions of everything displayed in addition to the view being rounded would reduce some of these artifacts to a greater degree. However, the more you round (which displays more cleanly), the less smooth the motion can be. Note also that view's scale can affect this too. The video you linked (Unity2D clip) can look bad when a larger version is shown in a smaller frame. This results in scaling and it seems that it doesn't scale smoothly. The video is fine in a small frame if you choose a lower resolution video (one that fits).

I read that there is an implementation fix for this with SelbaWard
I'm not sure of which implementation you speak. Maybe it's the Tilemap as it can pre-render the map first (although it does have other bonuses too!). That is, it renders at a fixed view scale and rounded positions to a render texture and then positions the render as needed and can be scaled however required. There can be not gaps in a render texture and a render texture can also be smoothed for extra smooth visuals.

I have fixed time step as well having v-sync enabled.
It's worth noting that it's always possible that the graphics card could be refusing v-sync :P
Anyway, fixed timestep is all well and good but is it rigidly fixed, uncoupled from rendering rate, and interpolated with previous state for smooth motion? ;)
https://gafferongames.com/post/fix_your_timestep/
Kairos' Timestep can help with that if you need it.
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

Trinity

  • Newbie
  • *
  • Posts: 10
    • View Profile
Re: Scrolling view causes tiles to blur/flicker
« Reply #6 on: August 28, 2017, 11:10:52 am »
Quote
Rounding the positions of everything displayed in addition to the view being rounded would reduce some of these artifacts to a greater degree.

It seems like your right as rounding the position of the player sprite improves the quality slightly. Even though not as smooth as one would want. This also seems like a very tedious process to carry on with as you have to round all positions of all the entities in the game. I thought there would be an easy solution!  :'(

Quote
I'm not sure of which implementation you speak. Maybe it's the Tilemap as it can pre-render the map first (although it does have other bonuses too!).

Yup, pleasant to meet the author too! I only checked it out for a brief moment and I might come to use your tilemap setup if everything doesn't work out. Even though I would like to write my own implementation like the one you did with the render to texture, but as my OpenGL is a bit rusty (I have worked a bit too much with DirectX11 for the last few months), it will probably take a while.

Quote
Anyway, fixed timestep is all well and good but is it rigidly fixed, uncoupled from rendering rate, and interpolated with previous state for smooth motion?

Embarassing to say it's simply a sf::clock which is created in main and then passed as clock.restart() to the update function of my Game class. The usage will then be to multiply with the passed deltatime (dt.asSeconds()). I also tried Kairos' timestep but it only made the problem worse, perhaps could have sometime to do with the fact that I'm using box2d for physics when moving the player.
« Last Edit: August 28, 2017, 06:50:16 pm by Trinity »

Hapax

  • Hero Member
  • *****
  • Posts: 3346
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Scrolling view causes tiles to blur/flicker
« Reply #7 on: August 28, 2017, 11:02:37 pm »
I thought there would be an easy solution!
There is; render to a texture first ;D

I would like to write my own implementation [...] with the render to texture, but as my OpenGL is a bit rusty, it will probably take a while.
Create a render texture of the size of the amount of map you want to show when it is not zoomed or moved (no fractions of pixels). Render to it without any scale and make sure all positions are integers (assuming its view is 1:1. Create a "render sprite" to show the render texture and set its texture from the render texture. Draw the render sprite directly to the window.

Probably look something like this:
sf::RenderTexture renderTexture;
sf::RenderWindow window;
// .. set up render texture and window (sizes and views if required, for example)

while (window.isOpen())
{
    // event loop

    // update loop

    // render to render texture
    renderTexture.clear();
    renderTexture.draw(tilemap);
    renderTexture.display();

    // prepare render sprite
    sf::Sprite renderSprite(renderTexture.getTexture());
    renderSprite.setScale({ 2.f, 2.f }); // zoomed in x2 (to top-left corner as we haven't adjusted its origin)
    renderSprite.setPosition({ -31.24f, -5.91f }); // just a non-integer number for position offset

    // render to window
    window.clear();
    window.draw(renderSprite);
    window.display();
}

You may find the sf::RenderTexture documentation useful here:
https://www.sfml-dev.org/documentation/2.4.2/classsf_1_1RenderTexture.php

Embarassing to say it's simply a sf::clock which is created in main and then passed as clock.restart() to the update function of my Game class. The usage will then be to multiply with the passed deltatime (dt.asSeconds()). I also tried Kairos' timestep but it only made the problem worse, perhaps could have sometime to do with the fact that I'm using box2d for physics when moving the player.
Kairos' Timestep breaks up time into equally sized pieces so dt is identical on every update frame. That's its whole point. ;D
Notice that if the amount of time passed doesn't perfectly divide into dt-sized pieces, there will be a slight difference between the actual time passed and the amount of time processed by the updates. This is where the interpolation comes in. Basically, you take the previous state (all positions, sizes, velocities etc.) and the current state and then interpolate between them using the interpolation from Timestep. This creates an exact one-frame lag but motion becomes smoother and is accurately following time.
This method is described in Fix Your Timestep under the heading "The Final Touch". Note that the fixed dt done by Kairos is implementing a method based on the "Free The Physics" part of this article. It's up to you to use the interpolation (it's calculated for you - timestep.getInterpolationAlpha()) to add the final touch. ;)
Here is a simple example on how to use interpolation and how it affects thing.
Here is a video showing that example in action.

If Kairos is doing anything strange (not described above), it needs fixing! :o
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

Trinity

  • Newbie
  • *
  • Posts: 10
    • View Profile
Re: Scrolling view causes tiles to blur/flicker
« Reply #8 on: August 29, 2017, 10:50:21 am »
Oh, I thought there wasn't any functionality for this within SFML and I had to write my own by setting up a framebuffer etc, but as there is, it seems rather easy!

Edit: Tried with render to texture and the results were the same, as the problem was actually  connected to a line where I updated the position of the player next to the draw call. Decoupling them solved it of course... Although the render to texture solution won't be necessary, it seems to reduce the process memory of the application as it is pre-rendered which means I'll stick to it anyways :).

Quote
If Kairos is doing anything strange (not described above), it needs fixing!

Well, I might have done something wrong so it's likely more of my fault than yours! Don't worry about it ;)
Thanks for all the help Hapax :)
« Last Edit: August 29, 2017, 01:40:09 pm by Trinity »

Hapax

  • Hero Member
  • *****
  • Posts: 3346
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Scrolling view causes tiles to blur/flicker [SOLVED]
« Reply #9 on: August 30, 2017, 03:42:45 pm »
You are welcome. Pleased to have helped. :)
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

abcd1234567

  • Newbie
  • *
  • Posts: 23
    • View Profile
Re: Scrolling view causes tiles to blur/flicker
« Reply #10 on: November 10, 2023, 05:09:42 pm »
First step would be to round the view's position to interger positions

Sorry for bumping, but can you please explain why rounding solves this?

I had a similar problem, with grid lines (colored white) that would flicker (constantly changed their thickness) when moving the view with keyboard input (using isKeyPressed and speed).
It seems to be solved when rounding before passing the arguments to view.move().

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 10800
    • View Profile
    • development blog
    • Email
Re: Scrolling view causes tiles to blur/flicker [SOLVED]
« Reply #11 on: November 10, 2023, 09:13:00 pm »
It's because of how the rasterizer works. Your screen has pixels to display things. If the pixel align 1:1 then everything is great and you get a solid line. But if you put your line between two pixels, OpenGL has to decide how to render this, how to rasterize this, and there are multiple "solutions" to it. One it can decide to not render it (disappears), or it can decide to render both adjacent pixels some value of gray (if say the pixel was black), that way it might try your brain into thinking that in the sum total of the two it becomes black again, even if it's technically wider. And depending on the movement, you can also get one frame the one and the next frame the other solution, which then leads to more flickering.

If you instead make sure that all lines always align with the pixels, then there's no need for making such decisions.

For completeness' sake, there's one additional thing to consider, one-width lines (i.e. LineStrip) don't have their "position" at the top left corner of the line, but the vertex is actually in the center of the pixel. So in such cases, you may actually want to offset the line by 0.5, so it's dead center on the pixel.
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/