maplibre / maplibre-gl-js

MapLibre GL JS - Interactive vector tile maps in the browser
https://maplibre.org/maplibre-gl-js/docs/
Other
6.42k stars 692 forks source link

Improve accuracy of CJK glyphs with higher resolution TinySDF textures #2990

Closed bdon closed 12 months ago

bdon commented 1 year ago

User Story

As a viewer of the map in Chinese or Japanese language, the quality of rendered text should look as good as Latin text and other scripts.

Rationale

font size

tinySDF = entry.tinySDF = new GlyphManager.TinySDF({
              fontSize: 24,
              buffer: 3,
              radius: 8,
              cutoff: 0.25,
              fontFamily,
              fontWeight
          });

Because TinySDF takes any font size as a parameter, we can increase the rendering resolution; most obvious would be doubling it to 48pt instead of 24. You can see the difference on the mapbox/TinySDF demo page (BSD).

Screenshot 2023-08-16 at 12 22 18 Screenshot 2023-08-16 at 12 22 36
float fontScale = u_is_text ? size / 24.0 : size;

https://github.com/maplibre/maplibre-gl-js/issues/1051 https://github.com/maplibre/maplibre-gl-js/issues/1002 https://github.com/maplibre/maplibre-style-spec/discussions/174

Impact

Alternatives

[^1]: Note the display of U+FA10 塚 may look unusual, this is my browser's locale setting and is not relevant to this issue.

HarelM commented 1 year ago

Generally speaking, and this is only my personal opinion, increasing to 48 feels like a patch and not a real solution, I would prefer to have solution that really solves this problem, preferably even one that allows using regular font files instead of this pre-generated glyphs. Again, my personal opinion.

bdon commented 1 year ago

@HarelM sure, I agree at a high level a solution that does not pre-rendered SDFs is better, for example:

But even if you have a non-pregenerated glyph solution, the rendering and WebGL components of MapLibre will always need to deal with signed distance fields. Any move away from SDFs would have a major impact on the user experience and styling capabilities of MapLibre. So an enhancement to the SDF pipeline for higher res textures is complementary to the solution you mentioned, not an alternative.

Other hardware-accelerated text display systems like video games use SDFs, but they can load fonts on disk and have higher VRAM budgets, so are not subject to the same constraints. A reasonable alternative to this proposal is to keep 24pt fonts but use multi-channel SDFs:

https://github.com/Chlumsky/msdfgen (MIT license) https://github.com/heremaps/harp.gl/tree/master/%40here/harp-text-canvas HarpGL map renderer (Apache License)

I think moving all of MapLibre to MSDFs is viable, but it would also require re-generating all font stacks, would triple the TinySDF cost and triple VRAM usage even if all glyph textures in the atlas are 24pt - you'd then need red, green and blue channels.

ChrisLoer commented 1 year ago

This is a great write-up @bdon! The Mapbox GL JS equivalent of this is one of the few things I worked on post-fork, so I think I need to stay a little bit at arms-length from this, but just to share a few bits of perspective from that effort:

wipfli commented 1 year ago

Thanks for this nice summary @bdon, I could not have written it better. Your proposal seems to be the right choice from my point of view. It is an incremental improvement of our text rendering stack and the risk of doing something wrong is very small.

bdon commented 1 year ago

I've made an interactive comparison of my branch vs maplibre 3.3.0:

https://bdon.github.io/maplibre-cjk/

Video:

https://github.com/maplibre/maplibre-gl-js/assets/77501/5de37a03-15a3-4595-84fb-e9865e8f2f03

It turns out this is easier than I expected to implement, without having to modify any shaders or vertex buffer layouts, only code that touches JavaScript. I haven't tested 100% of all cases or looked closely at the typographic metrics to make sure the spacing is the same between old and new code.

neodescis commented 1 year ago

Thanks for making a live demonstration. It is really eye-opening!

bdon commented 1 year ago

I've updated the demo to align the new glyphs pixel-perfect with the old ones, so visual styling should remain the same with a minor version bump. (At least on Apple devices, need to test others)

https://bdon.github.io/maplibre-cjk/

I've also fixed text-writing-mode: vertical cases.

Another comparison showing a particularly bad case that is fixed now:

https://github.com/maplibre/maplibre-gl-js/assets/77501/1af981ee-6461-4c28-8b1f-6b4a704ee928

HarelM commented 1 year ago

Looks great! Feel free to open a PR if you want the tests to run on every change. If this is a small increment towards a wider solution and improves the current situation without changing a lot of code, let's push it forward.

bdon commented 12 months ago

Released in 3.4.1