To use a multi-channel signed distance field (MSDF) in a fragment shader, sample the texture and compute the median of the three color channels.
Important: Interpret MSDF color channels in linear space, not sRGB.
Basic Implementation
in vec2 texCoord;
out vec4 color;
uniform sampler2D msdf;
uniform vec4 bgColor;
uniform vec4 fgColor;
float median(float r, float g, float b) {
return max(min(r, g), min(max(r, g), b));
}
void main() {
vec3 msd = texture(msdf, texCoord).rgb;
float sd = median(msd.r, msd.g, msd.b);
float screenPxDistance = screenPxRange()*(sd - 0.5);
float opacity = clamp(screenPxDistance + 0.5, 0.0, 1.0);
color = mix(bgColor, fgColor, opacity);
}
Calculating screenPxRange()
screenPxRange() represents the distance field range in output screen pixels.
For 2D rendering: Use a precomputed uniform value. If the pixel range was set to 2 for a 32x32 field drawn on a 72x72 quad, the value is (72/32) * 2 = 4.5.
For 3D perspective: Use fragment derivatives to handle varying texture scales:
uniform float pxRange; // set to distance field's pixel range
vec2 sqr(vec2 x) { return x*x; }
float screenPxRange() {
vec2 unitRange = vec2(pxRange)/vec2(textureSize(msdf, 0));
vec2 screenTexSize = inversesqrt(sqr(dFdx(texCoord))+sqr(dFdy(texCoord)));
return max(0.5*dot(unitRange, screenTexSize), 1.0);
}
Note: screenPxRange() should not be lower than 1. If it is lower than 2, anti-aliasing may fail; consider re-generating the field with a wider range.