maplibre-gl-js icon indicating copy to clipboard operation
maplibre-gl-js copied to clipboard

Multichannel signed distance fields proof-of-concept

Open wipfli opened this issue 1 year ago • 5 comments

This pull request aims to make a proof-of-concept version of MapLibre GL JS that uses multichannel signed distance fields rather than the normal signed distance fields. Related to #3705

You can try the status of the demo with:

npm run generate-shaders && npm run build-dev && npx serve --debug . -p 3000

In the browser you should see something like this:

image

This code should not be merged at the moment. It is just to share the status...

  • [x] Confirm your changes do not include backports from Mapbox projects (unless with compliant license) - if you are not sure about this, please ask!
  • [ ] Briefly describe the changes in this PR.
  • [ ] Link to related issues.
  • [ ] Include before/after visuals or gifs if this PR includes visual changes.
  • [ ] Write tests for all new functionality.
  • [ ] Document any changes to public APIs.
  • [ ] Post benchmark scores.
  • [ ] Add an entry to CHANGELOG.md under the ## main section.

wipfli avatar Feb 15 '24 15:02 wipfli

The MSDF RGBAImage is taken from https://github.com/openglobus/openglobus

wipfli avatar Feb 15 '24 15:02 wipfli

@Zemledelec I tried to copy your code from openglobus in label.ts. Here in the fragment shader you have a separate outline pass:

https://github.com/openglobus/openglobus/blob/88c2a6356841e7111fbf012272fc0b930434834c/src/shaders/label.ts#L215-L230

And there is this division by length(dxdy).

Do you mind sharing what the outline pass does and what the sdfParams are?

wipfli avatar Feb 15 '24 15:02 wipfli

@Zemledelec I tried to copy your code from openglobus in label.ts. Here in the fragment shader you have a separate outline pass:

https://github.com/openglobus/openglobus/blob/88c2a6356841e7111fbf012272fc0b930434834c/src/shaders/label.ts#L215-L230

And there is this division by length(dxdy).

Do you mind sharing what the outline pass does and what the sdfParams are?

Here is a link where I call for sdfParams for each font: https://github.com/openglobus/openglobus/blob/88c2a6356841e7111fbf012272fc0b930434834c/src/entity/LabelHandler.ts#L255 Font is here: https://github.com/openglobus/openglobus/blob/88c2a6356841e7111fbf012272fc0b930434834c/src/utils/FontAtlas.ts#L168

protected _applyFontDataToAtlas(atlas: FontTextureAtlas, data: IFontParams, index: number = 0) {
        let chars = data.chars;

        atlas.height = data.common.scaleH;
        atlas.width = data.common.scaleW;
        atlas.gliphSize = data.info.size;
        atlas.distanceRange = data.distanceField.distanceRange;

        let w = atlas.width,
            h = atlas.height,
            s = atlas.gliphSize;

        this.sdfParamsArr[index * 4] = w;
        this.sdfParamsArr[index * 4 + 1] = h;
        this.sdfParamsArr[index * 4 + 2] = s;
        this.sdfParamsArr[index * 4 + 3] = atlas.distanceRange;
...

where: w, h - atlas texture size, (1024x1024 - default) s - glyph size, (32 - default) atlas.distanceRange - distance range parameter (8 - default)

, all parameters I get from a font atlas generated cmd such as: npx msdf-bmfont-xml --reuse -i .\charset.txt -m 1024,1024 -f json -o arial.png -s 32 -r 8 -p 1 -t msdf arial.ttf

For a better understanding here is a description: https://levelup.gitconnected.com/msdf-font-rendering-in-webgl-91ce192d2bec

All those parameters significantly impact how it looks in the picture.

In openglobus I make two passes, first for the outline, and second for the inner font, here is https://github.com/openglobus/openglobus/blob/88c2a6356841e7111fbf012272fc0b930434834c/src/entity/LabelHandler.ts#L293

P.S. For multiple frustums (openglobus case), it makes some visual artifacts for semi-transparent (which is the usual thing) labels.

Examples for outline: https://sandbox.openglobus.org/examples/fonts

Zemledelec avatar Feb 16 '24 16:02 Zemledelec

Thank you @Zemledelec for the detailed response!

wipfli avatar Feb 20 '24 12:02 wipfli

fwidth() probably requires gl.getExtension("OES_standard_derivatives");, see https://developer.mozilla.org/en-US/docs/Web/API/OES_standard_derivatives

wipfli avatar Feb 20 '24 12:02 wipfli

fwidth() probably requires gl.getExtension("OES_standard_derivatives");, see https://developer.mozilla.org/en-US/docs/Web/API/OES_standard_derivatives

OES_standard_derivatives is a webgl1-only, and i believe this feature is supported by default in webgl2 which we use in almost all cases. Unfortunately, we probably can't leverage it because we can't leverage webgl2 shaders until a graphics modularization of the gl js codebase happen (or webgl1 support is sunset)

birkskyum avatar Feb 28 '24 14:02 birkskyum

Right @birkskyum some functions that needed extensions in webgl 1 are included by default in webgl 2.

I updated the first post of this pull request and added a link to a demo. You can adjust the size of the letter "M" with a slider. Does not work on my Android mobile phone and don't know why yet. But looks nice on my laptop...

wipfli avatar Feb 29 '24 13:02 wipfli

Demo should work now. I forgot the @2x sprite assets

wipfli avatar Feb 29 '24 16:02 wipfli

I updated the fragment shader to now also support outlines and font weight.

wipfli avatar Mar 01 '24 16:03 wipfli

Added an ASCII covering font, so now we can use the demo tiles labels for the demo...

wipfli avatar Mar 02 '24 14:03 wipfli

Basic proof of concept seems to work. Closing this draft pull request...

wipfli avatar Mar 07 '24 14:03 wipfli