小(M)SDF字体纹理有手工艺品

发布于 2025-01-23 14:15:14 字数 3670 浏览 0 评论 0 原文

我正在使用多通道签名的距离字段(MSDF)测试一些字体渲染。一切看起来都很完美,直到我远离渲染的文本,并且它开始具有怪异的文物(像素化,有些部分消失)。

第一个图像显示了渲染的文本如何近距离抬头。如您所见,它非常流畅(在新标签中打开图像)。

但是,随着我的进一步移动,它开始获得更多的人工制品(图像已放大):

甚至进一步:

所有MSDF字形都位于碎片着色器中使用的纹理图集上,每个字形都抗凝胶。另外,每个字形都在四边形上呈现。

片段着色器(用wgsl编写,但类似于GLSL,更新,以下图片显示了 的更好结果):

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);
}

中值()函数分组输入并获取中间号码。 unit_range 变量代表生成的Atlas中的像素范围(更多信息)。

我从字体生成和渲染技术。

因此,这些人工制品的原因是什么,我该如何修复。例如,我应该使用超级采样,还是有更有效的方法在碎片着色器中修复它?

我用WGPU对此进行了编程,但这并不重要。

编辑1:进行

了更多测试后,我发现使用纹理mipmaps会使文本看起来更糟。另外,使文本更厚(在碎片着色器中)可以消除一些人工制品。

现在,我的渲染文本从更远的地方看起来像这样:

与以前不同,您可以看到它也保留了大多数细节,我将测试SuperSmpling ing smampling并带来更多更新。最后,如果有人找到更好的解决方案,我将没有得到答案。

发出了类似的问题在这里

编辑2:

最后,我回到了MSDF渲染,创建了自己的 github repo ,我在其中添加有关此主题和MSDF的尽可能多的有用信息。在这里,您可以找到许多着色器示例,其中MSDF与厚度mod,大纲或阴影等其他修改一起使用。

我到目前为止发现解决此问题的最佳着色器看起来像这样:

#version 330

uniform sampler2D tex;
uniform float pxRange; // set to distance field's pixel range

in vec2 uvCoord;

float median(float r, float g, float b) {
    return max(min(r, g), min(max(r, g), b));
}

float screenPxRange() {
    vec2 unitRange = vec2(pxRange)/vec2(textureSize(tex, 0));
    vec2 screenTexSize = vec2(1.0)/fwidth(uvCoord);
    return max(0.5*dot(unitRange, screenTexSize), 1.0);
}

void main() {
    vec4 texel = texture(tex, uvCoord);
    float dist = median(texel.r, texel.g, texel.b);
    
    float pxDist = screenPxRange(tex) * (dist - 0.5);
    float opacity = clamp(pxDist + 0.5, 0.0, 1.0);
    
    gl_FragColor = vec4(1.0, 1.0, 1.0, opacity);
}

查看Chlumsky的 msdfgen 仓库。

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 the pixel range in the generated atlas (more info).

I copied this snippet from the official msdfgen repo, created by Viktor Chlumsk'y, who came up with his Multi-channel signed distance fields font generating and rendering technique.

So, 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 in Rust with wgpu, but it doesn't really matter.

Edit 1:

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:

Different from before, you can see that it keeps most of its details Also, I'll test supersampling and bring more updates. Finally, I'll leave this question unanswered if someone finds a better solution.

A similar problem was issued here.

Edit 2:

Finally, I came back to MSDF rendering and created my own GitHub repo, where I'm adding as much useful info as possible about this topic and MSDFs in general. There you can find many shader examples where MSDFs are used with additional modifications like thickness mods, outlines or shadows.

The best shader I have found so far to solve this problem looks something like this:

#version 330

uniform sampler2D tex;
uniform float pxRange; // set to distance field's pixel range

in vec2 uvCoord;

float median(float r, float g, float b) {
    return max(min(r, g), min(max(r, g), b));
}

float screenPxRange() {
    vec2 unitRange = vec2(pxRange)/vec2(textureSize(tex, 0));
    vec2 screenTexSize = vec2(1.0)/fwidth(uvCoord);
    return max(0.5*dot(unitRange, screenTexSize), 1.0);
}

void main() {
    vec4 texel = texture(tex, uvCoord);
    float dist = median(texel.r, texel.g, texel.b);
    
    float pxDist = screenPxRange(tex) * (dist - 0.5);
    float opacity = clamp(pxDist + 0.5, 0.0, 1.0);
    
    gl_FragColor = vec4(1.0, 1.0, 1.0, opacity);
}

Check out Chlumsky's msdfgen utility repo.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文