Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WebGL / Add support for patterns in polygons and lines #15279

Merged
merged 11 commits into from Nov 6, 2023

Conversation

jahow
Copy link
Contributor

@jahow jahow commented Oct 28, 2023

This PR adds support for fill and stroke patterns using the following properties of the flat WebGL-specific style:

  • fill-pattern-src and fill-pattern-img
  • fill-pattern-offset, fill-pattern-offset-origin and fill-pattern-size
  • stroke-pattern-src and stroke-pattern-img
  • stroke-pattern-offset, stroke-pattern-offset-origin and stroke-pattern-size
  • stroke-pattern-spacing

These properties work the same way as the icon- properties, letting the user specify an image either as a path or an Image or Canvas instance; the offset properties let the user specify a image in a spritesheet.

I didn't reproduce the current API which accepts CanvasPattern and CanvasGradient because:

  • it is tailor-made for the Canvas2D API and has limitations for WebGL (a texture can be created out of it, but the dimensions are not known)
  • doesn't let the user pick a sprite in a spritesheet
  • is not serializable

Fill pattern

Fill patterns have an origin which can be [0,0] in case of vector layers, or the tile origin in case of vector tiles. Patterns are slightly upscaled/downscaled when zooming to match integer zoom levels:

Fill patterns are tinted by the fill color if specified.
Peek 28-10-2023 15-11
(note: I didn't touch the actual webgl vector example)

Stroke pattern

Stroke patterns are scaled to match the line width. They are tinted by the line color if specified. I also worked on fixing the distance computation along the line when applying an offset; before this PR, the computation was off and symbols were clearly not lining up at the joins. Now the symbols line up, although the interpolation the joins still needs work:

Before:
Peek 28-10-2023 15-16

After:
Peek 28-10-2023 15-15

Note: providing Canvas or Image for fill patterns, stroke patterns or icons is not supported anymore. Use data URLs or object URLs instead.

@github-actions
Copy link

📦 Preview the website for this branch here: https://deploy-preview-15279--ol-site.netlify.app/.

This is necessary for dashes/symbols to render correctly along the line
when an offset is applied.
To do this we need to store an additional information for each vertex:
the sum of the tangents of the join angles encountered so far. This will then
be multiplied by the current line offset in the vertex shader.

Did my best ASCII art to try and explain better what is going on in this part
of the code.
@ahocevar
Copy link
Member

Nice! It should be easy to add support for fill pattern images to the Canvas 2D renderer. Stroke patterns like this will be a bit harder to support in Canvas 2D, because they need to consider the segment angle, but doable.

Regarding the new style properties, I'm wondering if we could get along without fill-pattern-offset-origin and stroke-pattern-offset-origin, because I think we'll be moving towards sprite sheets provided to the layer or map, separate from the styles, and the benefit of specifying the origin is quite minor, compared to always assuming top-left. With separate sprite sheets, we can eventually remove all of these new properties and just have fill-pattern and stroke-pattern instead.

@mike-000
Copy link
Contributor

Fill is not working in the deploy preview on some setups when there is no feature detected
image
(also hit detection reports "Faroe Islands boreal grasslands" for every feature - but that is not caused by this PR as it also happens in main).

@jahow
Copy link
Contributor Author

jahow commented Oct 28, 2023

Nice! It should be easy to add support for fill pattern images to the Canvas 2D renderer. Stroke patterns like this will be a bit harder to support in Canvas 2D, because they need to consider the segment angle, but doable.

Good to hear, feature parity would be awesome.

Regarding the new style properties, I'm wondering if we could get along without fill-pattern-offset-origin and stroke-pattern-offset-origin, because I think we'll be moving towards sprite sheets provided to the layer or map, separate from the styles, and the benefit of specifying the origin is quite minor, compared to always assuming top-left. With separate sprite sheets, we can eventually remove all of these new properties and just have fill-pattern and stroke-pattern instead.

The offset-origin properties are definitely not essential, but I figured they might still be a useful feature, and they don't bring that much complexity. So I don't really have a strong opinion either way.

Fill is not working in the deploy preview on some setups when there is no feature detected

@mike-000 could you please tell me on which platform you witnessed this? Thanks a lot!!

@mike-000
Copy link
Contributor

One of the systems mentioned in #13367 (comment) where until now there were no problems with WebGL, only WebGL2. In this case Firefox is also affected. The same ANGLE backend change will fix Chrome and Edge, I am not sure what can be done for Firefox.

Results for https://webglreport.com/?v=1 with Chrome

default settings (with the issue)
image

and with Angle backend set to D3D11on12 in flags (no issue but slow)
image

@jahow
Copy link
Contributor Author

jahow commented Oct 29, 2023

Thanks @mike-000 I could reproduce the issue (false hit detection + missing fill) using an emulated win10 system running both FF and Chrome; it's not related to this PR though.

This looks like an ANGLE-related issue. I will look into this, see if there's anything that can be done on OL side.

@mike-000
Copy link
Contributor

mike-000 commented Oct 29, 2023

I have seen missing fill in the example in main as well now, so cannot be related to this PR. Both issues can also been seen in the deploy preview for #15121 so probably started with that. Chrome on Android also has the false hit detection issue.

* @property {ColorExpression} [fill-color] The fill color.
* @property {ColorExpression} [fill-color] Fill color.
* @property {string} [fill-pattern-src] Fill pattern image source URI. If `fill-color` is defined as well, it will be used to tint this image.
* @property {HTMLImageElement|HTMLCanvasElement} [fill-pattern-img] Fill pattern image object. Can be provided as an alternative to `fill-pattern-src`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Accepting an image here is at odds with the goal of parsing styles and preparing attribute buffers in a worker. But we could wait until we are doing that and then deal with this then.

Copy link
Contributor Author

@jahow jahow Oct 30, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Absolutely, and a procedurally-generated image could easily be made into an object URL that could then be read from a worker.

I really went with a conservative approach here and mimicked the existing icon properties (also true for the origin-offset properties which @ahocevar mentioned). But I'm considering removing the code path for Image objects entirely, as there's no point in introducing APIs which we know are not aligned with long-term goals anyway.

edit: I thought this was present in the flat style as well but it isn't; I'll get rid of Image support in WebGL styles in this PR then

* be functions and are made up of simple objects instead of classes.
* @module ol/style/literal
* WebGL style objects slightly differ from standard flat styles for certain properties
* @module ol/style/webgl
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Feels like we should work toward having a single place for these types. I think it would be preferable to have a single set of types and then to allow the implementations to differ (or be incomplete) rather than having two sets of types.

Copy link
Contributor Author

@jahow jahow Oct 30, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is definitely what I'm aiming for. Having a separate type for WebGL renderers is helpful to keep track of where we stand and what is the gap between the two style formats, but it's not a situation that we want to keep eternally.

There is still some work to close this gap though, mainly around the concept of rules; I plan on addressing this later on while optimizing the way features are filtered out before rendering in WebGL.

@tschaub
Copy link
Member

tschaub commented Oct 30, 2023

Really impressive work, @jahow. I only left a couple general comments that I'm curious to hear your thoughts on, but think this looks good to go.

A procedurally-generated image can either be turned into a data url or
object url and then fed to the corresponding `*-src` property
@jahow
Copy link
Contributor Author

jahow commented Oct 31, 2023

@tschaub I added a commit to remove all traces of -img properties (for icons, fill patterns and stroke patterns), thus bringing the webgl style closer to the flat one.

@mike-000
Copy link
Contributor

mike-000 commented Nov 1, 2023

The docs describe the action of fill-color/stroke-color on patterns as "to tint". As in #15290 was it intentional for this to affect the alpha of the pattern?

@jahow
Copy link
Contributor Author

jahow commented Nov 1, 2023

The docs describe the action of fill-color/stroke-color on patterns as "to tint". As in #15290 was it intentional for this to affect the alpha of the pattern?

Yes absolutely, being able to get a translucent pattern is one benefit of the "tinting" behavior. Maybe the doc could clarify that tinting means multiplying colors?

@mike-000
Copy link
Contributor

mike-000 commented Nov 2, 2023

@jahow That makes sense. Applying icon-color of [255, 0, 0, 0.25) in canvas currently has the same effect as [255, 191, 191, 1] (which is the result of applying [255, 0, 0, 0.25] over a white canvas) so [255, 191, 191, 1] should always be used to achieve that, and the bug is [255, 0, 0, 0.25] not multiplying correctly in canvas styles.

@mike-000
Copy link
Contributor

mike-000 commented Nov 5, 2023

Options to scale/resize patterns would be useful. For example the Esri feature style linked in #15095 (comment) (reproduced in https://codesandbox.io/s/vector-esri-forked-3ly3ry?file=/main.js) contains a data url for the icon pattern (which produces a 256 x 256 image) in the eastern-most polygon and specifies a smaller (64 pixel) width and height to be used in the pattern

This could be specified as

  'fill-pattern-src': 'data:' + symbol.contentType + ';base64,' + symbol.imageData,
  'fill-pattern-width': symbol.width,
  'fill-pattern-height': symbol.height,

but without support for that the data url would need be to be asynchronously loaded to an image, then scaled in canvas to produce another data url.

@jahow
Copy link
Contributor Author

jahow commented Nov 5, 2023

I agree @mike-000, but with the limited resources available we're trying to aim for supporting Mapbox Style features, and the spec does not offer any option for scaling fill patterns.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants