Rendering text in Three.js using WebGPU

Background

When researching text rendering in Three.js I found two methods were the most recommended, using three.js's FontLoader's built in generateShapes method, or use Troika Text for Three.js.

Three.js's approach with the FontLoader seems okay when used sparingly, but struggles at scale. It generates complex geometries for each character of the font, leading to a relatively high vertex count and slower initial loads as the geometry for the text generates. Scaling also becomes an issue, as the geometry is made at a fixed resolution so as you zoom into text it becomes jagged unless you regenerate the geometry with even more sub-divisions.

Wireframe of the geometry generated by Three FontLoader for the text Hello World

Troika, on the other hand, seemed better. By using SDFs (signed distance fields) for the text, it only needs to render each character as a single quad geomeotry and then the shape of the character itself is handled by a shader. This approach improves on the FontLoader by having simple geometry which is quick to generate, while also not having scaling issues as shader will adjust and become more detailed as you zoom in.

Wireframe of the geometry generated by an SDF font for the text Hello World

To me, in that moment, Troika seemed like the obvious choice. That was until I tried to add it to my WebGPU project and it didn't work...

Troika didn't support WebGPU (at the time).

Efficient font rendering with WebGPU

Three.js's Font Geometry works with WebGPU. But after seeing how much of a step-up Troika text was I couldn't settle for going back to that.

So I did some more searching and eventually came across a small package, three-msdf-text-utils, by Léo Mouraire.

This package was exactly what I was looking for! It used MSDF fonts (an improved version of SDF using all three color channels to encode distance information), and included a TSL implementation of the shader material so that it worked with WebGPU.

There was a few little quirks with the package, but these were things I could help fix. It was ideal. Thank you Léo!

Comparing an SDF atlas to a MSDF atlas for the same font

Creating a package for synchronising with the DOM

The use case I wanted out of the text rendering was to be able to sync up text in the Three.js scene with text elements in the DOM. This could allow seamless pass over between the DOM and canvas, allowing for animations which would only be possible in a 3D scene to apply to something which looks like a 2D site.

Syncing with the DOM would also mean our 3D content is parsable by accessibility tools such as screen readers; an added bonus!

The three-msdf-text-utils was a great starting point for me in achieving this but lacked a couple of helpful features which would help me. These being:

  1. - Generating the text from a HTML element.
  2. - Geometry with an anchor point at the top-left.
  3. - Typescript support built into the package.

I created a fork of the package and made three-msdf-text-webgpu which includes all of these features above.

Examples with three-msdf-text-webgpu

By creating TSL shaders and applying them to the text material we can make some cool effects that wouldn't easily be made with CSS alone:

Rainbow Wave
Boiling Lines
Spinning Words

These are just some quick examples I put together so this is by no means the limit with what you can make by combining TSL with text.

Rendering the text in 3D also gives us the option to play with how the camera is positioned relative to the page content.

Outro

This whole blog has been created using the text geometry from the three-msdf-text-webgpu package, and hopefully this will highlight the potential uses of rendering and syncing text with the DOM.

The blog isn't perfect, syncronising is not the best between DOM and canvas elements while scrolling on lower end devices, but in practice I imagine you would take a different approach.

Overall, I really enjoyed learning all about font rendering and I'm happy I managed to get working package out which I can share.

If you are interested, please check out the three-msdf-text-webgpu package and let me know of what you create using it! Thanks again to Léo Mouraire for his three-msdf-text-utils package, and thank you for reading this blog.

Made by Tom MadeWithDove logo