This content originally appeared on Level Up Coding - Medium and was authored by Michael Gevlich
MSDF text rendering for WebGL with msdf-bmfont-xml
I used the msdf-bmfont-xml tool for generating font atlases and rendering textures for (multichannel signed distance fields) MSDF so that labels look much prettier! It was helped by the msdf-bmfont-xml tool for generating font atlases and rendering multichannel signed distance fields (MSDF) textures.
msdf-bmfont-xml allows you to generate a variety of texture atlases from ttf fonts. In our case, the atlas texture is a multichannel signed distance field that renders the sharp corners of the letters, in contrast to the original signed distance field.
In this article, I want to tell you what a letter storage atlas is and how to display text using WebGL.
Texture atlas msdf-bmfont-xml
Font texture atlas is a texture with saved on it symbols images. Each picture has corresponding texture coordinates.
To create the atlas, I use the command:
msdf-bmfont.cmd — reuse -i .\charset.txt -m 512,512 -f json -o %1.png -s 32 -r 8 -p 1 -t msdf %1
where %1 — being the name of the ttf font file, charset.txt — being a file with a set of symbols for which the atlas is being built, the rest of the parameters you can find on the official repository page of the msdf-bmfont-xml.
If the running the command is successful, several files are created. We are interested in the png atlas texture and the json atlas description.
In msdf-bmfont-xml all information on the symbol is stored in the chars section, for instance letter ‘q’ (in the picture above) has coordinates x = 131, y = 356, width = 22, height = 32, i.e. the coordinates of the left-top corner are [131, 356] and right bottom are [131+22, 356+32]. So, if font image has 512 x 512 pixel size, then texture coordinates of the ‘q’ letter are [131/512, 356/512 ] and [153/512, 388/512]. If we apply these texture coordinates to the shader that draws the rectangle, then we will see our symbol in this rectangle. On top of that, we know width and height of a glyph (or symbol), which allows us to set the size of the rectangle to make the symbol looks right proportion-wise.
{
id: 113,
char: “q”,
width: 22,
height: 32,
xoffset: -3,
yoffset: 11,
xadvance: 18,
x: 131,
y: 356,
...
}
Other important parameters for character positioning in a string are:
xoffsеt — horizontal offset of the character in pixels
yoffset — character vertical offset in pixels
xadvance — glyph width; distance from the left border of a glyph to the beginning of the next character in the line
Also, glyph has id which identifies a letter in the table of the horizontal kernings. Kerning— is the distance between two specific letters.
Example: displaying text “Wg!” for Arial font
Glyph parameters:
W: width: 37, height: 31, xoffset: -4, yoffset: 4, xadvance: 30
g: width: 23, height: 32, xoffset: -3, yoffset: 10, xadvance: 18
! : width: 11, height: 31, xoffset: -1, yoffset: 4, xadvance: 9
The origin of coordinates is the upper left corner, initially glyphs are located on one line (upper green line in the pictures below) and each glyph has its own position in the line according to the width parameter.
The next picture shows offset of characters relative to horizontal (central) axis vertically, according to yoffsset parameter.
Blue lines shows xadvance parameter (distance to the next character in the line), also each character is shifted horizontally according to the parameter xoffset.
The current version can be considered ready, however, for best quality you should apply kerning options, that is the offset relative to each other of two specific characters. In this example, I am not showing kernings; kerning is taken into account in the xoffset parameter when displaying text.
MSDF text rendering
Each glyph is drawn as a square by calling drawArrays function, where input buffer is a vertex buffer for the array:
vec2 a_vertices = [0, 0, 0, -1, 1, -1, 1, -1, 1, 0, 0, 0]
Basic character parameters are being normalized when building a font atlas:
imageSize = 512; //Atlas image texture size
nWidth = width / imageSize; //normalized glyph width
nHeight = height / imageSize; //normalized glyph height
nAdvance = xadvance / imageSize; //normalized glyph size to the next character in the line
nXOffset = xoffset / imageSize; //normalized horizontal offset
nYOffset = 1.0 — yoffset / imageSize; //normalized vertical offset
GLSL fragment shader
Vertex shader:
...
vec2 v = screenPos + (a_vertices * a_gliphParam.xy + a_gliphParam.zw + vec2(advanceOffset, 0.0)) * a_size;
Где:
screenPos - screen space string coordinates
a_vertices - quad vertices
a_gliphParam - glyph metrics, where:
x - nWidth, y - nHeight, z - nXOffset, w - nYOffset
advanceOffset - total offset by nAdvance, for each next glyph in the string
a_size - screen space font size in pixels
Fragment shader:
...
const float imageSize = 512.0;
const float distanceRange = 8.0;
layout(location = 0) out vec4 outScreen;
float median(float r, float g, float b) {
return max(min(r, g), min(max(r, g), b));
}
float getDistance() {
vec3 msdf = texture(fontTexture, v_uv).rgb;
return median(msdf.r, msdf.g, msdf.b);
}
void main () {
vec2 dxdy = fwidth(v_uv) * vec2(imageSize);
float dist = getDistance() + min(v_weight, 0.5 – 1.0 / DIST_RANGE) — 0.5;
float opacity = clamp(dist * distanceRange / length(dxdy) + 0.5, 0.0, 1.0);
outScreen = vec4(v_rgba.rgb, opacity * v_rgba.a);
}
Где:
fontTexture - font atlas texture
v_weight - glyph weight from 0 to 1, for outline. By default is 0. Outline is rendered first pass with v_weight value.
v_uv - texture coordinates of glyph in font atlas
v_rgba - цвет символа или окантовки
...
I hope I have explained clearly enough how to work with font atlases and how I use msdf-bmfont-xml for my project. This approach has improved the quality of the text labels on the map significantly.
Write in the comments what do you use to render fonts, and how do you think you can improve the quality of text labels?
If you have any questions, you can ask them on the openglobus forum https://groups.google.com/forum/#!forum/openglobus, and I will definitely answer!
Cheers!
Useful sources:
MSDF font rendering in WebGL was originally published in Level Up Coding on Medium, where people are continuing the conversation by highlighting and responding to this story.
This content originally appeared on Level Up Coding - Medium and was authored by Michael Gevlich
Michael Gevlich | Sciencx (2021-04-03T23:17:38+00:00) MSDF font rendering in WebGL. Retrieved from https://www.scien.cx/2021/04/03/msdf-font-rendering-in-webgl/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.