3

Currently I'm using FreeType in subpixel mode and take the largest color of each pixel as alpha value, with the following fragment shader:

    uniform sampler2D Image;
    uniform vec4 Color;

    smooth in vec2 vVaryingTexCoord;

    out vec4 vFragColor;

    void main(void){
        vec4 color = texture(Image, vVaryingTexCoord);
        vFragColor = color * Color;
    }

This works fine for dark backgrounds, but on lighter ones the border pixels show (e.g. when a text pixel is (1,0,0)). To make it work with brighter backgrounds, I'd need to pass the background color and do the blending myself, which starts breaking down once I move to more complex backgrounds.

Is there a way to use the RGB values from FreeType as alpha values for a solid color (which is passed to the shader)? This formula basically, where b = background pixel, t = current text pixel, c = static color:

b*((1,1,1) - t) + t*c.rgb*c.a

I think drawing everything else first and passing that framebuffer to the font shader would work, but that seems a bit overkill. Is there a way doing this in the OpenGL blend stage? I tried playing around with glBlendFunc and such, but didn't get anywhere.

weltensturm
  • 2,164
  • 16
  • 17
  • In my experience this is a tough nut to crack. Your conclussions are the same as mine. I eventually gave up. You might want to try "force" a background color through a halo around the text and blend against that color. As for OpenGL blend stage, my gut says "can't be done". – Andreas Feb 03 '18 at 13:12
  • The [FreeType shader](https://github.com/rougier/freetype-gl/blob/master/shaders/text.frag) (look at about the end) shows using `max` and `min` from the texture and using them as alpha. Then, computes blending in the shader. – Ripi2 Feb 03 '18 at 19:13

1 Answers1

4

It's possible using Dual Source Blending, available since OpenGL 3.3. This spec draft even mentions subpixel rendering as use case. All that is needed to make it work:

glBlendFunc(GL_SRC1_COLOR, GL_ONE_MINUS_SRC1_COLOR);

(don't forget to enable GL_BLEND, it happens to me all the time :D)

Specify dual output in the fragment shader: (You can bind by name instead if you want, see spec)

layout(location = 0, index = 0) out vec4 color;
layout(location = 0, index = 1) out vec4 colorMask;

In main:

color = StaticColor;
colorMask = StaticColor.a*texel;

Where StaticColor is the global text color uniform, and texel is the current pixel value of the glyph.

weltensturm
  • 2,164
  • 16
  • 17