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

Blending (aka composition operations)

Open AbelVM opened this issue 4 years ago • 18 comments

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

References:

  • The stalled issue at Mapbox repo: https://github.com/mapbox/mapbox-gl-js/issues/6818
  • LumaGL (used by DeckGL, Kepler, Unfolded...) has some interesting functionalities that might help accomplish this https://luma.gl/docs/api-reference/gltools/parameter-setting#blending

AbelVM avatar Dec 28 '20 21:12 AbelVM

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

kylebarron avatar Dec 28 '20 22:12 kylebarron

That was my point, indeed :slightly_smiling_face:

AbelVM avatar Dec 28 '20 22:12 AbelVM

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

snickell avatar Feb 12 '21 12:02 snickell

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

AbelVM avatar Feb 12 '21 21:02 AbelVM

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.

github-actions[bot] avatar Nov 03 '21 01:11 github-actions[bot]

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.

AbelVM avatar Nov 08 '21 11:11 AbelVM

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.

github-actions[bot] avatar May 08 '22 02:05 github-actions[bot]

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:

  • http://www.pegtop.net/delphi/articles/blendmodes/
  • https://delphic.me.uk/tutorials/webgl-alpha
  • https://mrdoob.github.io/webgl-blendfunctions/blendfunc.html
  • https://www.andersriggelsen.dk/glblendfunc.php
  • https://developer.nvidia.com/content/alpha-blending-pre-or-not-pre

AbelVM avatar May 12 '22 07:05 AbelVM

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).

HarelM avatar May 12 '22 08:05 HarelM

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

  • http://www.nutty.ca/articles/blend_modes/
  • https://github.com/jamieowen/glsl-blend

AbelVM avatar May 12 '22 09:05 AbelVM

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 :-(

HarelM avatar May 12 '22 13:05 HarelM

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

AbelVM avatar May 12 '22 14:05 AbelVM

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.

xabbu42 avatar May 12 '22 14:05 xabbu42

I would love to see that feature implemented as well.

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

timbtimbtimb avatar Jan 10 '24 23:01 timbtimbtimb

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...

wipfli avatar Jan 11 '24 03:01 wipfli