SpriteFont rendering - Can't seem to disable smoothing

Happy New Year, all!

I’m trying to get a pixelated text look in something I’m playing around with and noticing an issue when it comes to SpriteFont rendering. I always seem to get some smoothing when I draw, even though I’ve set SamplerState to PointClamp in my SpriteBatch.Begin. I also tried setting it on the graphics device (per a similar thread), as well as setting PreferMultiSampling to false, though I think the latter has more to do with 3D geometry instead of SpriteBatch drawing.

Anyway, the result is always the same… I can’t seem to make it not render without what appears to be an aliasing effect. It’s generally pretty easy to reproduce… simply start a new project, add a sprite font to whatever (ie, Consolas), and set the size to whatever you want (I’ve tested with 12, 14, and 18). Using some appropriately contrasting colours, render some text (ensuring your SpriteBatch.Begin uses SamplerState.PointClamp). To inspect, screen cap your window and paste into MSPaint, then zoom in.

I would expect the only colours used to be the text colour, or the background colour, but it definitely appears to do some smoothing on the text rendering.

Anybody else experienced this, or know of something I might be missing?

Thanks!

Happy New Year to you too :slight_smile: ! Which platform are you working with, and which version of MonoGame does this occur in?

The current test is with WindowsDX and using the latest build from the Downloads page, 3.7.1. I’ll do a quick test on Android and post back.

Yea I see it on Android as well. I don’t really know how to do the same image analysis on Android that I do on Windows (screen cap and then zoom without smoothing), so I just rendered to a target and then scaled that up (both using PointClamp) to the screen.

This is a pretty easy test to set up, can you maybe give it a try too on your system and let me know if you see the same issue?

To reproduce…

  1. Create new MonoGame project (Windows DX or Android)
  2. Create a new sprite font and add it to your content project.
  3. In the SpriteFont file, set FontName to Consolas, leave Size as the default (12).
  4. Add the following code to your Game1.cs file.

Add the following member variables (below graphics and spriteBatch)

        SpriteFont _font;
        RenderTarget2D _target;

Add the following to your LoadContent method…

            _font = this.Content.Load<SpriteFont>("Font");
            _target = new RenderTarget2D(graphics.GraphicsDevice, 400, 400);

Add the following to your Draw method, above the call to base.Draw…

            // Render to target
            graphics.GraphicsDevice.SetRenderTarget(_target);
            graphics.GraphicsDevice.Clear(Color.Transparent);
            spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp);

            spriteBatch.DrawString(_font, "This is a test!", Vector2.Zero, Color.Black);

            spriteBatch.End();

            // Render to screen
            graphics.GraphicsDevice.SetRenderTarget(null);
            graphics.GraphicsDevice.Clear(new Color(240, 255, 160));
            spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp);

            int scaleFactor = 16; // Set this to whatever. On my device with 1080x1920 resolution, this is appropriate.
            Rectangle dest = new Rectangle(0, 0, _target.Width * scaleFactor, _target.Height * scaleFactor);
            spriteBatch.Draw(_target, dest, Color.White);

            spriteBatch.End();

Here’s a screen cap from the simulator on my machine, which matches the results I get from my WindowsDX version.

I’m seeing this on the latest develop on a WindowsDX project (image resized; check full version):

Yea, that’s what I see as well. I wouldn’t expect to see the smoothed pixels, only hard colour ones.

Here’s an image created using Photoshop, setting the smoothing to None.

I’m not sure how XNA handled this specific case, but I had a bitmap font in an XNA game that had no smoothing. I recommend filing an issue on GitHub because this seems like a bug.

Yea, I seem to recall having no issues in XNA as well, but it was a loooong time ago. I’ll log it, thanks for helping to confirm the behaviour :slight_smile:

Something else I’m going to add… I inspected the Texture property of the font. From what I can gather, this is where it stores the pre-rendered data generated by whatever processes the SpriteFont file. I think it uses this, in combination with the Glyphs array on a SpriteFont object to draw the text.

I saved the texture to a file and opened it up. The smoothing is right there, so perhaps the issue lies in the font processor?

(NOTE: This is using a different font… it’s just what I happened to have set at the time. Same deal though.)

Are you sure the ttf font itself doesn’t have this aliasing as well before its even created as a spritefont ?

Point is working.

If this were actually the spritebatch doing this then there would be much more aliasing all over the place some of the letters have very crisp areas.

I think i have a bmp font i made with no aliasing lemme check.

Eh scaleing way up to like 6 7 its clear that’s getting aliased too.
I guess it is the importer.

Even the unicode font is getting it a little looks like it is replacing solid pixels as well. Wonder if this is how it handles scale in the spritefont itself.

I did test it with several other fonts and the same results occurred. I don’t think the smoothing is baked into the font though, because I can use a program like Photoshop or Paint.NET, disable anti aliasing, and see the expected result.

I don’t think the problem is with the sampler filter (ie, point), I think it’s with whatever generates the texture for the spritefont. I think it’s doing the smoothing right there… and I’m not sure why, or how to disable that.

So i was thinking about this a bit and thinking that this is how the importer handled upscaling,

