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

Author Topic: Wierd "Blurring" with SFML.  (Read 13452 times)

0 Members and 1 Guest are viewing this topic.

nitram_cero

  • Full Member
  • ***
  • Posts: 166
    • View Profile
Wierd "Blurring" with SFML.
« Reply #15 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!

nitram_cero

  • Full Member
  • ***
  • Posts: 166
    • View Profile
Wierd "Blurring" with SFML.
« Reply #16 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


Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Wierd "Blurring" with SFML.
« Reply #17 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.
Laurent Gomila - SFML developer

nitram_cero

  • Full Member
  • ***
  • Posts: 166
    • View Profile
Wierd "Blurring" with SFML.
« Reply #18 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

nitram_cero

  • Full Member
  • ***
  • Posts: 166
    • View Profile
Wierd "Blurring" with SFML.
« Reply #19 on: June 19, 2009, 06:06:17 pm »

dot

  • Newbie
  • *
  • Posts: 4
    • View Profile
    • http://www.m4studios.at
Wierd "Blurring" with SFML.
« Reply #20 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, 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.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Wierd "Blurring" with SFML.
« Reply #21 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
Laurent Gomila - SFML developer

dot

  • Newbie
  • *
  • Posts: 4
    • View Profile
    • http://www.m4studios.at
Wierd "Blurring" with SFML.
« Reply #22 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:



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



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 ;)


(The brighter line at the bottom is caused by the GL_CLAMP addressing mode used by sf::Image)

And without any offset:



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 and even issues such as this, this and this.
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.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Wierd "Blurring" with SFML.
« Reply #23 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.
Laurent Gomila - SFML developer

dot

  • Newbie
  • *
  • Posts: 4
    • View Profile
    • http://www.m4studios.at
Wierd "Blurring" with SFML.
« Reply #24 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?

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Wierd "Blurring" with SFML.
« Reply #25 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 :)
Laurent Gomila - SFML developer

dot

  • Newbie
  • *
  • Posts: 4
    • View Profile
    • http://www.m4studios.at
Wierd "Blurring" with SFML.
« Reply #26 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.