Distance field font artifacts

Started by
7 comments, last by unbird 10 years, 9 months ago

Hello,

I'm wondering how Valve got their distance field font looking so good. I tried generating my font with other tools, my tool and photoshop but the results are almost never as perfect as they are in Valves paper.

So my question is: must you fine tune the alpha threshold and is fattening the font characters "correct" in order to get them to draw nicely?

The distance field font texture is 256x128 and every letter is around 20x20 pixels.

Here are two images:

- the top one has thinner font with more artiafacts

- the bottom one has fatter font with less artifacts

http://i.imgur.com/ACVpfnX.png

http://i.imgur.com/OWmk1Zg.png

Advertisement

I think that in Valve's paper http://www.valvesoftware.com/publications/2007/SIGGRAPH2007_AlphaTestedMagnification.pdf they're just using a higher resolution than you. In figure 4 (the image with significant magnification), they're using a 256x256 "No Trespassing" source image, which judging by the layout of the source image in figure 2 would amount to 40-50 pixel height per character.

FFS Windows 8... third time I start typing this reply...

I think that in Valve's paper http://www.valvesoftware.com/publications/2007/SIGGRAPH2007_AlphaTestedMagnification.pdf they're just using a higher resolution than you. In figure 4 (the image with significant magnification), they're using a 256x256 "No Trespassing" source image, which judging by the layout of the source image in figure 2 would amount to 40-50 pixel height per character.

This, exactly. Distance field fonts do not look better by "magic" (though to some extent that is also the case because the distance information interpolates more favorably) but because they contain more information.

Instead of a boolean value, every pixel holds 8 bits (or 16 bits) of useful information. This is equivalent to using a texture that is 16 times (256 times) bigger in every dimension!

However, if Shannon taught us one thing, that is that information that isn't recorded does not magically appear because you upscale it later. The information must be present in the original dataset, i.e. you must use a larger source image to generate the distance field font.

Thanks for the replies, makes sense.

Off topic tip: Instead of an alpha threshold, you could try a steep gradient outside the threshold, which will give nice antialiasing :)

Yup done that, looks very nice :D

Off topic tip: Instead of an alpha threshold, you could try a steep gradient outside the threshold, which will give nice antialiasing smile.png

Could you possibly give some more detail how this work? How to make "steep gradient" to blend between DF and base font texture?

It's in that valve paper as well, the paragraph about antialiasing. The corresponding code is the one in the SOFT_EDGES if-clause, basically a smoothstep using the distance value and some range. Alternatively - also mentioned in the paragraph - on SM 3.0 one can use hardware gradients (ddx, ddy) so one wouldn't need to adjust the range for different sizes (viewing distances).

Thanks, but i need more help to understand this?

1. This Valve article is only valid for alpha tested "objects"?

2.

alpha = smoothstep( edge_min, edge_max, alphaDF );

In what ranges these first two parameters should be in context of rendering 2d fonts?

3. I don't understand ddx/y function, what parameters is it expecting and how should i replace smoothstep with them?

Thank you for your time and understanding.

*Digging up my distance field shader*

You're welcome.

1. This Valve article is only valid for alpha tested "objects"?

I don't think so. If you enable alpha blending that shader should work without any change. You can of course combine it with alpha testing (e.g. for performance).

In what ranges these first two parameters should be in context of rendering 2d fonts?

Depends on how big the decal (or whatever) appears on your render target and how you created the distance field in the first place.

In short: Let's play with it: Here's a distance you can use

61817e264354770.gif

(Click on the images, there's scaled up/down. I deliberately don't use the forum's gallery functionality: the images get sometimes screwed - or disappear. Imagebam keeps them for ages).

Here's a minimalpixel shader I just came up with for illustration:


float4 PS(in float2 texCoord: TEXCOORD0, in float4 diffuse: COLOR0) : COLOR0
{
    float dist = tex2D(DiffuseSampler, texCoord).r;
    float center = 0.46; 
    float transition = 0.01; // in distance field space !    
    diffuse.a *= smoothstep(center - transition, center + transition, dist);    
    return diffuse;
}
Note: I had to play around with the center value. Can't quite remember how I generated the distance field.

This yields:
6980a1264354773.gif

Playing with the transition value (now 0.02)
af9fa0264354776.gif

transition now 0.05
08ca32264354779.gif

3. I don't understand ddx/y function, what parameters is it expecting and how should i replace smoothstep with them?


ddx() gives you the rate of change of any value (not only scalars) from one pixel to the next to the right. ddy is the same for down.

With this information one can achieve a couple of useful stuff but here one can estimate the distance field change in screen space.
Here's a good explanation for this estimation (without the hardware gradients).
This GPU Gems article is also enlighting. (Paragraph 25.5 about Antialiasing).

Don't bother too much, there's a shortcut for the problem at hand : fwidth

    float transition = fwidth(dist) * 1.0;
This yields approx 1 pixel AA independant of how big we render.

3d5c55264354781.gif

Cheers.

This topic is closed to new replies.

Advertisement