diff --git a/include/mbgl/shaders/gl/symbol_sdf.hpp b/include/mbgl/shaders/gl/symbol_sdf.hpp index 1329676bd..23a039491 100644 --- a/include/mbgl/shaders/gl/symbol_sdf.hpp +++ b/include/mbgl/shaders/gl/symbol_sdf.hpp @@ -279,16 +279,22 @@ lowp float halo_blur = u_halo_blur; lowp vec4 color = fill_color; highp float gamma = EDGE_GAMMA / (fontScale * u_gamma_scale); - lowp float buff = (256.0 - 64.0) / 256.0; + lowp float inner_edge = (256.0 - 64.0) / 256.0; if (u_is_halo) { color = halo_color; gamma = (halo_blur * 1.19 / SDF_PX + EDGE_GAMMA) / (fontScale * u_gamma_scale); - buff = (6.0 - halo_width / fontScale) / SDF_PX; + inner_edge = inner_edge + gamma * gamma_scale; } lowp float dist = texture(u_texture, tex).a; highp float gamma_scaled = gamma * gamma_scale; - highp float alpha = smoothstep(buff - gamma_scaled, buff + gamma_scaled, dist); + highp float alpha = smoothstep(inner_edge - gamma_scaled, inner_edge + gamma_scaled, dist); + if (u_is_halo) { + // When drawing halos, we want the inside of the halo to be transparent as well + // in case the text fill is transparent. + lowp float halo_edge = (6.0 - halo_width / fontScale) / SDF_PX; + alpha = min(smoothstep(halo_edge - gamma_scaled, halo_edge + gamma_scaled, dist), 1.0 - alpha); + } fragColor = color * (alpha * opacity * fade_opacity); diff --git a/include/mbgl/shaders/gl/symbol_text_and_icon.hpp b/include/mbgl/shaders/gl/symbol_text_and_icon.hpp index 4b55116f1..39fc1906b 100644 --- a/include/mbgl/shaders/gl/symbol_text_and_icon.hpp +++ b/include/mbgl/shaders/gl/symbol_text_and_icon.hpp @@ -296,16 +296,22 @@ lowp float halo_blur = u_halo_blur; lowp vec4 color = fill_color; highp float gamma = EDGE_GAMMA / (fontScale * u_gamma_scale); - lowp float buff = (256.0 - 64.0) / 256.0; + lowp float inner_edge = (256.0 - 64.0) / 256.0; if (u_is_halo) { color = halo_color; gamma = (halo_blur * 1.19 / SDF_PX + EDGE_GAMMA) / (fontScale * u_gamma_scale); - buff = (6.0 - halo_width / fontScale) / SDF_PX; + inner_edge = inner_edge + gamma * gamma_scale; } lowp float dist = texture(u_texture, tex).a; highp float gamma_scaled = gamma * gamma_scale; - highp float alpha = smoothstep(buff - gamma_scaled, buff + gamma_scaled, dist); + highp float alpha = smoothstep(inner_edge - gamma_scaled, inner_edge + gamma_scaled, dist); + if (u_is_halo) { + // When drawing halos, we want the inside of the halo to be transparent as well + // in case the text fill is transparent. + lowp float halo_edge = (6.0 - halo_width / fontScale) / SDF_PX; + alpha = min(smoothstep(halo_edge - gamma_scaled, halo_edge + gamma_scaled, dist), 1.0 - alpha); + } fragColor = color * (alpha * opacity * fade_opacity); diff --git a/include/mbgl/shaders/mtl/symbol.hpp b/include/mbgl/shaders/mtl/symbol.hpp index fc6bdcb08..c4f22e667 100644 --- a/include/mbgl/shaders/mtl/symbol.hpp +++ b/include/mbgl/shaders/mtl/symbol.hpp @@ -437,12 +437,22 @@ half4 fragment fragmentMain(FragmentStage in [[stage_in]], const float EDGE_GAMMA = 0.105 / DEVICE_PIXEL_RATIO; const float fontGamma = in.fontScale * tileProps.gamma_scale; + const float fillGamma = EDGE_GAMMA / fontGamma; + const float haloGamma = (halo_blur * 1.19 / SDF_PX + EDGE_GAMMA) / fontGamma; + const float gamma = tileProps.is_halo ? haloGamma : fillGamma; + const float gammaScaled = gamma * in.gamma_scale; const half4 color = tileProps.is_halo ? halo_color : fill_color; - const float gamma = ((tileProps.is_halo ? (halo_blur * 1.19 / SDF_PX) : 0) + EDGE_GAMMA) / fontGamma; - const float buff = tileProps.is_halo ? (6.0 - halo_width / in.fontScale) / SDF_PX : (256.0 - 64.0) / 256.0; + const float fillInnerEdge = (256.0 - 64.0) / 256.0; + const float haloInnerEdge = fillInnerEdge + haloGamma * tileProps.gamma_scale; + const float innerEdge = tileProps.is_halo ? haloInnerEdge : fillInnerEdge; const float dist = image.sample(image_sampler, float2(in.tex)).a; - const float gamma_scaled = gamma * in.gamma_scale; - const float alpha = smoothstep(buff - gamma_scaled, buff + gamma_scaled, dist); + + float alpha = smoothstep(innerEdge - gammaScaled, innerEdge + gammaScaled, dist); + if (tileProps.is_halo) { + // When drawing halos, if the fill is translucent we want the inside of the halo to be translucent as well + const float haloEdge = (6.0 - halo_width / in.fontScale) / SDF_PX; + alpha = min(smoothstep(haloEdge - gammaScaled, haloEdge + gammaScaled, dist), 1.0 - alpha); + } return half4(color * (alpha * opacity * in.fade_opacity)); } @@ -673,13 +683,23 @@ half4 fragment fragmentMain(FragmentStage in [[stage_in]], } const float EDGE_GAMMA = 0.105 / DEVICE_PIXEL_RATIO; - const half4 color = tileProps.is_halo ? halo_color : fill_color; const float fontGamma = in.fontScale * tileProps.gamma_scale; - const float gamma = ((tileProps.is_halo ? (halo_blur * 1.19 / SDF_PX) : 0) + EDGE_GAMMA) / fontGamma; - const float buff = tileProps.is_halo ? (6.0 - halo_width / in.fontScale) / SDF_PX : (256.0 - 64.0) / 256.0; + const float fillGamma = EDGE_GAMMA / fontGamma; + const float haloGamma = (halo_blur * 1.19 / SDF_PX + EDGE_GAMMA) / fontGamma; + const float gamma = tileProps.is_halo ? haloGamma : fillGamma; + const float gammaScaled = gamma * in.gamma_scale; + const half4 color = tileProps.is_halo ? halo_color : fill_color; + const float fillInnerEdge = (256.0 - 64.0) / 256.0; + const float haloInnerEdge = fillInnerEdge + haloGamma * tileProps.gamma_scale; + const float innerEdge = tileProps.is_halo ? haloInnerEdge : fillInnerEdge; const float dist = glyph_image.sample(glyph_sampler, float2(in.tex)).a; - const float gamma_scaled = gamma * in.gamma_scale; - const float alpha = smoothstep(buff - gamma_scaled, buff + gamma_scaled, dist); + + float alpha = smoothstep(innerEdge - gammaScaled, innerEdge + gammaScaled, dist); + if (tileProps.is_halo) { + // When drawing halos, if the fill is translucent we want the inside of the halo to be translucent as well + const float haloEdge = (6.0 - halo_width / in.fontScale) / SDF_PX; + alpha = min(smoothstep(haloEdge - gammaScaled, haloEdge + gammaScaled, dist), 1.0 - alpha); + } return half4(color * (alpha * opacity * in.fade_opacity)); } diff --git a/include/mbgl/shaders/vulkan/symbol.hpp b/include/mbgl/shaders/vulkan/symbol.hpp index 31664b14f..96edd885d 100644 --- a/include/mbgl/shaders/vulkan/symbol.hpp +++ b/include/mbgl/shaders/vulkan/symbol.hpp @@ -485,12 +485,22 @@ void main() { const float EDGE_GAMMA = 0.105 / DEVICE_PIXEL_RATIO; const float fontGamma = frag_font_scale * tileProps.gamma_scale; + const float fillGamma = EDGE_GAMMA / fontGamma; + const float haloGamma = (halo_blur * 1.19 / SDF_PX + EDGE_GAMMA) / fontGamma; + const float gamma = tileProps.is_halo ? haloGamma : fillGamma; + const float gammaScaled = gamma * frag_gamma_scale; const vec4 color = tileProps.is_halo ? halo_color : fill_color; - const float gamma = ((tileProps.is_halo ? (halo_blur * 1.19 / SDF_PX) : 0) + EDGE_GAMMA) / fontGamma; - const float buff = tileProps.is_halo ? (6.0 - halo_width / frag_font_scale) / SDF_PX : (256.0 - 64.0) / 256.0; + const float fillInnerEdge = (256.0 - 64.0) / 256.0; + const float haloInnerEdge = fillInnerEdge + haloGamma * frag_gamma_scale; + const float innerEdge = tileProps.is_halo ? haloInnerEdge : fillInnerEdge; const float dist = texture(image0_sampler, frag_tex).a; - const float gamma_scaled = gamma * frag_gamma_scale; - const float alpha = smoothstep(buff - gamma_scaled, buff + gamma_scaled, dist); + float alpha = smoothstep(innerEdge - gammaScaled, innerEdge + gammaScaled, dist); + if (tileProps.is_halo) { + // When drawing halos, if the fill is translucent we want + // the inside of the halo to be translucent as well + const float haloEdge = (6.0 - halo_width / frag_font_scale) / SDF_PX; + alpha = min(smoothstep(haloEdge - gammaScaled, haloEdge + gammaScaled, dist), 1.0 - alpha); + } out_color = color * (alpha * opacity * frag_fade_opacity); } @@ -795,12 +805,22 @@ void main() { const float EDGE_GAMMA = 0.105 / DEVICE_PIXEL_RATIO; const float fontGamma = frag_font_scale * tileProps.gamma_scale; + const float fillGamma = EDGE_GAMMA / fontGamma; + const float haloGamma = (halo_blur * 1.19 / SDF_PX + EDGE_GAMMA) / fontGamma; + const float gamma = tileProps.is_halo ? haloGamma : fillGamma; + const float gammaScaled = gamma * frag_gamma_scale; const vec4 color = tileProps.is_halo ? halo_color : fill_color; - const float gamma = ((tileProps.is_halo ? (halo_blur * 1.19 / SDF_PX) : 0) + EDGE_GAMMA) / fontGamma; - const float buff = tileProps.is_halo ? (6.0 - halo_width / frag_font_scale) / SDF_PX : (256.0 - 64.0) / 256.0; + const float fillInnerEdge = (256.0 - 64.0) / 256.0; + const float haloInnerEdge = fillInnerEdge + haloGamma * frag_gamma_scale; + const float innerEdge = tileProps.is_halo ? haloInnerEdge : fillInnerEdge; const float dist = texture(glyph_image, frag_tex).a; - const float gamma_scaled = gamma * frag_gamma_scale; - const float alpha = smoothstep(buff - gamma_scaled, buff + gamma_scaled, dist); + float alpha = smoothstep(innerEdge - gammaScaled, innerEdge + gammaScaled, dist); + if (tileProps.is_halo) { + // When drawing halos, if the fill is translucent we want + // the inside of the halo to be translucent as well + const float haloEdge = (6.0 - halo_width / frag_font_scale) / SDF_PX; + alpha = min(smoothstep(haloEdge - gammaScaled, haloEdge + gammaScaled, dist), 1.0 - alpha); + } out_color = color * (alpha * opacity * frag_fade_opacity); } diff --git a/metrics/integration/render-tests/icon-halo-color/opacity/expected.png b/metrics/integration/render-tests/icon-halo-color/opacity/expected.png index bc661748c..2e5b22d66 100644 Binary files a/metrics/integration/render-tests/icon-halo-color/opacity/expected.png and b/metrics/integration/render-tests/icon-halo-color/opacity/expected.png differ diff --git a/metrics/integration/render-tests/text-color/translucent-icon/expected.png b/metrics/integration/render-tests/text-color/translucent-icon/expected.png new file mode 100644 index 000000000..fefe70dfa Binary files /dev/null and b/metrics/integration/render-tests/text-color/translucent-icon/expected.png differ diff --git a/metrics/integration/render-tests/text-color/translucent-icon/style.json b/metrics/integration/render-tests/text-color/translucent-icon/style.json new file mode 100644 index 000000000..cfb5e9261 --- /dev/null +++ b/metrics/integration/render-tests/text-color/translucent-icon/style.json @@ -0,0 +1,61 @@ +{ + "version": 8, + "metadata": { + "test": { + "height": 256 + } + }, + "center": [ + 13.418056, + 52.499167 + ], + "zoom": 14, + "sources": { + "mapbox": { + "type": "vector", + "maxzoom": 14, + "tiles": [ + "local://tiles/{z}-{x}-{y}.mvt" + ] + } + }, + "glyphs": "local://glyphs/{fontstack}/{range}.pbf", + "sprite": "local://sprites/emerald@2x", + "layers": [ + { + "id": "background", + "type": "background", + "paint": { + "background-color": "white" + } + }, + { + "id": "text", + "type": "symbol", + "source": "mapbox", + "source-layer": "poi_label", + "filter": [ + "==", + "maki", + "restaurant" + ], + "layout": { + "symbol-placement": "point", + "text-allow-overlap": true, + "text-ignore-placement": true, + "text-field": ["format", "Test", ["image", "rer"]], + "text-size": 32, + "text-font": [ + "Open Sans Semibold", + "Arial Unicode MS Bold" + ] + }, + "paint": { + "text-color": "blue", + "text-halo-color": "yellow", + "text-halo-width": 2, + "text-opacity": 0.5 + } + } + ] +} diff --git a/metrics/integration/render-tests/text-color/translucent/expected.png b/metrics/integration/render-tests/text-color/translucent/expected.png new file mode 100644 index 000000000..712432273 Binary files /dev/null and b/metrics/integration/render-tests/text-color/translucent/expected.png differ diff --git a/metrics/integration/render-tests/text-color/translucent/style.json b/metrics/integration/render-tests/text-color/translucent/style.json new file mode 100644 index 000000000..cfe21526e --- /dev/null +++ b/metrics/integration/render-tests/text-color/translucent/style.json @@ -0,0 +1,60 @@ +{ + "version": 8, + "metadata": { + "test": { + "height": 256 + } + }, + "center": [ + 13.418056, + 52.499167 + ], + "zoom": 14, + "sources": { + "mapbox": { + "type": "vector", + "maxzoom": 14, + "tiles": [ + "local://tiles/{z}-{x}-{y}.mvt" + ] + } + }, + "glyphs": "local://glyphs/{fontstack}/{range}.pbf", + "layers": [ + { + "id": "background", + "type": "background", + "paint": { + "background-color": "white" + } + }, + { + "id": "text", + "type": "symbol", + "source": "mapbox", + "source-layer": "poi_label", + "filter": [ + "==", + "maki", + "restaurant" + ], + "layout": { + "symbol-placement": "point", + "text-allow-overlap": true, + "text-ignore-placement": true, + "text-field": "Test", + "text-size": 32, + "text-font": [ + "Open Sans Semibold", + "Arial Unicode MS Bold" + ] + }, + "paint": { + "text-color": "blue", + "text-halo-color": "yellow", + "text-halo-width": 2, + "text-opacity": 0.5 + } + } + ] +} diff --git a/metrics/integration/render-tests/text-color/transparent/expected.png b/metrics/integration/render-tests/text-color/transparent/expected.png new file mode 100644 index 000000000..83ca4a4d8 Binary files /dev/null and b/metrics/integration/render-tests/text-color/transparent/expected.png differ diff --git a/metrics/integration/render-tests/text-color/transparent/style.json b/metrics/integration/render-tests/text-color/transparent/style.json new file mode 100644 index 000000000..0f3853b44 --- /dev/null +++ b/metrics/integration/render-tests/text-color/transparent/style.json @@ -0,0 +1,59 @@ +{ + "version": 8, + "metadata": { + "test": { + "height": 256 + } + }, + "center": [ + 13.418056, + 52.499167 + ], + "zoom": 14, + "sources": { + "mapbox": { + "type": "vector", + "maxzoom": 14, + "tiles": [ + "local://tiles/{z}-{x}-{y}.mvt" + ] + } + }, + "glyphs": "local://glyphs/{fontstack}/{range}.pbf", + "layers": [ + { + "id": "background", + "type": "background", + "paint": { + "background-color": "white" + } + }, + { + "id": "text", + "type": "symbol", + "source": "mapbox", + "source-layer": "poi_label", + "filter": [ + "==", + "maki", + "restaurant" + ], + "layout": { + "symbol-placement": "point", + "text-allow-overlap": true, + "text-ignore-placement": true, + "text-field": "Test", + "text-size": 32, + "text-font": [ + "Open Sans Semibold", + "Arial Unicode MS Bold" + ] + }, + "paint": { + "text-color": "transparent", + "text-halo-color": "black", + "text-halo-width": 1 + } + } + ] +} diff --git a/shaders/symbol_sdf.fragment.glsl b/shaders/symbol_sdf.fragment.glsl index 6bc97ac3e..76bfd36e4 100644 --- a/shaders/symbol_sdf.fragment.glsl +++ b/shaders/symbol_sdf.fragment.glsl @@ -57,16 +57,22 @@ void main() { lowp vec4 color = fill_color; highp float gamma = EDGE_GAMMA / (fontScale * u_gamma_scale); - lowp float buff = (256.0 - 64.0) / 256.0; + lowp float inner_edge = (256.0 - 64.0) / 256.0; if (u_is_halo) { color = halo_color; gamma = (halo_blur * 1.19 / SDF_PX + EDGE_GAMMA) / (fontScale * u_gamma_scale); - buff = (6.0 - halo_width / fontScale) / SDF_PX; + inner_edge = inner_edge + gamma * gamma_scale; } lowp float dist = texture(u_texture, tex).a; highp float gamma_scaled = gamma * gamma_scale; - highp float alpha = smoothstep(buff - gamma_scaled, buff + gamma_scaled, dist); + highp float alpha = smoothstep(inner_edge - gamma_scaled, inner_edge + gamma_scaled, dist); + if (u_is_halo) { + // When drawing halos, we want the inside of the halo to be transparent as well + // in case the text fill is transparent. + lowp float halo_edge = (6.0 - halo_width / fontScale) / SDF_PX; + alpha = min(smoothstep(halo_edge - gamma_scaled, halo_edge + gamma_scaled, dist), 1.0 - alpha); + } fragColor = color * (alpha * opacity * fade_opacity); diff --git a/shaders/symbol_text_and_icon.fragment.glsl b/shaders/symbol_text_and_icon.fragment.glsl index 8c307d0f0..ce5d120c8 100644 --- a/shaders/symbol_text_and_icon.fragment.glsl +++ b/shaders/symbol_text_and_icon.fragment.glsl @@ -74,16 +74,22 @@ void main() { lowp vec4 color = fill_color; highp float gamma = EDGE_GAMMA / (fontScale * u_gamma_scale); - lowp float buff = (256.0 - 64.0) / 256.0; + lowp float inner_edge = (256.0 - 64.0) / 256.0; if (u_is_halo) { color = halo_color; gamma = (halo_blur * 1.19 / SDF_PX + EDGE_GAMMA) / (fontScale * u_gamma_scale); - buff = (6.0 - halo_width / fontScale) / SDF_PX; + inner_edge = inner_edge + gamma * gamma_scale; } lowp float dist = texture(u_texture, tex).a; highp float gamma_scaled = gamma * gamma_scale; - highp float alpha = smoothstep(buff - gamma_scaled, buff + gamma_scaled, dist); + highp float alpha = smoothstep(inner_edge - gamma_scaled, inner_edge + gamma_scaled, dist); + if (u_is_halo) { + // When drawing halos, we want the inside of the halo to be transparent as well + // in case the text fill is transparent. + lowp float halo_edge = (6.0 - halo_width / fontScale) / SDF_PX; + alpha = min(smoothstep(halo_edge - gamma_scaled, halo_edge + gamma_scaled, dist), 1.0 - alpha); + } fragColor = color * (alpha * opacity * fade_opacity);