MakeSpriteFont - Blurry small fonts, Suggestion/Request

Sep 1, 2013 at 9:24 PM
My fonts, created via the MakeSpriteFont tool appear a little blurry/fuzzy to me. This has been bugging me for a while and today I decided to look into it. The source is definitely the tool, not my shaders or settings (I don't render with the sprite batch in this tool kit).

I'm a font-noob so I looked at how MakeSpriteFont draws the fonts and then created a test app to show me samples of a font with various render settings.

Here is an image showing the various rendering settings: Font Settings

Since every pixel matters here, you probably want to view it full size (it is a lossless image).

The font I used for an example is Consolas at 12 point. The red arrow points to the rendering settings that MakeSpriteFront uses.

The columns have the same pixel offset mode, the groupings have the same interpolation mode, and the lines within a group represent the text rendering hints. The sample strings have mode acronymns appended "pixelOffset/Interp/renderHint".

I included the ClearType version for comparison (the middle line of the groups).

The settings used by MakeSpriteFont tend to make a blurrier glyph; at small font sizes anyway. I didn't compare the modes with large font sizes.

The pixel offset setting makes the biggest difference. The None and HighSpeed settings make crisper text. In particular, if you look at the glyphs generated you can see quite a difference in letters like E and F. With the tool's default settings E and F get a trunk that looks ok, but the arms come out faded. With the None/HS settings the arms and trunk both look good.

The following two images were created by MakeSpriteFont:

Current Settings:

Changed Settings (Pixel offset = None):

As far as I can tell, the interpolation setting doesn't do anything; which makes sense, the docs say it is for scaling and rotation. It is set in MakeSpriteFont so I included it for completeness. I compared the results of the PixelOffset=None lines and they are identical across all the interpolation settings.

I tried a few different fonts and the results are consistently sharper setting PixelOffset to None. I don't know if that is always the case.

My request: Make the PixelOffset and TextRenderingHint adjustable via the command line. I also have doubts about the current settings for defaults as well. I haven't seen any cases (though perhaps bigger fonts it does) where the current settings give better results.

This is easy enough to fix for myself, but I think some others might find the crisper text useful, and it would be nice to be able to tweak the extra rendering params per font to tailor the appearance easily.
Sep 3, 2013 at 9:03 PM
Hello, and thanks for the detailed image examples!

I think this basically boils down to a preference for antialising vs. no (or at least minimal) antialiasing on the glyph images. I could certainly see adding such a switch to the tool, but I'd be reluctant to expose all the (in my opinion far too many!) underlying knobs that System.Drawing provides.

Do you think a single no-aa switch would be enough? If so, any suggestions on what options that should use?
Sep 3, 2013 at 10:18 PM
I'll definitely agree that all the knobs aren't needed. Making that bigger image was kind of eye opening to me in just how many combinations you could get out of it. Also in doing that I think it boiled down only a couple relevant items.

I don't know which option the OS defaults to, but if you set the PixelOffsetMode to Default, it comes out looking like the HighSpeed and None options (visually I have a really hard time telling the difference between those two).

For the AA, even my second image is still AA'd, via the AntiAliasGridFit.

What I have been using for my small fonts to make them crisper is TextRenderingHint::AAGridFit and PixelOffset::None. For me anyway, I think the PixelOffset setting is the more important one.

I am fine with the hard coded AA-GridFit option, but that's just me. It might be useful to expose that one. I don't know if anybody would use the subpixel/ClearType version since you wouldn't be able to change the color of the font if you did. I personally think the Single Bit Per Pixel ones look like garbage, but I can't say if that would always hold true for everybody or every font.

With a fatter font/bigger point size, the HighQuality pixel offset might also look better. Really didn't have any complaints on the quality until I started making small fonts.

Both of those options can have such a dramatic impact on the appearance I think it would be worth it to expose them both.

Here is my preference:

I think if you felt inclined to add those at least you would close the door for future moaning and groaning (like I am doing) since the major quality switches would be under control of the user.

I'll even do it if you would like and then send you the code. My main concern currently is that I make the changes myself (which I have done, but I just hard coded my preferences at the moment) and then I go to update the library at some point and can't remember all the changes I have made or have to dif all the files to figure it out.
Sep 3, 2013 at 10:29 PM
Oh and by the way, to not sound completely whiny...

I think the tool is great and I love having the source code to it. Thank you!
Sep 4, 2013 at 3:20 PM
Exposing all those options would certainly make the tool very flexible and would make sure this never needed to be revisted, but I have two doubts about such an approach:
  • It's not easy to understand what all these options would do! I worry that this would make the tool hard to use. You had to write a test program and spend considerable time investigating this to understand all the implications - I think it would be better if we could find some way to package up these learnings rather than expecting everyone to achieve a similar level of understanding to know what GridFit vs. Antialias does etc.
  • It leaks implication details of System.Drawing across a component boundary. At the moment System.Drawing is just an internal detail of how MakeSpriteFont happens to be implemented, but if the command line switches expose too many of these low level options, now the tool and the underlying rendering technology are permanently tied together.
Do you really need all this flexibility, or have you found just one combination that looks best? (if so what is that?) I'm wondering if just a single /sharp option might not be enough to select between the current very-antialiased vs. a single new sharper-outlines set of enum values...
Sep 4, 2013 at 4:18 PM
Edited Sep 4, 2013 at 4:19 PM
Alright, I see where you are coming from; if you want to keep the settings abstracted from the implementation I can work with that. My only reservation with that is that it comes down to some subjective calls on the results you get out of those settings. I can certainly narrow it down to sets that I think are improvements but that's just my opinion in the end.

Render Hint:
  • AntiAlias - Probably wouldn't want to select this one over AAGF.
  • AntiAliasGridFit - Is the current default and also what I used.
  • ClearType - Probably don't want this since you can't shade the results.
  • SingleBitPerPixel - Looks bad (horribly opinionated).
  • SingleBitPerPixelGridFit - Still looks bad.
Winner: AntiAliasGridFit

I found better info on the PixelOffset in the GDI+ docs. The .NET docs don't say a whole lot. According to GDI+:
  • Default == Highspeed == None
  • HighQuality == Half
So there are really only two options. I have to admit I'm happy to see the overlap in settings because it simplifies the controls which you wanted to do anyway.

I am thinking your single /sharp option might be enough given those settings:
  • Always use AntiAliasGridFit
  • Switch between PixelOffsets:HighQuality/None
Which one would you default it to? No preference here really. Do more people use larger fonts that need more AA or more people make small fonts that could use some more sharpness?
Sep 4, 2013 at 4:41 PM
Edited Sep 4, 2013 at 5:45 PM
As for which to default it to:

I suppose it makes sense to leave it how it is and add the /sharp switch. I'm having trouble imagining what the option would be in reverse.

If you made it sharp by default the opposite switch would be... /blurry, /lessSharp, /moarAA

I guess it would be rude to switch the expectations around on existing users too.
Sep 4, 2013 at 7:51 PM
This discussion has been copied to a work item. Click here to go to the work item and continue the discussion.
Sep 5, 2013 at 2:12 AM
I checked in a fix adding /sharp option to the MakeSpriteFont tool. Many thanks Myiasis for the suggestion and very helpful investigations!
Marked as answer by walbourn on 1/23/2014 at 11:26 PM
Sep 5, 2013 at 4:25 AM
Great, thanks for doing that. :)