This is a series of blog posts related to WebGL. New post will be available every day
Join mailing list to get new posts right to your inbox
Built with
Hey 👋
Welcome to WebGL month.
In previuos tutorials we were focused on rendering 2d and 3d shapes, but never rendered text, which is important part of any application.
In this article we'll review possible ways of text rendering.
HTML overlay
The most obvoius and simple solution would be to render text with HTML and place it above the webgl canvas, but this will only work for 2D scenes, 3D stuff will require some calculations to calculate text position and css transforms
Canvas as texture
Other technique might be applied in a wider range of cases. It requires several steps
- create another canvas
- get 2d context (
canvas.getContext('2d')
) - render text with
fillText
orstrokeText
- use this canvas as webgl texture with correct texture coordinates
Since the texture is a rasterized image, it will loose the quality when you'll come "closer" to the object
Glyphs texture
Each font is actually a set of "glyphs" – each symbol is rendered in a signle image
A | B | C | D | E | F | G |
---------------------------
H | I | J | K | L | M | N |
...
Each letter will have it's own "properties", like width (i
is thiner than W
), height (o
vs L
) etc.
These properties will affect how to build rectangles, containing each letter
Typically aside of texture you'll need to have a javascript object describing all these properties and coordinates in original texture image
const font = {
textureSize: {
width: 512,
height: 512,
},
height: 32,
glyphs: {
a: { x: 0, y: 0, height: 32, width: 16 },
b: { x: 16, y: 0, height: 32, width: 14 },
},
// ...
};
and to render some text you'll need something like this
function getRects(text, sizeMultiplier) {
let prevLetterX = 0;
const rects = text.split('').map((symbol) => {
const glyph = font.glyphs[symbol];
return {
x: prevLetterX,
y: font.height - glyph.height,
width: glyph.width * sizeMultiplier,
height: glyph.height * sizeMultiplier,
texCoords: glyph,
};
});
}
Later this "rects" will be used to generate attributes data
import { createRect } from './gl-helpers';
function generateBuffers(rects) {
const attributeBuffers = {
position: [],
texCoords: [],
};
rects.forEach((rect, index) => {
attributeBuffers.position.push(...createRect(rect.x, rect.y, rect.width, rect.height)),
attributeBuffers.texCoords.push(
...createRect(rect.texCoords.x, rect.texCoords.y, rect.texCoords.width, rect.texCoords.height)
);
});
return attributeBuffers;
}
There's a gl-render-text package which can render texture based fonts
Font triangulation
Since webgl is capable of drawing triangles, one more obvious solution would be to break each letter into triangles
This seem to be a very complex task 😢
Luckily – there's a fontpath-gl package, which does exactly this
Signed distance field font
Another technique for rendering text in OpenGL/WebGL
Find more info here
Join mailing list to get new posts right to your inbox
Built with
Top comments (0)