<p>I am working on a "CAD" like program in HTML5 that requires drawing many thousands (700,000+) of images on the screen. I think, "fortunately" the many images are replicated uses of a unique set of images. The unique set is many orders of magnitude less than the instances of them. One example I am working with has 700,000+ instances from a set of 360 unique images. The images are actually generated on the fly when the program first loads and they are rectangles with the "name" of the image centered about the middle of the rectangle (no color within the rectangle, etc... just a rectangle outline with the text in the middle, text and rectangle outline is black). The program should be able to display the images at many magnification levels, and of course, be fast enough for it to be useful.</p>

<p>A first implementation worked well with SVG images loaded. Due to the vector aspect of the images, it worked nicely at all magnifications. But after about 70,000 or so instances the program started to run out of memory. I assume because the DOM is not able to keep up with so many instances...</p>

<p>After a lot of studying and experimentation, I was able to implement a working version of the program using WebGL. It works pretty well, and it is fast. I know I will have to implement all the fun things I got from SVG for free, like CSS colors, listeners, individual elements in the DOM, etc, but I was not using a lot of that anyhow.</p>

<p>So far I've been able to implement a system that can render a lot of different instances of a subset of rectangles using a shape atlas with 1 texture and then using the standard technique of passing the texture coordinates to the pixel shader for rendering. This worked OK, except that the strings in the center of the atlas shape did not look too good at all magnifications. For the program to be most useful, I need to be able to display the strings clearly. Generating the rectangle atlases from a canvas 2d, even at high resolutions, with the strings as part of the atlas rectangles, while quite straight forward to do, did not seem to render well at all magnifications. I looked into generating string atlases by themselves, which is fine, but it seems to me that I should be able to create an image atlas that can display pretty well at a reasonable number of magnifications including the text, and perhaps save a bunch of unique draw calls for simply generating the text using Signed Distance Fields.</p>

<p>This is where I have hit a wall... I found a few places that reference the paper "Improved Alpha-Tested Magnification for Vector Textures and Special Effects". It seems exactly what I am looking for. I think of my unique set of rectangle, text pairs as "decals" as outlined in the paper above. In my case, I would have all my unique instances generate a lower resolution SDF version (64x64) of a high resolution version (2048x2048) of the instances and then change my fragment shader to be able to render at any resolution as outlined here -> Drawing Text with Signed Distance Fields in Mapbox GL. However, I have not found anywhere that shows how to generate a lower resolution version SDF from a high resolution image.</p>

<p>My questions are the following:</p>

<ol>
<li><p>How do I generate a lower resolution SDF version (64x64) of a hi-res image (2048x2048) generated on the fly using canvas and JavaScript so I can create a texture to use in my fragment shader? Ideally, this would only have to be generated once at the start of the program.</p></li>
<li><p>Am I thinking about his correctly? Is the text doomed to have to be drawn by itself separately using an SDF font atlas?</p></li>
</ol>

CC BY-SA 3.0
2017-02-21T04:13:14.657Z
For generating SDFs, you can brute force it doing something like: For every empty pixel, find the nearest 'solid' pixel by searching the entire bitmap (smallest distance wins). Not a cheap method but plenty of room of optimisation later. For downscaling you should be taking averages of distance over the area you are sampling from.
PaulHK
CC BY-SA 3.0
2017-02-21T04:55:55.473Z
Will using ctx.drawImage would work for the downscaling?
Jose
CC BY-SA 3.0
2017-02-21T07:10:51.820Z
Also, how do I normalize the distance representation into apha values
Jose
CC BY-SA 3.0
2017-02-21T07:16:01.577Z
If you are encoding as 8bit alpha you would normalise with something like    Alpha[n] = distField[n] * 255 / MaxDist;    were MaxDist is the largest distance in your field, this requires you to pass MaxDist as a uniform to your shader so it can unpack your alpha buffer properly. You could maybe get away with not not needing MaxDist if you have fixed texture dimensions. Ideally you should be using a floating point format though.
PaulHK
CC BY-SA 3.0
2017-02-22T18:03:20.280Z
Hi Paul, thank you for your answer. Can you elaborate on the downscaling?
Jose
<webgl><javascript>
Creating Signed Distance Fields Images On The Fly For WebGL Application
Jose
# Creating Signed Distance Fields Images On The Fly For WebGL Application

