-
-
Notifications
You must be signed in to change notification settings - Fork 3k
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
Fix color style for WebGL tile layer #16075
Conversation
📦 Preview the website for this branch here: https://deploy-preview-16075--ol-site.netlify.app/. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for this PR @kikuchan, after trying it out a little locally I think it makes sense. I honestly can't remember why I added alpha premultiplication in the colorToGlsl
function back then, I mean it works but it seems way more straightforward to do this premultiplication on the final color in the shader.
I'm leaving a few comments that will hopefully make it simpler in the end, and then we can see if the rendering tests still pass! thanks!
src/ol/webgl/ShaderBuilder.js
Outdated
// this used to produce an alpha-premultiplied color from a texture | ||
vec4 samplePremultiplied(sampler2D sampler, vec2 texCoord) { | ||
vec4 color = texture2D(sampler, texCoord); | ||
return vec4(color.rgb * color.a, color.a); | ||
return premultiplyAlpha(texture2D(sampler, texCoord)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm wondering if we can just get rid of this samplePremultiplied
function altogether now
src/ol/webgl/ShaderBuilder.js
Outdated
@@ -112,9 +115,9 @@ export class ShaderBuilder { | |||
* @type {string} | |||
* @private | |||
*/ | |||
this.symbolColorExpression_ = colorToGlsl( | |||
this.symbolColorExpression_ = `premultiplyAlpha(${colorToGlsl( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think these should go in the final shader outputs in ShaderBuilder.js:
- for symbols:
@@ -582,7 +582,7 @@ void main(void) {
float c = cos(v_angle);
float s = sin(v_angle);
coordsPx = vec2(c * coordsPx.x - s * coordsPx.y, s * coordsPx.x + c * coordsPx.y);
- gl_FragColor = ${this.symbolColorExpression_};
+ gl_FragColor = premultiplyAlpha(${this.symbolColorExpression_});
if (u_hitDetection > 0) {
if (gl_FragColor.a < 0.05) { discard; };
gl_FragColor = v_prop_hitColor;
- for strokes:
@@ -846,7 +841,7 @@ void main(void) {
float currentLengthPx = max(0., min(dot(segmentTangent, startToPoint), segmentLength)) + v_distanceOffsetPx;
float currentRadiusPx = abs(dot(segmentNormal, startToPoint));
float currentRadiusRatio = dot(segmentNormal, startToPoint) * 2. / v_width;
- vec4 color = ${this.strokeColorExpression_} * u_globalAlpha;
+ vec4 color = ${this.strokeColorExpression_};
float capType = ${this.strokeCapExpression_};
float joinType = ${this.strokeJoinExpression_};
float segmentStartDistance = computeSegmentPointDistance(currentPoint, v_segmentStart, v_segmentEnd, v_width, v_angleStart, capType, joinType);
@@ -856,7 +851,7 @@ void main(void) {
max(segmentStartDistance, segmentEndDistance)
);
distance = max(distance, ${this.strokeDistanceFieldExpression_});
- gl_FragColor = color * smoothstep(0.5, -0.5, distance);
+ gl_FragColor = premultiplyAlpha(color) * smoothstep(0.5, -0.5, distance) * u_globalAlpha;
if (u_hitDetection > 0) {
if (gl_FragColor.a < 0.1) { discard; };
gl_FragColor = v_prop_hitColor;
- for fills:
@@ -954,7 +954,7 @@ void main(void) {
}
#endif
if (${this.discardExpression_}) { discard; }
- gl_FragColor = ${this.fillColorExpression_} * u_globalAlpha;
+ gl_FragColor = premultiplyAlpha(${this.fillColorExpression_}) * u_globalAlpha;
if (u_hitDetection > 0) {
if (gl_FragColor.a < 0.1) { discard; };
gl_FragColor = v_prop_hitColor;
This way premultiplyAlpha
doesn't have to be called in too many places.
Note: I've tried these changes locally but it still broke the rendering... maybe I'm missing something, but I feel like this should work somehow.
src/ol/webgl/ShaderBuilder.js
Outdated
@@ -150,9 +153,9 @@ export class ShaderBuilder { | |||
* @type {string} | |||
* @private | |||
*/ | |||
this.strokeColorExpression_ = colorToGlsl( | |||
this.strokeColorExpression_ = `premultiplyAlpha(${colorToGlsl( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same as above
src/ol/webgl/ShaderBuilder.js
Outdated
@@ -189,9 +192,9 @@ export class ShaderBuilder { | |||
* @type {string} | |||
* @private | |||
*/ | |||
this.fillColorExpression_ = colorToGlsl( | |||
this.fillColorExpression_ = `premultiplyAlpha(${colorToGlsl( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same as above
src/ol/webgl/styleparser.js
Outdated
@@ -304,21 +304,21 @@ function parseCircleProperties( | |||
// FILL COLOR | |||
let fillColor = null; | |||
if ('circle-fill-color' in style) { | |||
fillColor = expressionToGlsl( | |||
fillColor = `premultiplyAlpha(${expressionToGlsl( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can leave this call out, see my comments on ShaderBuilder
src/ol/webgl/styleparser.js
Outdated
@@ -422,21 +422,21 @@ function parseShapeProperties( | |||
// FILL COLOR | |||
let fillColor = null; | |||
if ('shape-fill-color' in style) { | |||
fillColor = expressionToGlsl( | |||
fillColor = `premultiplyAlpha(${expressionToGlsl( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same as above
src/ol/webgl/styleparser.js
Outdated
} | ||
|
||
// STROKE COLOR | ||
let strokeColor = null; | ||
if ('shape-stroke-color' in style) { | ||
strokeColor = expressionToGlsl( | ||
strokeColor = `premultiplyAlpha(${expressionToGlsl( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same as above
src/ol/webgl/styleparser.js
Outdated
@@ -506,7 +506,7 @@ function parseIconProperties( | |||
// COLOR | |||
let color = 'vec4(1.0)'; | |||
if ('icon-color' in style) { | |||
color = expressionToGlsl(fragContext, style['icon-color'], ColorType); | |||
color = `premultiplyAlpha(${expressionToGlsl(fragContext, style['icon-color'], ColorType)})`; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same as above
src/ol/webgl/styleparser.js
Outdated
@@ -628,7 +628,7 @@ function parseStrokeProperties( | |||
) { | |||
if ('stroke-color' in style) { | |||
builder.setStrokeColorExpression( | |||
expressionToGlsl(fragContext, style['stroke-color'], ColorType), | |||
`premultiplyAlpha(${expressionToGlsl(fragContext, style['stroke-color'], ColorType)})`, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same as above
src/ol/webgl/styleparser.js
Outdated
@@ -793,7 +793,7 @@ function parseFillProperties( | |||
) { | |||
if ('fill-color' in style) { | |||
builder.setFillColorExpression( | |||
expressionToGlsl(fragContext, style['fill-color'], ColorType), | |||
`premultiplyAlpha(${expressionToGlsl(fragContext, style['fill-color'], ColorType)})`, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same as above
acb49ae
to
bbdc6b6
Compare
Hi @jahow, thank you for your review and suggestions! Unfortunately, I tried rewriting the To address the issue of multiple of What are your thoughts on this approach? Thanks! |
Ok, I think there is a way to make the alpha premultiplication much less of a concern throughout the code. See my branch here: https://github.com/jahow/openlayers/tree/fix-webgl-color-style Alpha premultiplication is now only done at the end of each fragment shader. I kept all your changes throught the code to not multiply everything by alpha all the time, and also added some changes in the style parser to adapt the color expressions accordingly. The rendering tests pass, so it's a matter of adapting the unit tests now. What do you think? I feel like this would be the bast way forward. Thank you for your continued efforts! |
…iler to styleparser Co-authored-by: Olivia Guyot <olivia.guyot@camptocamp.com>
bbdc6b6
to
1faeae6
Compare
Oh! It surely works! It's great! I've sent a rebased and revised version. Thank you! |
@@ -580,6 +574,7 @@ void main(void) { | |||
float s = sin(v_angle); | |||
coordsPx = vec2(c * coordsPx.x - s * coordsPx.y, s * coordsPx.x + c * coordsPx.y); | |||
gl_FragColor = ${this.symbolColorExpression_}; | |||
gl_FragColor.rgb *= gl_FragColor.a; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BTW, currently u_globalAlpha
is not applied here. Is this OK for a symbol...?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, right, maybe that was missing. I think this should be done in another PR, I have the feeling this isn't tested anywhere
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That looks perfect, thank you for sticking to this!!
This PR moves alpha premultiplication from the WebGL expression compiler to
styleparser
.This change is necessary because alpha premultiplication strategies can differ between shaders.
The shader in
WebGLTileLayer
employs a lazy strategy, while the shader instyleparser
uses an eager strategy.Therefore, it is more appropriate to avoid applying alpha premultiplication within the
color
operator.Fixes #16074.