mojira.dev
MC-227034

TTF glyphs are antialiased against non-transparent background

TTF glyphs have unwanted "outline" effect.

This issue closely relates to MC-207500.


How to replicate:

  1. Install resource pack "ttf resoucepack.zip" from attachments and select it.

  2. See any font on very contrast background. (ex. White Text + Snow + /time set day)


Dummy command used to make screenshot:

/title @s title "ABCDEFGHIJKLMNOPQRSTUVWXYZ"

 

Linked issues

Attachments

Comments 8

Can't reproduce in 1.17 pre-release 2; My game crashes in 1.16.5 when i load the pack. (Note: are you atalking about that black outline around colored signs?)

[media]

@sac1 You are all about another bug, MC-161933. Your attached screenshot is not for this issue either. Also my game is not crashing on 1.16.5 when loading the pack.

I'm not exactly sure what your issue here is?

[media][media]

– are these signs with glow ink applied? So is your issue that the background seems very odd?

[media]

– I assume you mean the slight gray outline here, similar to MC-161933? Same with

[media]

?

Please clarify.

@violine1101

In short term, MC-161933 is how glyphs with transparent pixels blend with sign model. Transparent pixels near edges of TTF glyphs of some fonts, which created by anti-aliasing, or custom transparent symbols are both rendered in same render pass with sign, so that transparent font pixels replace existing sign pixels, so you can see through signs whats behind them. (Also applies to sac1's screenshot)

This issue however, isn't about how font transparency is handled at runtime. This issue is about Minecraft TTF font's resource reload stage, where it pre-renders all needed glyphs to a texture (where glyphs are rasterized and anti-aliased).

For text coloring reasons, font glyphs are usually rendered in white color, which minecraft does. But what also minecraft does is rasterizing those glyphs on black background (glyph dump attached). This way, the more transparent pixel is, the more black it is. This is a bug and transparent pixels should have not only transparency mask, but also should be rendered on transparent background.

Also, Regular OpenGL's blend functions aren't enough to remove this background the right way. This is why issue name says "anti-aliased", not "rendered".

So I fixed it using a mod. Turns out, signs are not affected by this bug at all. I am removing all attachments with signs which I can remove.

To fix this, in Mojang's mappings, I upgraded com/mojang/blaze3d/font/TrueTypeGlyphProvider$Glyph#upload from 1-channel image (NativeImage$Format#LUMINANCE) to 4-channel image (NativeImage$Format#RGBA). I moved the luminance channel to alpha channel and set all RGB values to 255 so the whole glyph's image is white. Also I changed TrueTypeGlyphProvider$Glyph#isColored to return true. I know there is a better way to fix it, but this works for me for now.

Affects versions up to 1.19.3, attached is a .ttf font used in place of alt, seams its rendered red with a black background:

[media]

@Alexander you may want to add the tags "font", "fonts", and "ttf" to this bug report, if possible

Code analysis

The fragment shader for the text_intensity render type uses the rendertype_text_intensity shader program, whose fragment shader looks like this:

#version 150

#moj_import <fog.glsl>

uniform sampler2D Sampler0;

uniform vec4 ColorModulator;
uniform float FogStart;
uniform float FogEnd;
uniform vec4 FogColor;

in float vertexDistance;
in vec4 vertexColor;
in vec2 texCoord0;

out vec4 fragColor;

void main() {
    vec4 color = texture(Sampler0, texCoord0).rrrr * vertexColor * ColorModulator;
    if (color.a < 0.1) {
        discard;
    }
    fragColor = linear_fog(color, vertexDistance, FogStart, FogEnd, FogColor);
}

The intensity channel of the texture controls not only the alpha channel of the fragment but also its red, green, and blue channels. The render program JSON, on the other hand, assumes that the color output of the fragment shader uses non-premultiplied alpha.

This issue can be fixed by making the texture intensity affect only the alpha channel of the fragment:

vec4 color = vec4(vec3(1.0), texture(Sampler0, texCoord0).r) * vertexColor;

Alternatively, the blend parameters in the shader program JSON could be modified to assume alpha premultiplication:

"blend": {
        "func": "add",
        "srcrgb": "1",
        "dstrgb": "1-srcalpha"
    },

Alexander

(Unassigned)

Confirmed

Rendering, Resource Packs, Text

font, fonts, rendering, resource-pack, ttf

1.16.5, 1.17 Pre-release 2, 1.17 Pre-release 3, 1.17 Pre-release 4, 1.17 Pre-release 5, ..., 22w24a, 1.19.3, 1.19.4, 23w13a, 23w17a

Retrieved