What to do about scaled down df fonts losing color?

You can see this example with a df font when it is scaled to 0.25 and lower it goes from white to grey. What would be good way to modify it so it maintains color better at smaller scales?

df_font

Same but with red

df_font2

Red with border and shadow set to red is slightly better

df_font3

White with white border and white shadow

df_font4

I seen this too. That been happen after some engine update, not sure which. Now my labels are all gray instead of white.

I think it was a change to the df shader and the way dfs were generated? I’ll see if I can dig up old shader from backups…

Old

varying mediump vec2 var_texcoord0;
varying lowp vec4 var_face_color;
varying lowp vec4 var_outline_color;
varying mediump vec4 var_sdf_params;
uniform lowp sampler2D texture;
uniform lowp vec4 texture_size_recip;

mediump float sample_df(mediump vec2 where)
{
    return texture2D(texture, where.xy).x;
}

mediump float scale_sample(mediump float v)
{
    return v * var_sdf_params.x + var_sdf_params.y;
}

mediump vec2 eval_borders(mediump vec2 where)
{
    mediump float df = scale_sample(sample_df(where));
    mediump vec2 borders = vec2(clamp((df - var_sdf_params.z), 0.0, var_sdf_params.w), clamp(df, 0.0, var_sdf_params.w));
    return borders * borders * (3.0 - 2.0 * borders);
}

void main_supersample()
{
    mediump vec2 dtex = vec2(0.5 * texture_size_recip.xy / var_sdf_params.x);
    // sample 4 points around var_texcoord. the sample pattern will not be fixed in texture coordinate space,
    // and it is assumed the text is uniformly scaled.
    mediump vec4 dt = vec4(vec2(var_texcoord0 - dtex), vec2(var_texcoord0 + dtex));
    mediump vec2 borders = 2.0 * eval_borders(var_texcoord0)
                   + eval_borders(dt.xy) // upper left
                   + eval_borders(dt.xw) // bottom left
                   + eval_borders(dt.zy) // upper right
                   + eval_borders(dt.zw); // bottom right

    borders = (1.0/6.0) * borders;
    gl_FragColor = mix(mix(var_face_color, var_outline_color, borders.y), vec4(0), borders.x);
}

void main_default()
{
    lowp vec2 borders = eval_borders(var_texcoord0);
    gl_FragColor = mix(mix(var_face_color, var_outline_color, borders.y), vec4(0), borders.x);
}

void main()
{
      main_default();
}

New

varying lowp vec2 var_texcoord0;
varying lowp vec4 var_face_color;
varying lowp vec4 var_outline_color;
varying lowp vec4 var_sdf_params;

uniform mediump sampler2D texture;
uniform lowp vec4 texture_size_recip;

void main()
{
    lowp float distance = texture2D(texture, var_texcoord0).x;

    lowp float sdf_edge = var_sdf_params.x;
    lowp float sdf_outline = var_sdf_params.y;
    lowp float sdf_smoothing = var_sdf_params.z;
    
    lowp float alpha = smoothstep(sdf_edge - sdf_smoothing, sdf_edge + sdf_smoothing, distance);
    lowp float outline_alpha = smoothstep(sdf_outline - sdf_smoothing, sdf_outline + sdf_smoothing, distance);
    lowp vec4 color = mix(var_outline_color, var_face_color, alpha);

    gl_FragColor = color * outline_alpha;
}

The previous distance field font shader rendered the fonts too “thick” compared to the font source file, that might be why it appears the fonts “grey out” more when scaled down now (they appear thinner than previously).

If you want to fiddle with the parameters we use when rendering df fonts, you can copy the df font material and add a vertex program constant and replace elements in var_sdf_params. From the top of my head the value we use for sdf_edge is 0.75, and sdf_outline is some value sdf_edge > sdf_outline > 0 depending on the outline set in the font, and lastly sdf_smoothing is how to blend between edge->outline and outline->outside which is a function of the scale on the component.

Note that we currently don’t take into account the projected screen size of fonts when calculating the smoothing, so your fonts may look strange if using for example a perspective camera. There is a ticket for this DEF-2963.

4 Likes

df_font5

Top normal bottom

    lowp float sdf_edge = 0.0;
    lowp float sdf_outline = var_sdf_params.y;
    lowp float sdf_smoothing = 0.1;

So it seems for scaled down df fonts want to reduce the smoothing with scale (although this may be too much) to avoid the greying.

 lowp float sdf_smoothing = var_sdf_params.z * 0.35;

Seems close to good.

4 Likes