maplibre / maplibre-gl-js

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

Blending (aka composition operations) #48

Open AbelVM opened 3 years ago

AbelVM commented 3 years ago

To enable per-layer o per-feature blending modes as multiply, lighten, darken and so on.

References:

kylebarron commented 3 years ago

luma.gl mainly wraps the WebGL API. All of those blending functions are available in the pure WebGL api. Mapbox GL JS uses the WebGL API directly, so it might make sense to look at some of luma.gl's internals, but probably not to add a dependency from maplibre-gl-js on luma.gl

AbelVM commented 3 years ago

That was my point, indeed :slightly_smiling_face:

snickell commented 3 years ago

This would be super cool to have, @AbelVM maybe you'd like to put together a proposal on this?

AbelVM commented 3 years ago

The target would be to bring to MapLibre layer and feature composition, allowing feature-feature and/or layer-layer blending modes like multiply, add, overlay, lighten, darken, etc. As described in this ancient CartoCSS tutorial (bringing back CartoCSS support too might be an awesome feature, indeed). Current transparency management does not fulfill the requirements. This feature might boost not only the current cartographic design capabilities but also add /extend new ones as proper hill shading or better management of 3D objects and perspective (v.g.: buildings vs. labels or roads).

This might be a complex task as it involves playing with the shades and low-level WebGL stuff (I have zero experience in raw WebGL, so there's little I can help there)

The path that leads to this feature might start by bringing back composite layers that were removed in 2014 due to performance degradation, and this PR should do the final trick. BUT (big, bold, uppercase "but") all that code, tickets, PRs, and so on are related to MapBox v0.1.0, so ancient history. So, maybe a full rework on the shaders side (Glii style) might be needed... but that looks like an overwhelming task at this stage of MapLibre as that code region of MapBoxGL is plain huge as far as I remember

github-actions[bot] commented 2 years ago

This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 7 days.

AbelVM commented 2 years ago

Hi, I've found this library, Lygia, that has all the wrappers for easily implement color blending functionality here https://github.com/patriciogonzalezvivo/lygia/tree/main/color/blend.

I really don't know whether that library might help or not, but it has made me come to this issue to bring it back to life. I (still) think this might be an awesome core feature to add to this project. 2014 is way back in the past, and I'm quite sure that composition won't hurt performance that hard... and the trade-offs would be great (not only in 2D but also on 3D occlusion effects).

I think we should keep this issue alive. My two cents.

github-actions[bot] commented 2 years ago

This issue is stale because it has been open 180 days with no activity. Remove stale label or comment or this will be closed in 30 days.

AbelVM commented 2 years ago

https://github.com/maplibre/maplibre-gl-js/pull/1191 tells it's feasible to add composition/blending to layers and/or features, so

As per http://www.pegtop.net/delphi/articles/blendmodes/, using gl.blendFunc

multiply    a * b
screen  1 - (1 - a) * (1 - b)
darken  min(a, b)
lighten     max(a, b)
difference  abs(a - b)
negation    1 - abs(1 - a - b)
exclusion   a + b - 2 * a * b
overlay     a < .5 ? (2 * a * b) : (1 - 2 * (1 - a) * (1 - b))
hard light  b < .5 ? (2 * a * b) : (1 - 2 * (1 - a) * (1 - b))
soft light  b < .5 ? (2 * a * b + a * a * (1 - 2 * b)) : (sqrt(a) * (2 * b - 1) + (2 * a) * (1 - b))
dodge   a / (1 - b)
burn    1 - (1 - a) / b

(multiply would be something like gl.blendFunc(GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA))

Refs:

HarelM commented 2 years ago

I'm finding it hard to map between the current functionality (opacity is basically stacked), the new feature of fill opacity per geometry and these formulas. Can you map at least the existing two to these formulas? This will help me better understand the relations and how to properly name the new style-spec property (hopefully).

AbelVM commented 2 years ago

Some resources with source code and explanations that might help :sweat_smile:

HarelM commented 2 years ago

I've read through both and it didn't help much unfortunately :-( While I understand the concept of blending, I don't see how it correlates to the code that was changed and the code that exits :-(

AbelVM commented 2 years ago

In https://github.com/maplibre/maplibre-gl-js/pull/1191#issuecomment-1120247425, it's described how an additive blending is applied, just with just gl.blendFunc(gl.ONE, gl.ZERO); (in the right place). So, my point is that if and additive blending is feasible, then maybe we can just add some other blending modes just playing with the parameters of blendFunc() as described in the references above. This way, potentially, we might add some blending modes to MapLibre styling just reusing @tongust work

xabbu42 commented 2 years ago

That comment is about blending the individual features of a layer together, not blending the layer on the map which is still alpha-blending. So perhaps the pull request and this issue are less connected than I initially thought.

timbtimbtimb commented 7 months ago

I would love to see that feature implemented as well.

Here is my usecase, using Leaflet and CSS mix-blend-mode

wipfli commented 7 months ago

I played around with blending the other day because I wanted to get something like the multiply operation to blend hillshade and forests like the swisstopo raster maps do. But I did not understand how to use the OpenGL blend modes to do something like this...

timbtimbtimb commented 2 months ago

Any news on this?

wiesehahn commented 2 months ago

Any news on this?

Just saw it was added to the bounties last year https://github.com/maplibre/maplibre/issues/269

msbarry commented 1 month ago

Updated luma.gl link from the original issue description: https://luma.gl/docs/api-reference/core/parameters#blending