When i set the point size in the spritefont to 24
Which is the default in windows font viewer.
I get this with no anti aliasing. Yet im still scaling up.

Looking at the previous picture this isn’t just a antialising bug this is also actually making parts of the letter in the previous picture become lightened up or alpha-ed.

See the difference in the letter ‘J’ in both pictures.

Setting this unifont to

12 perfectly crisp.

15 botched to all hell.

So this is something to do with scaling the font from the ttf on creation,

Have you tried playing around with the compression settings on the font in the content processor?

I did try those, but maybe something someone else can confirm the behaviour of?

tl;dr: SpriteFont texture generation always applies smoothing to the font. Using the BitmapFont object in MonoGame.Extended solves the problem. Followed the tutorial and everything worked perfectly.

Been a while but I figured I’d update this. I just decided to go with MonoGame.Extended’s BitmapFont solution as it renders crisply. I’m pretty confident the problem is in how MonoGame’s content processor generates the resulting texture for a SpriteFont… there seems to be no way to disable smoothing.

Doing some googling around, it seems people have been encountering this for a while now so it’s probably not reasonable to expect a fix. MonoGame.Extended’s BitmapFont does what I need it to do, so that works :slight_smile:

For anybody experiencing the same problem, here’s a link to the tutorial I followed: http://docs.monogameextended.net/Features/Bitmap-Fonts/

I personally don’t see this as a problem but reasonable feature thus not something to be fixed. I propose simple shader that will yield superior control. Simply ceil UV coordinates when sampling to closest 1-2-3 (or whatever resolution you target) pixel and do same with color. It will let you to change it on the fly without reloading sprite fonts and give you really good control (from experience, lot of ppl hate pixelated fonts, for instance Dead cells use smooth fonts as default and pixelated fonts are digged into settings). Alternatively write your own preprocessor for sampling font into sprite font, sooner on later there is good chance you will want distance signed fonts and at that point you will need to do that anyway.

No i should of posted back here there was a little talk about this on github.
Actually its more of a running talk… in particular see mr helmuts comments.

This is primarily a thing with ttf’s that don’t have font hinting.
The effect manifests itself in just about any font api in one way or another.
Even in spritefont plus there is a difference just in a different way.

Basically good font’s with hinting that are well made can do it all… but ones without it, can only work here or there like this or that but not both or wont work for some things.

E.G. like a bmp fonts are cool and all but scaling is limited and so is its quality under scaling when aliased.
A well made ttf is basically saved like a bunch of polygons SpriteFont however ultimately holds bitmaps.

So in spritefont when you specify the font size it makes a bitmap at that size but its also limited to the ttf font’s quality.

As stated above, while I’m not 100% sure, I don’t think XNA had this issue. Either way, it’s about having the option to turn the smoothing on or off. For the particular application I’m going with, it’s part of my style to have a very pixelated font look so in this case, I don’t need anything else. I had to use an external tool to achieve the result, which maybe isn’t the greatest thing. Everybody has their own opinion though.

I’m not so sure this is the problem here. I’m not going to pretend to understand the conversation you guys are having in that thread, but the above tests were done with Consolas. Maybe it has good font hinting, maybe it doesn’t… all I know is if I use other rendering packages I’m able to easily disable the anti-aliasing effect.

Here’s a simple WinForms example:

  1. Create a new WinForms project.
  2. Set your Form’s font to Consolas, 18pt.
  3. Add this into your form’s code…
protected override void OnPaint(PaintEventArgs e)
{
    base.OnPaint(e);

    Rectangle bounds = this.ClientRectangle;
    Graphics g = e.Graphics;
    g.FillRectangle(Brushes.CornflowerBlue, bounds);

    //g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SingleBitPerPixel;
    g.DrawString("This is a test!", this.Font, Brushes.White, new PointF(8, 8));
}

Trying with and without the commented line has a visible effect, which is to enable/disable the smoothing. Perhaps the MonoGame content processor just needs to expose this functionality?

I did a lot of digging around for this and there was an old XNA tool, ttf2bmp, which effectively just did the above. It used the .NET Graphics object to just render each glyph for a font to a bitmap with the appropriate options, then generated a texture sheet with that result for XNA to use. I suspect BMFont does something similar to generate its texture.

Anyway, like I said, I have something that works for me and generates the desired result. I now have nice clean font edges which plays into the style I’m looking for. Here’s a screenshot:

(NOTE: This is an 18pt font, I just zoomed it in using MSPaint. The shadow effect is added by a shader and not part of the actual font rendering.)

It’d be nice to have this out of the box with MonoGame, but it’s not a big deal since getting it working was relatively straightforward. I’m not a huge fan of being reliant on an external tool to generate the font, but ah well :slight_smile:

Yes Consolas is a windows cleartype font one of the best.

  1. typeface (hinted and then some)
  2. without cleartype 3) with cleartype.
    https://docs.microsoft.com/en-us/typography/cleartype/images/mmm.gif

The thing is when the font is rendered by the underlying rasterizer mg uses aa can’t be turned off on it.
After that sure aa can be turned off by monogame but by then the pixels are already messed up:(

The one we use now is best used for well hinted fonts or 1 to 1 scaled rasterized bitmaps due to that.