SFML community forums
Help => Graphics => Topic started 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?
-
Have you tried setting smooth to false?
your_image.SetSmooth(false);
-
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)
-
Images are smoothed, not sprites. Therefore images are always at their regular size.
-
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
-
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?
-
No, because the rendered glyphs are too crappy without bilinear filtering ;)
Are you using a custom view? Did you resize your window?
-
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
-
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:
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.
-
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.
-
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
-
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!
#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();
}
}
-
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.
const_cast<Image &>(GetDefaultFont().GetImage()).SetSmooth(false);
Regards
-Martín
-
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.
-
Skipped that, sorry.
It's not if you're making a pixelated game (Where smoothed fonts look bad).
-
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.
float a1=2.f/800.f;
float a2=2.f/799.f;
double b1=2.0/800.0;
double b2=2.0/799.0;
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!
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!
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!
-
Some empirical values...
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;
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
-
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.
-
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
-
Possible solution, read here:
http://www.sfml-dev.org/forum/viewtopic.php?p=8455
-
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:
// 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.
-
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
-
- 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...
- 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.
-
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.
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.
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.
-
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 ;)
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?
-
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 :)
-
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.
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.