(Asked by: username_0 on 2017-02-21)

I am working on a "CAD" like program in HTML5 that requires drawing many thousands (700,000+) of images on the screen. I think, "fortunately" the many images are replicated uses of a unique set of images. The unique set is many orders of magnitude less than the instances of them. One example I am working with has 700,000+ instances from a set of 360 unique images. The images are actually generated on the fly when the program first loads and they are rectangles with the "name" of the image centered about the middle of the rectangle (no color within the rectangle, etc... just a rectangle outline with the text in the middle, text and rectangle outline is black). The program should be able to display the images at many magnification levels, and of course, be fast enough for it to be useful.

A first implementation worked well with SVG images loaded. Due to the vector aspect of the images, it worked nicely at all magnifications. But after about 70,000 or so instances the program started to run out of memory. I assume because the DOM is not able to keep up with so many instances...

After a lot of studying and experimentation, I was able to implement a working version of the program using WebGL. It works pretty well, and it is fast. I know I will have to implement all the fun things I got from SVG for free, like CSS colors, listeners, individual elements in the DOM, etc, but I was not using a lot of that anyhow.

So far I've been able to implement a system that can render a lot of different instances of a subset of rectangles using a shape atlas with 1 texture and then using the standard technique of passing the texture coordinates to the pixel shader for rendering. This worked OK, except that the strings in the center of the atlas shape did not look too good at all magnifications. For the program to be most useful, I need to be able to display the strings clearly. Generating the rectangle atlases from a canvas 2d, even at high resolutions, with the strings as part of the atlas rectangles, while quite straight forward to do, did not seem to render well at all magnifications. I looked into generating string atlases by themselves, which is fine, but it seems to me that I should be able to create an image atlas that can display pretty well at a reasonable number of magnifications including the text, and perhaps save a bunch of unique draw calls for simply generating the text using Signed Distance Fields.

This is where I have hit a wall... I found a few places that reference the paper "Improved Alpha-Tested Magnification for Vector Textures and Special Effects". It seems exactly what I am looking for. I think of my unique set of rectangle, text pairs as "decals" as outlined in the paper above. In my case, I would have all my unique instances generate a lower resolution SDF version (64x64) of a high resolution version (2048x2048) of the instances and then change my fragment shader to be able to render at any resolution as outlined here -> Drawing Text with Signed Distance Fields in Mapbox GL. However, I have not found anywhere that shows how to generate a lower resolution version SDF from a high resolution image.

My questions are the following:

1. How do I generate a lower resolution SDF version (64x64) of a hi-res image (2048x2048) generated on the fly using canvas and JavaScript so I can create a texture to use in my fragment shader? Ideally, this would only have to be generated once at the start of the program.
2. Am I thinking about his correctly? Is the text doomed to have to be drawn by itself separately using an SDF font atlas?

**Tags:** webgl, javascript

> **Comments:**
> **username_1**: For generating SDFs, you can brute force it doing something like: For every empty pixel, find the nearest 'solid' pixel by searching the entire bitmap (smallest distance wins). Not a cheap method but plenty of room of optimisation later. For downscaling you should be taking averages of distance over the area you are sampling from.  
> **username_0**: Will using ctx.drawImage would work for the downscaling?  
> **username_0**: Also, how do I normalize the distance representation into apha values  
> **username_1**: If you are encoding as 8bit alpha you would normalise with something like    Alpha[n] = distField[n] * 255 / MaxDist;    were MaxDist is the largest distance in your field, this requires you to pass MaxDist as a uniform to your shader so it can unpack your alpha buffer properly. You could maybe get away with not not needing MaxDist if you have fixed texture dimensions. Ideally you should be using a floating point format though.  
> **username_0**: Hi Paul, thank you for your answer. Can you elaborate on the downscaling?  

---

## 0 answers

