SFML community forums

Help => Graphics => Topic started by: crazy2be on June 07, 2009, 01:25:12 am

Title: Wierd "Blurring" with SFML.
Post by: crazy2be on June 07, 2009, 01:25:12 am
When i try to display images to the screen on my "Menubar" at the bottom of the screen, they end up very garbled and messy looking.
(https://dl.getdropbox.com/u/57502/Ickylookingbox.png)
The image on the left is what comes out when i display it onscreen, the image on the right is what *should* come out. (it is a "X" with a transparent background and a black border. The transparency has been replaced with the menu color for the purposes of this post). Note that the image has been scaled to 8x so that you can see what is happening easier.

Any idea why this is happening? If you want to take a look at the code, you can get it from the "opentower" sourceforge project (there is way too much to post here, although the relevant code would all be in /game). I'm guessing it's something to do with the view being set weirdly?
Title: Wierd "Blurring" with SFML.
Post by: dabo on June 07, 2009, 02:15:49 am
Have you tried setting smooth to false?

Code: [Select]
your_image.SetSmooth(false);
Title: Wierd "Blurring" with SFML.
Post by: crazy2be on June 07, 2009, 03:14:24 am
That fixes it... why was the "smoothing" making it look really bad?
I've disabled smoothing for now, because it makes the images look really bad, but is there any way to disable smoothing only if the image is at it's regular size? (so that images are smoothed when drawn at smaller and larger sizes than normal, but not otherwise)
Title: Wierd "Blurring" with SFML.
Post by: Tank on June 07, 2009, 01:03:45 pm
Images are smoothed, not sprites. Therefore images are always at their regular size.
Title: Wierd "Blurring" with SFML.
Post by: nitram_cero on June 08, 2009, 06:54:45 pm
I think that the artifacts you see (besides the "smoothing") are due to a border on the image (e.g. a white border)

Try leaving an extra 1 pixel border that matches the colors of the real border (in your case, black), so the interpolation is correctly achieved by OpenGL.
To get the appropiate subpicture (without the border 1 pixel "new border") use Sprite's SetSubRect()

You may understand it better from a graphic that I posted in another thread (the thread is about something related to what I'm telling you): http://www.sfml-dev.org/forum/viewtopic.php?t=1224

Hope this helps.
-Martín
Title: Wierd "Blurring" with SFML.
Post by: crazy2be on June 09, 2009, 07:16:07 pm
Well, i turned of the smoothing for the icons (i don't want smoothing anyway, since they won't be resized), but is there a similar option for text?
(https://dl.getdropbox.com/u/57502/IckyLookingText.PNG)
Is what i get for output when i display a series of pipe characters (|) on the screen. I would like to disable any blurring of the font, especially if it is uneven like in the picture. Is there any way to do this?
Title: Wierd "Blurring" with SFML.
Post by: Laurent on June 09, 2009, 11:29:13 pm
No, because the rendered glyphs are too crappy without bilinear filtering ;)

Are you using a custom view? Did you resize your window?
Title: Wierd "Blurring" with SFML.
Post by: nitram_cero on June 10, 2009, 06:15:54 pm
Smoothing is for texturizing, but if the view is not the default, or you're not using integer numbers for positions (for example)... that's what happens.

OpenGL will do smoothing anyway, but not because of texture-to-polygon coordinates but because the polygon itself is not aligned to the pixels of the screen (i.e. the sprite's position has decimals)

Well... I'm just guessing that :3
Title: Wierd "Blurring" with SFML.
Post by: crazy2be on June 11, 2009, 02:34:28 am
Well, as far as i know, i am using a view equal to the size of the window. Here is my code that handles the sf::Resized event:
Code: [Select]
if (Event.Type == sf::Event::Resized) {
    // Resize the game view
    Gfx::View.SetHalfSize(Event.Size.Width/(2*Gfx::CurrentZoom),
    Event.Size.Height/(2*Gfx::CurrentZoom));
    // Resize and center the "Normal" view (toolbars and menus are drawn on this one, including the toolbar that has the problem images/text drawn on it)
    Gfx::NormalView.SetHalfSize(Event.Size.Width/2, (Event.Size.Height)/2);
    Gfx::NormalView.SetCenter(Event.Size.Width/2, (Event.Size.Height)/2);
    // Resize the menu at the bottom
    BottomMenu.OnResize();
}

Is there some other was i should be doing it to make the width/height as it should be? I really like SFML (It's fast and really quite nice to use :P), but i hate this problem, and i hope there is a way to fix it.
Title: Wierd "Blurring" with SFML.
Post by: Laurent on June 11, 2009, 09:41:42 am
Your code should be ok. If you give me a minimal and complete code that reproduces the problem, I can see if there's anything to do about it.
Title: Wierd "Blurring" with SFML.
Post by: nitram_cero on June 11, 2009, 02:38:00 pm
Is there a window size in which this doesn't happen to you?

Even if you use a view of the size of the window, this could mean that the metrics are 2 units per 3 pixels or something like that, forcing that anti-aliasing.
The view makes a projection in respect to the viewport, that in turn is the size of the window. So if you resize to make everything fit in, you might get that behaviour as texels (rendered image pixels) can get to be between two screen pixels.

Try window sizes that are power-of-two divisions of your window size.
If you're using 800x600, try 400x300, 200x150... and see if this still happens.

I hope this helps

EDIT: You could also try to disable all kinds of antialiasing/anisotropic filtering with opengl hints.
Or leaving a border (transparent) for each glyph.

Regards
-Martín
Title: Wierd "Blurring" with SFML.
Post by: crazy2be on June 13, 2009, 04:18:29 am
Here is some example code that reproduces the problem (for me). The problem seems to get much worse with smaller fonts (and large fonts actually look ok).

What are opengl hints, and how can i disable them?

Could is be that my graphics card has bad anti aliasing? (is this handled directly by the graphics card these days?)

Thank you for your interest in helping me!
Code: [Select]
#include <SFML/Graphics.hpp>
#include <iostream>
#include <string>

int main() {
    sf::String ExampleText("||||||||||||||||||||||||||||||||||||||||||||\n"
                           "____________________________________________\n"
                           "--------------------------------------------\n"
                           "::::::::::::::::::::::::::::::::::::::::::::\n"
                           "The quick brown fox jumped over the lazy dog");
    ExampleText.SetSize(12);
    sf::RenderWindow App(sf::VideoMode(800, 600, 32), "Example");
    bool Running = true;
    App.SetFramerateLimit(30);
    while (Running) {
        sf::Event Event;
        while (App.GetEvent(Event)) {
            if (Event.Type == sf::Event::Resized) {
                sf::View View;
                View = App.GetView();
                View.SetHalfSize(Event.Size.Width/2, Event.Size.Height/2);
                View.SetCenter(Event.Size.Width/2, Event.Size.Height/2);
                std::cout << "Width: " << Event.Size.Width << "\tHeight: " << Event.Size.Height << '\n';
                App.SetView(View);
            } else if (Event.Type == sf::Event::Closed) {
                App.Close();
                Running = false;
            }
        }
        App.Clear();
        App.Draw(ExampleText);
        App.Display();
    }
}
Title: Wierd "Blurring" with SFML.
Post by: nitram_cero on June 13, 2009, 09:32:15 am
Hints: http://www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/hint.html

Sorry for the confusion. I thought that glHint could change the full screen antialiasing but apparently it's just for points, lines, etc.

It's unlikely to be your graphics card. I can't try that right now, but I'll recheck this thread later.

Doing another game I've seen that smoothing on "rendered text" can be weird.
Maybe the character separation makes some glyphs to be not-pixel-aligned doing those strange artifacts.


It would be nice to have "SetSmooth(false)" for sf::Strings for this matter.
EDIT: You can try this, I haven't but will.
Code: [Select]
const_cast<Image &>(GetDefaultFont().GetImage()).SetSmooth(false);

Regards
-Martín
Title: Wierd "Blurring" with SFML.
Post by: Laurent on June 13, 2009, 09:47:30 am
Quote
It would be nice to have "SetSmooth(false)" for sf::Strings for this matter

Well, I already answered this question a few messages above ;)
Disabling filtering for fonts is worse in any case.
Title: Wierd "Blurring" with SFML.
Post by: nitram_cero on June 13, 2009, 09:50:52 am
Skipped that, sorry.

It's not if you're making a pixelated game (Where smoothed fonts look bad).
Title: Wierd "Blurring" with SFML.
Post by: nitram_cero on June 13, 2009, 12:50:49 pm
I think the problem with resizing is that the projection sf::Matrix3 is holding  floats instead of doubles.

The errors could come from rounding under different widths/heights.

Code: [Select]
float a1=2.f/800.f;
float a2=2.f/799.f;
double b1=2.0/800.0;
double b2=2.0/799.0;


Code: [Select]

   a1 0.0024999999 float
   a2 0.0025031290 float
   b1 0.0025000000000000001 double
   b2 0.0025031289111389237 double



somewhat related to this:
http://abepralle.wordpress.com/2009/04/02/iphone-2d-projection-matrix-fpu/

read!
Quote
Finally, after hours of screwing around, I realized I could ditch the floating point-based pixel-to-unit OpenGL ES transformation matrix and do a better job of it myself using doubles instead of floats!


Quote

I was then able to transform pixel coordinates (0..319,0..479) with pixel-perfect accuracy!  Not only that, but it clarified my bitmap text drawing to where I didn’t need any -0.5 translation – in this case, it think the original benefit of -0.5 was more from compensating for floating point error more than it was from compensating for any sort of texel sampling setting.


Bingo!
Title: Wierd "Blurring" with SFML.
Post by: nitram_cero on June 13, 2009, 01:20:35 pm
Some empirical values...

Code: [Select]
float floatWidth=(float)ns.GetWidth();
double doubleWidth=(double)ns.GetWidth();

volatile float floatPrjWidth=floatWidth;
volatile double doublePrjWidth=doubleWidth;

floatPrjWidth=2.f/floatPrjWidth;
floatPrjWidth=2.f/floatPrjWidth;

doublePrjWidth=2.f/doublePrjWidth;
doublePrjWidth=2.f/doublePrjWidth;


Quote

      floatWidth   482.00000   float
      floatPrjWidth   481.99997   volatile float
      doubleWidth   482.00000000000000   double
      doublePrjWidth   482.00000000000000   volatile double



      floatWidth   457.00000   float
      floatPrjWidth   457.00000   volatile float
      doubleWidth   457.00000000000000   double
      doublePrjWidth   457.00000000000000   volatile double


      floatWidth   373.00000   float
      floatPrjWidth   373.00000   volatile float
      doubleWidth   373.00000000000000   double
      doublePrjWidth   373.00000000000000   volatile double

      floatWidth   419.00000   float
      floatPrjWidth   418.99997   volatile float
      doubleWidth   419.00000000000000   double
      doublePrjWidth   419.00000000000000   volatile double


      floatWidth   439.00000   float
      floatPrjWidth   438.99997   volatile float
      doubleWidth   439.00000000000000   double
      doublePrjWidth   439.00000000000000   volatile double



      floatWidth   237.00000   float
      floatPrjWidth   237.00002   volatile float
      doubleWidth   237.00000000000000   double
      doublePrjWidth   237.00000000000003   volatile double



      floatWidth   209.00000   float
      floatPrjWidth   209.00002   volatile float
      doubleWidth   209.00000000000000   double
      doublePrjWidth   209.00000000000000   volatile double

Title: Wierd "Blurring" with SFML.
Post by: Laurent on June 13, 2009, 01:30:09 pm
If you could investigate more, like trying to tweak SFML directly and see if it makes a difference, that would me even more interesting :)

But I'm personnally not convinced, as OpenGL and graphics cards are manipulating floats. At least on common PCs, I don't know about the iPhone.
Title: Wierd "Blurring" with SFML.
Post by: nitram_cero on June 13, 2009, 01:33:02 pm
I'm tweaking by code... that could be later be ported to the View lib code.

Try to hack doubles into projections would be a mess (Changing Matrix3 and EVERY part of the code that uses an opengl compatible matrix taken from Matrix3)

I'm trying, but posting through the process is a sort of brainstorm, so anyone else could make a comment and help.


EDIT: Couldn't solve it. I'm dropping it.

The conclusion I reached is that it's probably not related to the precision of the floats.
When you set wider widths (RenderWindow::SetSize and changing the View acordingly), apparently the sprites look wider themselves.
If you narrow it, they tend to get narrower.

It's very noticeable if you change from a width like 800px to one like 300px.

Sprites seem to get their size in relation to the window's size (Either smoothed and non-smoothed ones).
Larger window, larger aspect of sprites. Smaller window, smaller aspect of sprites.

This really bothers me, as I'm making an editor using wxWidgets, and resizing the sfml canvas always changes how sprites are seen!

glHint(GL_PERSPECTIVE_CORRECTION_HINT, xxxxxx) doesn't seem to affect the behaviour.



Well, I hope someone makes this work!
Good luck!
-Martín
Title: Wierd "Blurring" with SFML.
Post by: nitram_cero on June 19, 2009, 06:06:17 pm
Possible solution, read here:

http://www.sfml-dev.org/forum/viewtopic.php?p=8455
Title: Wierd "Blurring" with SFML.
Post by: dot on February 10, 2012, 12:35:54 am
I know this thread is quite old, but this bug still seems to be there, affecting a lot of people, and I think I know how to fix it (SetSmooth(false) is not a real solution, the floor operation used in nearest neighbor filtering just makes the image look right).

I took a look at the SFML code as this behavior is quite typical for an issue with texture coordinate calculation I am pretty familiar with, and I think the problem lies in Sprite.cpp in line 191:
Code: [Select]

        // Use the "offset trick" to get pixel-perfect rendering
        // see http://www.opengl.org/resources/faq/technical/transformations.htm#tran0030
        GLCheck(glTranslatef(0.375f, 0.375f, 0.f));

As far as my understanding goes, this is exactly what not to do if you want pixel-perfect rendering in OpenGL. I'm pretty surprised to find such wrong advice on opengl.org.
The OpenGL rasterization rules define texels and pixels to already be aligned perfectly (see for example the current OpenGL 4.2 Core Profile specification section 3 page 171 and 3.9.11 page 247).
Direct3D 9 used to have texels and pixels offset by 0.5 as described here (http://msdn.microsoft.com/en-us/library/windows/desktop/bb219690.aspx), but afaik this was never the case in OpenGL and I'm rather curious how they arrived at this magical value of 0.375f...
Anyway, removing this line appears to fix the problem, enabling pixel-perfect rendering with bilinear filtering turned on ;)

I don't really have the time to test this thoroughly, but maybe some of you want to take a closer look at this.
Title: Wierd "Blurring" with SFML.
Post by: Laurent on February 10, 2012, 07:55:27 am
Hi

Thanks for your feedback, but:
- this line was added because there was a problem, so I don't see how removing it would magically make everything work ;)
- don't waste too much time with this old code, nobody cares about it, SFML 2.0 is nearly finished
Title: Wierd "Blurring" with SFML.
Post by: dot on February 10, 2012, 11:44:07 pm
Quote from: "Laurent"

- this line was added because there was a problem, so I don't see how removing it would magically make everything work ;)

Well, because texels and pixels already are aligned in OpenGL, the spec guarantees this (the 0.5 offset is an issue with Direct3D 9 only; starting with Direct3D 10, texels and pixels align in Direct3D as well).
So without that line, texels and pixels align and therefore no blurring occurs when bilinear filtering is enabled.

But I find it only reasonable to distrust the guy walking in and telling you that the very website of the API itself is wrong about something. I guess it would make me very skeptical myself, to say the least. But maybe i can convince you ;)

(Note that the FAQ just consists of contributions of "various developers" and overall appears to be pretty outdated, so it's not like I'm trying to say the ARB is telling lies. And then, even the MSDN has some examples that do exactly what not to do...happens)

I don't really expect anyone to go and dive into the OpenGL Specification I referred to in my previous post because of this, so let me just summarize what it says in those two places:
In section 3, pixel (fragment) centers, which are the sampling locations for rasterization (see 3.6.1), are defined to be at half-integer coordinates.
Section 3.9.11 then deals with texture filtering. If you look at the equations for how texels get selected for bilinear filtering, it is obvious that texel centers are at half-integer coordinates as well.
From this follows that texels and pixels are aligned. They have to be in any conforming implementation. No need for fancy offsets, especially not 0.375f.

For further demonstration, I modified the code from the sprite rendering tutorial to draw this sprite:

(http://dl.dropbox.com/u/1722583/sfml_sprite.png)

At integer coordinates, I get this output, which is clearly wrong:

(http://dl.dropbox.com/u/1722583/sfml_with.png)

Well, actually not wrong but exactly what one would expect to happen when bilinearly filtering this texture at sampling locations offset by 0.375.

If I am right, we ought to see a uniformly grey square if the offset was 0.5 instead of 0.375. And guess what ;)

(http://dl.dropbox.com/u/1722583/sfml_with_mod.png)
(The brighter line at the bottom is caused by the GL_CLAMP addressing mode used by sf::Image)

And without any offset:

(http://dl.dropbox.com/u/1722583/sfml_without.png)

voilà :)

Now I don't know what problem this line was supposed to fix, but I guess it actually didn't fix said problem either, whatever it might have been, but only shifted everything in a way that it would not be noticeable under normal circumstances. And I am almost 100% sure that it is the cause of most of these SFML blurring problems like, for example, just recently here (http://www.sfml-dev.org/forum/viewtopic.php?t=6951) and even issues such as this (http://www.sfml-dev.org/forum/viewtopic.php?t=6933), this (http://www.sfml-dev.org/forum/viewtopic.php?t=6665) and this (http://www.sfml-dev.org/forum/viewtopic.php?t=5952&postdays=0&postorder=asc&start=0).
Turning off filtering does not fix the real issue, which is that texels and pixels do not align.
And then I can't really rotate my sprites anymore because that'd look pretty bad without filtering.
But removing line 191 from Sprite.cpp does fix it.


In fact, whenever I write a sprite renderer, I actually use this as a test to check if my texcoords can possibly be correct. I render a single sprite (preferably of a size as odd as it can get) at integer coordinates, once with bilinear filtering and once without and then diff the resulting images. If there is even the slightest difference (and especially if there is just a slight difference), then I know that something must be wrong with my texcoords.
I highly recommend this method as I was able to clear up many uncertain situations this way, for example when drawing small images from a large atlas, where it can get pretty hard to tell just by visual inspection if things really are as they are supposed to be or just about 0.0001f off...


Quote from: "Laurent"
- don't waste too much time with this old code, nobody cares about it, SFML 2.0 is nearly finished

I know. The reason why I investigated this is that I remember seeing people with this problem on basically every one of the forums that I usually am active in at some point. So when yesterday there was another question of this kind on one of our forums, I thought that I might just as well have a look at it.
Since I am pretty confident that this is the way to really fix it, I though I should share it, so that at least other people can find it here.

To me it seems that there are still lots of people using 1.6 out there. And even though I don't really use SFML myself because I usually have no application for it, I am very fond of this library. Among all alternatives that I know of, I consider it by far the best option, because it is very simple to use (it really lives up to its name ;) ), clean and reasonably efficient. So I quite frequently recommend it to beginners asking where to start. And I think this is a very important issue because I imagine this to be an especially nasty problem for those beginners as there is basically no way for a beginner to possibly get to grips with this. And then, after getting frustrated by not being able to figure out what he's doing wrong, our beginner is left with such an unsatisfying workaround as having to turn off filtering because it says so somewhere on the internet, wondering why it is even turned on by default in the first place.

I hope you don't get me wrong, I really appreciate what you've done with SFML :)
I just wanted to point this out because I think that an almost trivial change could provide a fundamental improvement here.

EDIT: I just tried the same thing with SFML 2.0 and it seems to be correct there.
Title: Wierd "Blurring" with SFML.
Post by: Laurent on February 11, 2012, 10:23:31 am
Don't misunderstand my comment. In fact I'm not really suprised that opengl.org might contain wrong information, as a developer I'm used to this kind of stuff, nothing's perfect ;)

My point was that this fix is supposed to solve something, I didn't add this line just for fun. So removing it should get the old bug back.

However I agree with you, I've also read that pixels and texels are aligned in OpenGL, and this line of code just made things worse anyway. That's why the first thing I did in SFML 2 was to remove it -- and that's why I'm telling you not to waste your time with it.

Quote
And I am almost 100% sure that it is the cause of most of these SFML blurring problems like, for example, just recently here and even issues such as this, this and this

Most of them are 2.0, so it's unrelated. In fact my problem in 2.0 is a different one: getting pixel-perfect rendering with decimal coordinates. My conclusion was that it is impossible: either we round coordinates and we get jerky movements, or we don't do anything and we see extra pixels sometimes when the coordinates don't perfectly match pixels.

Quote
I highly recommend this method as I was able to clear up many uncertain situations this way, for example when drawing small images from a large atlas, where it can get pretty hard to tell just by visual inspection if things really are as they are supposed to be or just about 0.0001f off...

I have a big test app for this, with many sprites in many situations: smooth on/off, view at decimal/integer coordinates, sprite at decimal/integer coordinates, moving/static, with a grid pattern inside a bigger texture surrounded with red pixels, ... ;)
And so far, no solution made my test app 100% working.
Title: Wierd "Blurring" with SFML.
Post by: dot on February 11, 2012, 11:57:12 am
Quote from: "Laurent"
However I agree with you, I've also read that pixels and texels are aligned in OpenGL, and this line of code just made things worse anyway. That's why the first thing I did in SFML 2 was to remove it -- and that's why I'm telling you not to waste your time with it.

Ok, you've got a point there ;)


Quote from: "Laurent"
Quote
And I am almost 100% sure that it is the cause of most of these SFML blurring problems like, for example, just recently here and even issues such as this, this and this

Most of them are 2.0, so it's unrelated. In fact my problem in 2.0 is a different one: getting pixel-perfect rendering with decimal coordinates. My conclusion was that it is impossible: either we round coordinates and we get jerky movements, or we don't do anything and we see extra pixels sometimes when the coordinates don't perfectly match pixels.

Ok, I guess I should have read them more carefully  :oops:

You are correct when you say that it is impossible to avoid getting in neighboring pixels when coordinates are not integer. There will always be constellations where that will happen (on which edges it happens might be, among other things, hardware dependent).
There are two ways to avoid this that I know of:
1) Manually clamping the texcoords in the shader
2) Surrounding the subimage by a 1 pixel border (for example replicate the edge pixels there)

