'Small (M)SDF font textures have artefacts
I am testing some font rendering with Multi-channel signed distance fields (MSDF). Everything looks perfect until I move further away from the rendered text, and it starts having weird artefacts (pixelated, some parts disappear).

The first image shows how the rendered text looks up close. As you can see, it is very smooth (open image in new tab).
But as I am moving further it starts getting more artefacts (images are zoomed in):

Even further:

All MSDF glyphs are located on a texture atlas used in the fragment shader, where each glyph is anti-aliased. In addition, each glyph is rendered on its quad.
The fragment shader (written in wgsl but is similar to glsl, updated with better results shown in the picture below):
var texture: texture_2d<f32>;
var tex_sampler: sampler;
var<uniform> unit_range: f32;
fn screen_px_range(tex_coord: vec2<f32>) -> f32 {
let range = vec2<f32>(unit_range, unit_range)/vec2<f32>(textureDimensions(texture));
let screen_tex_size: vec2<f32> = vec2<f32>(1.0, 1.0)/fwidth(tex_coord);
return max(0.5 * dot(range, screen_tex_size), 1.0);
}
fn fragment(tex_coords: vec2<f32>) -> [[location(0)]] vec4<f32> {
let s = textureSample(texture, tex_sampler, tex_coords).rgb;
// Acquire the signed distance
let d = median(s.r, s.g, s.b) - 0.5;
// Convert the distance to screen pixels
let screen_pixels = screen_px_range(in.tex_pos) * d;
// Opacity
let w = clamp(d/fwidth(d) + 0.5, 0.0, 1.0);
let bg_color: vec4<f32> = vec4<f32>(0.3, 0.2, 0.1, 0.0);
let fg_color: vec4<f32> = vec4<f32>(0.6, 0.5, 0.4, 1.0);
return mix(bg_color, fg_color, w);
}
median() function sorts the input and gets the middle number.
unit_range variable represents pixel range in the generated atlas (more info).
I copied this snippet from the official msdfgen repo, which was created by Viktor Chlumsk'y, who came up with Multi-channel signed distance fields font rendering technique.
So my question is, what is the cause for these artefacts, and how do I fix it. For example, should I use supersampling, or is there a more efficient way to fix this in the fragment shader?
I programmed this is Rust with wgpu, but I don't think that it matters.
1. Edit:
After more testing, I found that using texture mipmaps makes the text look worse. Also, making the text thicker (in the fragment shader) removes some artefacts.
Now, my rendered text looks something like this from further away:

You can see that it doesn't lose most of its details, unlike before. Also, I'll try to test supersampling and bring more updates. I'll leave this question unanswered if someone finds a better solution.
Similar problem was issued here.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
