Let's solve pixelated SVG texture rendering in Three.js

Update: I significantly improved the rendering for DPRs of 1 by removing the minFilter setting from the CanvasTexture:

That is amazing. I hadn’t understood signed distance fields yet, but that simple and excellent video made it so obvious: the texture doesn’t have to be high res, but with the signed distance field, it can simply estimate (from a low res image) where the lines should be approximately, and a high-res image isn’t needed because there are enough pixels around to average from in the low res image to make a meaningful calculation. And even though he didn’t actual say that, it was so obvious. This should be the video everyone curious about SDF sees first. Wonderful!

With the technique I am using above, rendering to a canvas, I might, based on some heuristic, render a higher resolution to the canvas if an object gets closer to screen, but that is definitely less performant, and also not as simple.

Indeed it may be a deep rabbit hole to re-implement SVG features with SDF though. It would undoubtedly start off as a project with a subset of SVG features, then progress over time based on what features people ask for, whereas the less-performant solution of drawing to canvas with custom resolution is good for cases that don’t need to re-create the texture all the time (that’s the costly part) but desire the full featureset of SVG in their case.

Thanks for sharing that!

1 Like

You may not go down that rabbit hole after all, I just found a workaround, it’s a bit hacky but surprisingly effective, especially if you have lots of icons or SVG.

There is this excellent library troika-three-text that use the same SDF technique to render crisp edge text, if you take a look at this example you’ll see that it can be used to render material icons from this .woff font file.

Now you can generate your own custom icons or SVG font file (.woff or .ttf) using fontello or icomoon and use it as you would use any regular font file with the troika library.

2 Likes

@Fennec I have been doing exactly this recently :grin:

For the kind of svg icons that @trusktr linked at the top of this issue it’s perfect and I don’t think it’s hacky at all - this fancy “&” symbol is font, after all.

9ee09aa59cecac388f4b54364cf63b43066175d7_2_690x161

There’s two main issues I’ve found:

  1. Only one color supported by troika three text (I think?)
  2. You need to use an SVG designed for this, you can’t expect any SVG icon to work out of the box. I found fontello to work better than icomoon but in general you may have to rebuild existing SVGs to make them work
3 Likes

@looeee

I have been doing exactly this recently

Glad I’m not the only stubborn here, I think for @trusktr obsession is the right word :sweat_smile:

  1. Only one color supported by troika three text (I think?)

It’s experimental and not mentioned in the docs.

There is a warning flag in the jsDoc comments (didn’t test it).

/**
       * @member {object|null} colorRanges
       * WARNING: This API is experimental and may change.
       * This allows more fine-grained control of colors for individual or ranges of characters,
       * taking precedence over the material's `color`. Its format is an Object whose keys each
       * define a starting character index for a range, and whose values are the color for each
       * range. The color value can be a numeric hex color value, a `THREE.Color` object, or
       * any of the strings accepted by `THREE.Color`.
       */
      this.colorRanges = null

You need to use an SVG designed for this

Yeah copy/past won’t do here, I think you need to convert the SVG to a single path, center, resize and set the right viewbox, if you have lots of icons this can easily translate to hours of work. On the good side most icons libraries are prebuilt with this kind of constraints in mind.

2 Likes

Yeah but I think most icon libraries already provide font versions, so I expect this’ll be most useful with custom icons.

Regarding the colors, that’s really cool and I hadn’t seen it before. However I meant multiple colors in a single icon. I think that’s possible with fonts - they use one character per color and then draw the characters on top of each other to provide a multi-color font (I don’t know how the positioning is done, negative kerning maybe?).

Maybe that would work here if you set the range so that each section of the character is colored differently?

1 Like

In my case the object is a constant distance away from the camera, and only rotates a little. So drawing to canvas once (uploading texture only once) turned out to be a simple and good enough solution.

I do have another case (image viewer, jpg, png, svg, etc) where SDF won’t fit well (without some serious work)

All depends on the use case. :smile:

(But I’m loving this SDF stuff!)

2 Likes

I meant multiple colors in a single icon.

I mostly design web apps and always get away with simple flat icons, but for a 3D or Game UI I can easily see why you need multiple colors in a single icon, that’s a bit advance and problematic, may be it can be done with some tweaking on the Text Derived Material shaders or simply playing around the colorRanges param, didn’t test it and probably won’t, I guess I’m not that stubborn :sweat_smile:

All depends on the use case.

I agree, It would’ve been an overkill to implement an entire library just for one or two fixed SVG, the simplest solution can also be the most effective. It all depends on the use case :ok_hand:

1 Like

My use case is to create a text label where lines start with a custom icon followed by normal text.

These are some random icons I found on the internet but have a similar complexity to the ones I am using - each has just two or three colors (for me, just two colors would be enough).

Currently I am using each icon as a texture on a plane followed by a Troika text element. This works ok but I have to take a lot of care to position the icon correctly and also worry about z-fighting and so on. That’s why I tried converting the SVG icons to a font, it makes positioning them easy but I lose color.

I’d also have to rebuild the icons but if I could get the colors to work it would be worth doing that, I only have three icons to deal with currently.

1 Like