I consider 2) the cleaner solution, but it requires spritesheets to be prepared whereas 1) can be done just programmatically. Maybe SFML 2.0 could provide 1) as an option that can be enabled/disabled?
Title: Wierd "Blurring" with SFML.
Post by: Laurent on February 11, 2012, 04:57:31 pm
SFML 2.0 is not shader-based (yet), so I can't provide a solution that would require a shader.

By the way, thank you very much for your feedback, it's very helpful. I'm glad that someone else experienced with rasterization issues can confirm that it's impossible to find a perfect solution :)
Title: Wierd "Blurring" with SFML.
Post by: dot on February 12, 2012, 03:17:56 am
Quote from: "Laurent"
SFML 2.0 is not shader-based (yet), so I can't provide a solution that would require a shader.

Ok, that's not an option then. Maybe in the next version ;)

With shaders out of the question, I'd say that you did all that you can do on the library side.
Replicating the edges to form a 1 pixel wide border around each sprite in the spritesheet might be a good advice for people running into such issues I think, as it should give identical results to clamping.

Quote from: "Laurent"
By the way, thank you very much for your feedback, it's very helpful. I'm glad that someone else experienced with rasterization issues can confirm that it's impossible to find a perfect solution :)

Glad I could at least help a bit :) . It's actually quite easy to see why this must be the case. Just imagine some sprite of integer size. If this sprite is not placed at exact integer coordinates, then in each direction there is always one edge that is closer than 1/2 to the next pixel center. And with texcoords closer to the edge than 1/2 texel (which is exactly what you get in this case if the mapping is perfect), bilinear filtering will sample the bordering texel.
So actually there's not just some constellations where it happens but it always does unless the coordinates are integer. It's only a question of how much offset it takes until the effect produces a noticeable artifact, which will mostly depend on the image.
Now there's two things one can do about this: Either clamp the texcoords to stay within the desired range or make the bordering texels so that sampling them will lead the desired result anyway.
If you map a whole texture onto a quad, then you can just use the GL_CLAMP_TO_EDGE address mode and be good (I see you already do this in SFML 2.0).
But for the general case of mapping only a subregion of a larger image onto the quad I think this is proof that there really is nothing you can do besides what was already mentioned.