Advertisement

BMFont and gamma correction

Started by March 02, 2011 12:46 AM
7 comments, last by WitchLord 13 years, 11 months ago
Hi

It looks like fonts generated with smoothing enabled are rendered in non linear space. This result in over darkened text when using blindly, but can be fixed with proper pixel shader (check image attached).

What happened when outline is added and encoded in single channel? Is it converted to linear space?
Does super sampling do any correction?

[attachment=1558:Image3.jpg]
I'm not sure what is causing the effect you see, but I don't do any kind of special antialiasing or gamma correction in BMFont. I just use the plain vanilla font smoothing done by GDI when converting true type to bitmap, and supersampling if you chose that option.

When encoding glyph and outline in a single channel, there are only 128bits of grayscale for the transition from glyph to outline, and 128bits of alpha for the transition from outline to background. You need to compensate for that in the pixel shader. Maybe that is the cause of the effect you see.

Regards,
Andreas

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

Advertisement
I was using standard alpha-blending with constant color set in pixel shader and alpha read from texture. Problem with black font is that alpha values are correct only for white font over black background. For example: 50% transparent pixel should have 50% white 50% black color, but with gamma correction this is 0,5^1/2,2=0,73 (so alpha value is around 186), and while it gives good result for white font (because gamma is already applied), when using black font over white background you get: black*0,73 + white*(1-0,73) = 0,27, but it's still middle gray and should be 0,73. Shader code I am using to fix this blends between two different ramps (but this is only approximation since it doesn't know background color):
void fontstate(out float4 color : COLOR,
float2 FontUV : TEXCOORD0,
uniform sampler2D FontPage : register(s0),
uniform float4 FontColor : register(c0) )
{
float4 diff = tex2D(FontPage, FontUV.xy)*FontColor;
float lf = max(diff.x, max(diff.y, diff.z));
float inv_w = 1.0f - pow(1.0f - pow(diff.w, 2.2f), 1.0f/2.2f);
diff.w = lerp(inv_w, diff.w, lf);
color = diff;
}


So, glyph is rendered as white on black (with or without outline), outline is black on white ? (I'm not sure here), and when encoding in single channel they must by split and transformed to [0;1] before correction.

About super sampling, if you don't use any gamma correction you get linear results (simple average of 2 black pixels and 2 white gives 0,5 not 0,73) and I think that is why it produces this blur effect.
Can you add extra option, like "Linear space" for super sampling?, that will work as:
- render font
- transform to linear space (may require higher precision here)
- downsample
- transform back to sRGB
I'm a bit lost here.

The actual pixel values in the texture are produced by the the GDI function GetGlyphOutline. As far as I know the antialiasing done by that function is in linear space, i.e. 50% transparency is 0.5. The supersampling option I do in BMFont is just plan average of these values, so it will also continue in linear space. Whether you export the font as black on white, or white or black, the 50% transparency is still 0.5.

Hmm, I think I know what's going on. You must be exporting the font with the options (A:Glyph, R:Glyph, G:Glyph, B:Glyph). This will actually produce the pixels (0.5,0.5,0.5,0.5) where the pixel is half-filled by the glyph. This corresponds to 50% transparent, 50% gray, and when blending it on the background color you get 50% gray + 50% background color, which is why you get 25% gray when rendering white on black, and 75% gray when rendering black on white.

What you should do is to export the font as (A:Glyph, R:One, G:One, B:One) or (A:Glyph, R:Zero, G:Zero, B:Zero) depending on your option. This will make sure the color channel has a solid color, and only the alpha channel is what is controlling the aliasing.

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

Finally, after checking pixel-by-pixel font's texture file I found it's different than one created with current BMFont version. Somehow some fonts survived from early 2008 (but only this particular one was anti aliased (and in gamma space)). So that was error on my side, I'm sorry for wasting your time.
No worries. You're not wasting my time. :)

I still dont understand why you think the textures created by BMFont would be in gamma space. I didn't do anything differently in BMFont for earlier versions in regards to anti-aliasing, except maybe if the font you have was created while I was still using clear-type during the glyph rendering. Maybe clear-type is rendering in gamma space. That would make sense, since clear-type is about producing the best visuals and not just about anti-aliasing small fonts.

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

Advertisement
I still dont understand why you think the textures created by BMFont would be in gamma space.
Tehnically, any image that looks right on (i.e. is designed to be viewed on) a computer monitor is in gamma space. The vast majority of image files are in gamma space (e.g. every image on this webpage). If GDI's output is meant to be displayed directly onto computer sceens without further modification, then it's in gamma space too.
Like Hodgman said, it looked good in my previous engine, before I even learned I have to do some gamma correction (I didn't use dark/black fonts back then)
(and currently I was feeding my HDR pipeline with new 'linear' fonts thinking they are gamma corrected and hardware back-transformed at sample time, but that only works for color channels not alpha rolleyes.gif, so at the end everything was right)

This strange font texture must be older than I think (at 2008 I bought new PC so file time stamp is irrelevant), it looks like gamma corrected, but is not mathematically accurate, and uses only 16 colors (you can download it from here: png fnt )

In the meantime, looking for gamma related stuff, I found some articles about sub-pixel font rendering if you're intrested.
link and link 2

I confess I never really cared about studying gamma space, but it seems I'll have to change that now. Thanks for the links, they'll be good starting point.

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

This topic is closed to new replies.

Advertisement