maplibre-gl-js
maplibre-gl-js copied to clipboard
Multichannel signed distance fields proof-of-concept
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:
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.
The MSDF RGBAImage is taken from https://github.com/openglobus/openglobus
@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?
@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
Thank you @Zemledelec for the detailed response!
fwidth()
probably requires gl.getExtension("OES_standard_derivatives");
, see https://developer.mozilla.org/en-US/docs/Web/API/OES_standard_derivatives
fwidth()
probably requiresgl.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)
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...
Demo should work now. I forgot the @2x sprite assets
I updated the fragment shader to now also support outlines and font weight.
Added an ASCII covering font, so now we can use the demo tiles labels for the demo...
Basic proof of concept seems to work. Closing this draft pull request...