playcanvas
Version:
PlayCanvas WebGL game engine
80 lines (61 loc) • 3.03 kB
JavaScript
var msdfPS = /* glsl */ `
uniform sampler2D texture_msdfMap;
float median(float r, float g, float b) {
return max(min(r, g), min(max(r, g), b));
}
float map (float min, float max, float v) {
return (v - min) / (max - min);
}
uniform float font_sdfIntensity; // intensity is used to boost the value read from the SDF, 0 is no boost, 1.0 is max boost
uniform float font_pxrange; // the number of pixels between inside and outside the font in SDF
uniform float font_textureWidth; // the width of the texture atlas
uniform vec4 outline_color;
uniform float outline_thickness;
uniform vec4 shadow_color;
uniform vec2 shadow_offset;
varying vec4 outline_color;
varying float outline_thickness;
varying vec4 shadow_color;
varying vec2 shadow_offset;
vec4 applyMsdf(vec4 color) {
// Convert to linear space before processing
// TODO: ideally this would receive the color in linear space, but that would require larger changes
// on the engine side, with the way premultiplied alpha is handled as well.
color.rgb = gammaCorrectInput(color.rgb);
// sample the field
vec3 tsample = texture2D(texture_msdfMap, vUv0).rgb;
vec2 uvShdw = vUv0 - shadow_offset;
vec3 ssample = texture2D(texture_msdfMap, uvShdw).rgb;
// get the signed distance value
float sigDist = median(tsample.r, tsample.g, tsample.b);
float sigDistShdw = median(ssample.r, ssample.g, ssample.b);
// smoothing limit - smaller value makes for sharper but more aliased text, especially on angles
// too large value (0.5) creates a dark glow around the letters
float smoothingMax = 0.2;
// smoothing depends on size of texture on screen
vec2 w = fwidth(vUv0);
float smoothing = clamp(w.x * font_textureWidth / font_pxrange, 0.0, smoothingMax);
float mapMin = 0.05;
float mapMax = clamp(1.0 - font_sdfIntensity, mapMin, 1.0);
// remap to a smaller range (used on smaller font sizes)
float sigDistInner = map(mapMin, mapMax, sigDist);
float sigDistOutline = map(mapMin, mapMax, sigDist + outline_thickness);
sigDistShdw = map(mapMin, mapMax, sigDistShdw + outline_thickness);
float center = 0.5;
// calculate smoothing and use to generate opacity
float inside = smoothstep(center-smoothing, center+smoothing, sigDistInner);
float outline = smoothstep(center-smoothing, center+smoothing, sigDistOutline);
float shadow = smoothstep(center-smoothing, center+smoothing, sigDistShdw);
vec4 tcolor = (outline > inside) ? outline * vec4(outline_color.a * outline_color.rgb, outline_color.a) : vec4(0.0);
tcolor = mix(tcolor, color, inside);
vec4 scolor = (shadow > outline) ? shadow * vec4(shadow_color.a * shadow_color.rgb, shadow_color.a) : tcolor;
tcolor = mix(scolor, tcolor, outline);
// Convert back to gamma space before returning
tcolor.rgb = gammaCorrectOutput(tcolor.rgb);
return tcolor;
}
`;
export { msdfPS as default };