What is the performant way to render a big amount of static text

Hello everyone. For the project i’m working on, i have to create a ruler, that shows pixel dimensions of the screen.
I’m working with a screen space coordinates, instead of clip space.
Project is in 2D, and is using Orthographic camera. At zoom equals to 1 of camera, my scene dimensions match screen pixels.

const camera = new OrthographicCamera(
      -canvas.clientWidth / 2,
      canvas.clientWidth / 2,
      canvas.clientHeight / 2,
      -canvas.clientHeight / 2,

Ruler should react on the position and zoom of the camera. And the whole scene varies in the range of -65 000 to + 65 000 pixels. User can drag through the scene. For the ruler it means that marks on it would be displayed with a certain step. But this step can vary not only when we are moving into another place of the scene, but also zoom. Will try to illustrate with pictures :

  1. I’m starting at the center with the zoom 1, and my step in ruler is 10 pixels. So from the beggining, depenidng on the dimensions of the screen, user would have the range from let’s say -1000 to 0, and from 0 to 1000 pixels in x axis.

  2. Later user can navigate to another place on the scene and zoom in, thus marks of the ruler are going to be shifted and reflect the scaling of the scene, making the step between marks smaller.

Ruler should be able to generate values on the fly. And there would be a lot of them. Because digits on the ruler can be changed almost to any values, due to zooming, and translating camera.

Was thinking about two ways. First one to use font geometry. Second one - textures.
The first approach that I’ve tried, was to generate font geometry using FontLoader. It is working perfectly. Easy to create, and place geometry. But when I’m trying to create all numbers with a step of 10px from -6500px to +65000px, and place them it takes some time.

Second approach that was thinking about, is to create font geometry on the fly, and put them at the ruler while person drags and moves camera, or zooms it. However, i guess, even if it would work more or less smoothly, it would be a quite a bit of a load. And i can’t create geometry ahead, because the marks on the ruler are changing dynamically, and to cover it i would have to create thousands of font geometries.
While it’s a simple ruler, that supposed to play a role of a helping tool in the application.

Also thought about using InstancedMesh, creating let’s say 100 instances of each digit from 0 to 9, and taking them from the “pool” of Instanced digits, positioning them accordingly next to other digits, depending which number app is supposed to display on the ruler. And use it for each digit, in each number. What can also be quite expensive, and also i don’t know about font positioning, because it seems not that easy to place each digit next to another one, with a predefined offset. Because in fonts different digits, or symbols, are having different offsets.

Haven’t done anything with textures so far, trying to wrap head around. But from the get go, it seems as it can be really cheap and performant way of implementing the functionality the app needs. What i have to do, is t create a Sprite Sheet. of ruler coordinates. As the images above. So i would have plane

const plane = new PlaneGeometry(130000, 50);

and map chunks of the spirte sheet accordingly to UV coordinates. Not sure if it’s available to do with three tools, but my guess is it’s as least possible to write a custom shader. Had a small experience with textures in OpenGl, so for now it seems quite possible. Excuse me for my ignorance, in case I’m wrong.
But with this approach there is one drawback. It would work well, if zoom of camera is pretty low. It’s not that hard to build SpriteSheet when it ranges from 0 to 65000px and 1000px fit the screen.
It would mean 65 samples of my ruler, as pictures above for positive x values, and the same amount for negative.
Even if it’s a lot of textures to make, seems that it would be more performant than font geometries.
But when zoom level would reach values of 128, or 256 ( which is max value in the app), i won’t be able to create any texture maps for that. Because marks on the ruler would range from -3 to + 3, and there should be 130 000 of them.

If somebody read till here want to apologize. A lot of text, and it isn’t structured very well. My language skills are quite poor.
Maybe somebody has any ideas how to implement this functionality. What would be the most performant way of doing it. Thank you.


You might find the linked code (and related bits) useful. It creates a texture atlas of a font and then uses instanced meshes and a custom shader to display correctly placed strings (in screen space, so they do not scale with zooming) - it handles character spacing too. The geometries are cached so that instances of the same string use shared geometries but different scene objects to position them (my use case has a lot of repeated small strings).

1 Like

SDF-based fonts would be an improvement on both TextGeometry and canvas-based text in most 3D cases:


If the text doesn’t need to be in 3D space (maybe I missed this in the OP?) then you could also consider just HTML/CSS, which is optimized well by the browser. :slight_smile: