summaryrefslogtreecommitdiff
path: root/src/mbgl/shaders
diff options
context:
space:
mode:
authorAnsis Brammanis <brammanis@gmail.com>2017-06-16 10:42:33 -0400
committerAnsis Brammanis <brammanis@gmail.com>2017-07-11 09:10:24 -0700
commite514138b691615be24f484986c40f486223df82a (patch)
tree4cab221d92f66feefd132818a700c47cc67ef245 /src/mbgl/shaders
parent77734cfe1b9e77a0058fa3e0db79e3c20a264165 (diff)
downloadqtlocation-mapboxgl-e514138b691615be24f484986c40f486223df82a.tar.gz
[core] improve legibility of labels that follow lines
port https://github.com/mapbox/mapbox-gl-js/pull/4781 This improves legibility of labels that follow lines in pitched views. The previous approach used the limited information in the shader to calculate put the glyph in approximatelyright place. The new approach does this more accurately by doing it on the cpu where we have access to the entire line geometry.
Diffstat (limited to 'src/mbgl/shaders')
-rw-r--r--src/mbgl/shaders/collision_box.cpp2
-rw-r--r--src/mbgl/shaders/symbol_icon.cpp70
-rw-r--r--src/mbgl/shaders/symbol_sdf.cpp208
3 files changed, 93 insertions, 187 deletions
diff --git a/src/mbgl/shaders/collision_box.cpp b/src/mbgl/shaders/collision_box.cpp
index 05f306ef65..07fa94e338 100644
--- a/src/mbgl/shaders/collision_box.cpp
+++ b/src/mbgl/shaders/collision_box.cpp
@@ -36,7 +36,7 @@ void main() {
v_max_zoom = a_data.x;
v_placement_zoom = a_data.y;
- v_perspective_zoom_adjust = log2(collision_perspective_ratio * collision_adjustment) * 10.0;
+ v_perspective_zoom_adjust = floor(log2(collision_perspective_ratio * collision_adjustment) * 10.0);
v_fade_tex = vec2((v_placement_zoom + v_perspective_zoom_adjust) / 255.0, 0.0);
}
diff --git a/src/mbgl/shaders/symbol_icon.cpp b/src/mbgl/shaders/symbol_icon.cpp
index 8960e02c28..cb00cdad05 100644
--- a/src/mbgl/shaders/symbol_icon.cpp
+++ b/src/mbgl/shaders/symbol_icon.cpp
@@ -7,17 +7,16 @@ namespace shaders {
const char* symbol_icon::name = "symbol_icon";
const char* symbol_icon::vertexSource = R"MBGL_SHADER(
+const float PI = 3.141592653589793;
+
attribute vec4 a_pos_offset;
-attribute vec2 a_label_pos;
attribute vec4 a_data;
+attribute vec3 a_projected_pos;
-// icon-size data (see symbol_sdf.vertex.glsl for more)
-attribute vec3 a_size;
uniform bool u_is_size_zoom_constant;
uniform bool u_is_size_feature_constant;
uniform highp float u_size_t; // used to interpolate between zoom stops when size is a composite function
uniform highp float u_size; // used when size is both zoom and feature constant
-uniform highp float u_layout_size; // used when size is feature constant
uniform highp float u_camera_to_center_distance;
uniform highp float u_pitch;
uniform highp float u_collision_y_stretch;
@@ -31,13 +30,12 @@ varying lowp float opacity;
uniform lowp float u_opacity;
#endif
-// matrix is for the vertex position.
uniform mat4 u_matrix;
+uniform mat4 u_label_plane_matrix;
+uniform mat4 u_gl_coord_matrix;
uniform bool u_is_text;
-uniform highp float u_zoom;
-uniform bool u_rotate_with_map;
-uniform vec2 u_extrude_scale;
+uniform bool u_pitch_with_map;
uniform vec2 u_texsize;
@@ -56,61 +54,49 @@ void main() {
vec2 a_offset = a_pos_offset.zw;
vec2 a_tex = a_data.xy;
- highp vec2 label_data = unpack_float(a_data[2]);
- highp float a_labelminzoom = label_data[0];
- highp vec2 a_zoom = unpack_float(a_data[3]);
- highp float a_minzoom = a_zoom[0];
- highp float a_maxzoom = a_zoom[1];
+ vec2 a_size = a_data.zw;
+
+ highp vec2 angle_labelminzoom = unpack_float(a_projected_pos[2]);
+ highp float segment_angle = -angle_labelminzoom[0] / 255.0 * 2.0 * PI;
+ mediump float a_labelminzoom = angle_labelminzoom[1];
float size;
- // In order to accommodate placing labels around corners in
- // symbol-placement: line, each glyph in a label could have multiple
- // "quad"s only one of which should be shown at a given zoom level.
- // The min/max zoom assigned to each quad is based on the font size at
- // the vector tile's zoom level, which might be different than at the
- // currently rendered zoom level if text-size is zoom-dependent.
- // Thus, we compensate for this difference by calculating an adjustment
- // based on the scale of rendered text size relative to layout text size.
- highp float layoutSize;
if (!u_is_size_zoom_constant && !u_is_size_feature_constant) {
size = mix(a_size[0], a_size[1], u_size_t) / 10.0;
- layoutSize = a_size[2] / 10.0;
} else if (u_is_size_zoom_constant && !u_is_size_feature_constant) {
size = a_size[0] / 10.0;
- layoutSize = size;
} else if (!u_is_size_zoom_constant && u_is_size_feature_constant) {
size = u_size;
- layoutSize = u_layout_size;
} else {
size = u_size;
- layoutSize = u_size;
}
- float fontScale = u_is_text ? size / 24.0 : size;
+ vec4 projectedPoint = u_matrix * vec4(a_pos, 0, 1);
+ highp float camera_to_anchor_distance = projectedPoint.w;
+ // See comments in symbol_sdf.vertex
+ highp float distance_ratio = u_pitch_with_map ?
+ camera_to_anchor_distance / u_camera_to_center_distance :
+ u_camera_to_center_distance / camera_to_anchor_distance;
+ highp float perspective_ratio = 0.5 + 0.5 * distance_ratio;
- highp float zoomAdjust = log2(size / layoutSize);
- highp float adjustedZoom = (u_zoom - zoomAdjust) * 10.0;
- // result: z = 0 if a_minzoom <= adjustedZoom < a_maxzoom, and 1 otherwise
- highp float z = 2.0 - step(a_minzoom, adjustedZoom) - (1.0 - step(a_maxzoom, adjustedZoom));
+ size *= perspective_ratio;
- vec4 projectedPoint = u_matrix * vec4(a_label_pos, 0, 1);
- highp float camera_to_anchor_distance = projectedPoint.w;
- highp float perspective_ratio = 1.0 + 0.5*((camera_to_anchor_distance / u_camera_to_center_distance) - 1.0);
+ float fontScale = u_is_text ? size / 24.0 : size;
- vec2 extrude = fontScale * u_extrude_scale * perspective_ratio * (a_offset / 64.0);
- if (u_rotate_with_map) {
- gl_Position = u_matrix * vec4(a_pos + extrude, 0, 1);
- gl_Position.z += z * gl_Position.w;
- } else {
- gl_Position = u_matrix * vec4(a_pos, 0, 1) + vec4(extrude, 0, 0);
- }
+ highp float angle_sin = sin(segment_angle);
+ highp float angle_cos = cos(segment_angle);
+ mat2 rotation_matrix = mat2(angle_cos, -1.0 * angle_sin, angle_sin, angle_cos);
+
+ vec4 projected_pos = u_label_plane_matrix * vec4(a_projected_pos.xy, 0.0, 1.0);
+ gl_Position = u_gl_coord_matrix * vec4(projected_pos.xy / projected_pos.w + rotation_matrix * (a_offset / 64.0 * fontScale), 0.0, 1.0);
v_tex = a_tex / u_texsize;
// See comments in symbol_sdf.vertex
highp float incidence_stretch = camera_to_anchor_distance / (u_camera_to_center_distance * cos(u_pitch));
highp float collision_adjustment = max(1.0, incidence_stretch / u_collision_y_stretch);
- highp float perspective_zoom_adjust = log2(perspective_ratio * collision_adjustment) * 10.0;
+ highp float collision_perspective_ratio = 1.0 + 0.5*((camera_to_anchor_distance / u_camera_to_center_distance) - 1.0);
+ highp float perspective_zoom_adjust = floor(log2(collision_perspective_ratio * collision_adjustment) * 10.0);
v_fade_tex = vec2((a_labelminzoom + perspective_zoom_adjust) / 255.0, 0.0);
}
diff --git a/src/mbgl/shaders/symbol_sdf.cpp b/src/mbgl/shaders/symbol_sdf.cpp
index bae01a5b59..b4158bacc5 100644
--- a/src/mbgl/shaders/symbol_sdf.cpp
+++ b/src/mbgl/shaders/symbol_sdf.cpp
@@ -9,11 +9,9 @@ const char* symbol_sdf::name = "symbol_sdf";
const char* symbol_sdf::vertexSource = R"MBGL_SHADER(
const float PI = 3.141592653589793;
-// NOTE: the a_data attribute in this shader is manually bound (see https://github.com/mapbox/mapbox-gl-js/issues/4607).
-// If removing or renaming a_data, revisit the manual binding in painter.js accordingly.
attribute vec4 a_pos_offset;
-attribute vec2 a_label_pos;
attribute vec4 a_data;
+attribute vec3 a_projected_pos;
// contents of a_size vary based on the type of property value
// used for {text,icon}-size.
@@ -21,17 +19,14 @@ attribute vec4 a_data;
// For source functions, we bind only one value per vertex: the value of {text,icon}-size evaluated for the current feature.
// For composite functions:
// [ text-size(lowerZoomStop, feature),
-// text-size(upperZoomStop, feature),
-// layoutSize == text-size(layoutZoomLevel, feature) ]
-attribute vec3 a_size;
+// text-size(upperZoomStop, feature) ]
uniform bool u_is_size_zoom_constant;
uniform bool u_is_size_feature_constant;
uniform highp float u_size_t; // used to interpolate between zoom stops when size is a composite function
uniform highp float u_size; // used when size is both zoom and feature constant
-uniform highp float u_layout_size; // used when size is feature constant
-#ifdef HAS_UNIFORM_u_fill_color
+#ifndef HAS_UNIFORM_u_fill_color
uniform lowp float a_fill_color_t;
attribute highp vec4 a_fill_color;
varying highp vec4 fill_color;
@@ -39,8 +34,7 @@ varying highp vec4 fill_color;
uniform highp vec4 u_fill_color;
#endif
-
-#ifdef HAS_UNIFORM_u_halo_color
+#ifndef HAS_UNIFORM_u_halo_color
uniform lowp float a_halo_color_t;
attribute highp vec4 a_halo_color;
varying highp vec4 halo_color;
@@ -48,8 +42,7 @@ varying highp vec4 halo_color;
uniform highp vec4 u_halo_color;
#endif
-
-#ifdef HAS_UNIFORM_u_opacity
+#ifndef HAS_UNIFORM_u_opacity
uniform lowp float a_opacity_t;
attribute lowp vec2 a_opacity;
varying lowp float opacity;
@@ -57,8 +50,7 @@ varying lowp float opacity;
uniform lowp float u_opacity;
#endif
-
-#ifdef HAS_UNIFORM_u_halo_width
+#ifndef HAS_UNIFORM_u_halo_width
uniform lowp float a_halo_width_t;
attribute lowp vec2 a_halo_width;
varying lowp float halo_width;
@@ -66,8 +58,7 @@ varying lowp float halo_width;
uniform lowp float u_halo_width;
#endif
-
-#ifdef HAS_UNIFORM_u_halo_blur
+#ifndef HAS_UNIFORM_u_halo_blur
uniform lowp float a_halo_blur_t;
attribute lowp vec2 a_halo_blur;
varying lowp float halo_blur;
@@ -75,168 +66,100 @@ varying lowp float halo_blur;
uniform lowp float u_halo_blur;
#endif
-
-// matrix is for the vertex position.
uniform mat4 u_matrix;
+uniform mat4 u_label_plane_matrix;
+uniform mat4 u_gl_coord_matrix;
uniform bool u_is_text;
-uniform highp float u_zoom;
-uniform bool u_rotate_with_map;
uniform bool u_pitch_with_map;
uniform highp float u_pitch;
-uniform highp float u_bearing;
-uniform highp float u_aspect_ratio;
uniform highp float u_camera_to_center_distance;
-uniform highp float u_max_camera_distance;
uniform highp float u_collision_y_stretch;
-uniform vec2 u_extrude_scale;
uniform vec2 u_texsize;
-varying vec2 v_tex;
-varying vec2 v_fade_tex;
-varying float v_gamma_scale;
-varying float v_size;
-
-// Used below to move the vertex out of the clip space for when the current
-// zoom is out of the glyph's zoom range.
-highp float clipUnusedGlyphAngles(const highp float render_size,
- const highp float layout_size,
- const highp float min_zoom,
- const highp float max_zoom) {
- highp float zoom_adjust = log2(render_size / layout_size);
- highp float adjusted_zoom = (u_zoom - zoom_adjust) * 10.0;
- // result: 0 if min_zoom <= adjusted_zoom < max_zoom, and 1 otherwise
- return 2.0 - step(min_zoom, adjusted_zoom) - (1.0 - step(max_zoom, adjusted_zoom));
-}
+varying vec4 v_data0;
+varying vec2 v_data1;
void main() {
-
+
#ifndef HAS_UNIFORM_u_fill_color
fill_color = unpack_mix_vec4(a_fill_color, a_fill_color_t);
#else
highp vec4 fill_color = u_fill_color;
#endif
-
#ifndef HAS_UNIFORM_u_halo_color
halo_color = unpack_mix_vec4(a_halo_color, a_halo_color_t);
#else
highp vec4 halo_color = u_halo_color;
#endif
-
#ifndef HAS_UNIFORM_u_opacity
opacity = unpack_mix_vec2(a_opacity, a_opacity_t);
#else
lowp float opacity = u_opacity;
#endif
-
#ifndef HAS_UNIFORM_u_halo_width
halo_width = unpack_mix_vec2(a_halo_width, a_halo_width_t);
#else
lowp float halo_width = u_halo_width;
#endif
-
#ifndef HAS_UNIFORM_u_halo_blur
halo_blur = unpack_mix_vec2(a_halo_blur, a_halo_blur_t);
#else
lowp float halo_blur = u_halo_blur;
#endif
-
vec2 a_pos = a_pos_offset.xy;
vec2 a_offset = a_pos_offset.zw;
vec2 a_tex = a_data.xy;
+ vec2 a_size = a_data.zw;
+
+ highp vec2 angle_labelminzoom = unpack_float(a_projected_pos[2]);
+ highp float segment_angle = -angle_labelminzoom[0] / 255.0 * 2.0 * PI;
+ mediump float a_labelminzoom = angle_labelminzoom[1];
+ float size;
- highp vec2 label_data = unpack_float(a_data[2]);
- highp float a_labelminzoom = label_data[0];
- highp float a_lineangle = (label_data[1] / 256.0 * 2.0 * PI);
- highp vec2 a_zoom = unpack_float(a_data[3]);
- highp float a_minzoom = a_zoom[0];
- highp float a_maxzoom = a_zoom[1];
-
- // In order to accommodate placing labels around corners in
- // symbol-placement: line, each glyph in a label could have multiple
- // "quad"s only one of which should be shown at a given zoom level.
- // The min/max zoom assigned to each quad is based on the font size at
- // the vector tile's zoom level, which might be different than at the
- // currently rendered zoom level if text-size is zoom-dependent.
- // Thus, we compensate for this difference by calculating an adjustment
- // based on the scale of rendered text size relative to layout text size.
- highp float layoutSize;
if (!u_is_size_zoom_constant && !u_is_size_feature_constant) {
- v_size = mix(a_size[0], a_size[1], u_size_t) / 10.0;
- layoutSize = a_size[2] / 10.0;
+ size = mix(a_size[0], a_size[1], u_size_t) / 10.0;
} else if (u_is_size_zoom_constant && !u_is_size_feature_constant) {
- v_size = a_size[0] / 10.0;
- layoutSize = v_size;
+ size = a_size[0] / 10.0;
} else if (!u_is_size_zoom_constant && u_is_size_feature_constant) {
- v_size = u_size;
- layoutSize = u_layout_size;
+ size = u_size;
} else {
- v_size = u_size;
- layoutSize = u_size;
+ size = u_size;
}
- float fontScale = u_is_text ? v_size / 24.0 : v_size;
-
- vec4 projectedPoint = u_matrix * vec4(a_label_pos, 0, 1);
+ vec4 projectedPoint = u_matrix * vec4(a_pos, 0, 1);
highp float camera_to_anchor_distance = projectedPoint.w;
- highp float perspective_ratio = 1.0 + 0.5*((camera_to_anchor_distance / u_camera_to_center_distance) - 1.0);
-
- // pitch-alignment: map
- // rotation-alignment: map | viewport
- if (u_pitch_with_map) {
- highp float angle = u_rotate_with_map ? a_lineangle : u_bearing;
- highp float asin = sin(angle);
- highp float acos = cos(angle);
- mat2 RotationMatrix = mat2(acos, asin, -1.0 * asin, acos);
- vec2 offset = RotationMatrix * a_offset;
- vec2 extrude = fontScale * u_extrude_scale * perspective_ratio * (offset / 64.0);
-
- gl_Position = u_matrix * vec4(a_pos + extrude, 0, 1);
- gl_Position.z += clipUnusedGlyphAngles(v_size*perspective_ratio, layoutSize, a_minzoom, a_maxzoom) * gl_Position.w;
- // pitch-alignment: viewport
- // rotation-alignment: map
- } else if (u_rotate_with_map) {
- // foreshortening factor to apply on pitched maps
- // as a label goes from horizontal <=> vertical in angle
- // it goes from 0% foreshortening to up to around 70% foreshortening
- highp float pitchfactor = 1.0 - cos(u_pitch * sin(u_pitch * 0.75));
-
- // use the lineangle to position points a,b along the line
- // project the points and calculate the label angle in projected space
- // this calculation allows labels to be rendered unskewed on pitched maps
- vec4 a = u_matrix * vec4(a_pos, 0, 1);
- vec4 b = u_matrix * vec4(a_pos + vec2(cos(a_lineangle), sin(a_lineangle)), 0, 1);
- highp float angle = atan((b[1] / b[3] - a[1] / a[3]) / u_aspect_ratio, b[0] / b[3] - a[0] / a[3]);
- highp float asin = sin(angle);
- highp float acos = cos(angle);
- mat2 RotationMatrix = mat2(acos, -1.0 * asin, asin, acos);
- highp float foreshortening = (1.0 - pitchfactor) + (pitchfactor * cos(angle * 2.0));
-
- vec2 offset = RotationMatrix * (vec2(foreshortening, 1.0) * a_offset);
- vec2 extrude = fontScale * u_extrude_scale * perspective_ratio * (offset / 64.0);
-
- gl_Position = u_matrix * vec4(a_pos, 0, 1) + vec4(extrude, 0, 0);
- gl_Position.z += clipUnusedGlyphAngles(v_size * perspective_ratio, layoutSize, a_minzoom, a_maxzoom) * gl_Position.w;
- // pitch-alignment: viewport
- // rotation-alignment: viewport
- } else {
- vec2 extrude = fontScale * u_extrude_scale * perspective_ratio * (a_offset / 64.0);
- gl_Position = u_matrix * vec4(a_pos, 0, 1) + vec4(extrude, 0, 0);
- }
-
- gl_Position.z +=
- step(u_max_camera_distance * u_camera_to_center_distance, camera_to_anchor_distance) * gl_Position.w;
-
- v_gamma_scale = gl_Position.w / perspective_ratio;
-
- v_tex = a_tex / u_texsize;
+ // If the label is pitched with the map, layout is done in pitched space,
+ // which makes labels in the distance smaller relative to viewport space.
+ // We counteract part of that effect by multiplying by the perspective ratio.
+ // If the label isn't pitched with the map, we do layout in viewport space,
+ // which makes labels in the distance larger relative to the features around
+ // them. We counteract part of that effect by dividing by the perspective ratio.
+ highp float distance_ratio = u_pitch_with_map ?
+ camera_to_anchor_distance / u_camera_to_center_distance :
+ u_camera_to_center_distance / camera_to_anchor_distance;
+ highp float perspective_ratio = 0.5 + 0.5 * distance_ratio;
+
+ size *= perspective_ratio;
+
+ float fontScale = u_is_text ? size / 24.0 : size;
+
+ highp float angle_sin = sin(segment_angle);
+ highp float angle_cos = cos(segment_angle);
+ mat2 rotation_matrix = mat2(angle_cos, -1.0 * angle_sin, angle_sin, angle_cos);
+
+ vec4 projected_pos = u_label_plane_matrix * vec4(a_projected_pos.xy, 0.0, 1.0);
+ gl_Position = u_gl_coord_matrix * vec4(projected_pos.xy / projected_pos.w + rotation_matrix * (a_offset / 64.0 * fontScale), 0.0, 1.0);
+ float gamma_scale = gl_Position.w;
+
+ vec2 tex = a_tex / u_texsize;
// incidence_stretch is the ratio of how much y space a label takes up on a tile while drawn perpendicular to the viewport vs
// how much space it would take up if it were drawn flat on the tile
// Using law of sines, camera_to_anchor/sin(ground_angle) = camera_to_center/sin(incidence_angle)
@@ -256,8 +179,12 @@ void main() {
highp float collision_adjustment = max(1.0, incidence_stretch / u_collision_y_stretch);
// Floor to 1/10th zoom to dodge precision issues that can cause partially hidden labels
- highp float perspective_zoom_adjust = floor(log2(perspective_ratio * collision_adjustment) * 10.0);
- v_fade_tex = vec2((a_labelminzoom + perspective_zoom_adjust) / 255.0, 0.0);
+ highp float collision_perspective_ratio = 1.0 + 0.5*((camera_to_anchor_distance / u_camera_to_center_distance) - 1.0);
+ highp float perspective_zoom_adjust = floor(log2(collision_perspective_ratio * collision_adjustment) * 10.0);
+ vec2 fade_tex = vec2((a_labelminzoom + perspective_zoom_adjust) / 255.0, 0.0);
+
+ v_data0 = vec4(tex.x, tex.y, fade_tex.x, fade_tex.y);
+ v_data1 = vec2(gamma_scale, size);
}
)MBGL_SHADER";
@@ -273,73 +200,66 @@ varying highp vec4 fill_color;
uniform highp vec4 u_fill_color;
#endif
-
#ifndef HAS_UNIFORM_u_halo_color
varying highp vec4 halo_color;
#else
uniform highp vec4 u_halo_color;
#endif
-
#ifndef HAS_UNIFORM_u_opacity
varying lowp float opacity;
#else
uniform lowp float u_opacity;
#endif
-
#ifndef HAS_UNIFORM_u_halo_width
varying lowp float halo_width;
#else
uniform lowp float u_halo_width;
#endif
-
#ifndef HAS_UNIFORM_u_halo_blur
varying lowp float halo_blur;
#else
uniform lowp float u_halo_blur;
#endif
-
uniform sampler2D u_texture;
uniform sampler2D u_fadetexture;
uniform highp float u_gamma_scale;
uniform bool u_is_text;
-varying vec2 v_tex;
-varying vec2 v_fade_tex;
-varying float v_gamma_scale;
-varying float v_size;
+varying vec4 v_data0;
+varying vec2 v_data1;
void main() {
-
+
#ifdef HAS_UNIFORM_u_fill_color
highp vec4 fill_color = u_fill_color;
#endif
-
#ifdef HAS_UNIFORM_u_halo_color
highp vec4 halo_color = u_halo_color;
#endif
-
#ifdef HAS_UNIFORM_u_opacity
lowp float opacity = u_opacity;
#endif
-
#ifdef HAS_UNIFORM_u_halo_width
lowp float halo_width = u_halo_width;
#endif
-
#ifdef HAS_UNIFORM_u_halo_blur
lowp float halo_blur = u_halo_blur;
#endif
+ vec2 tex = v_data0.xy;
+ vec2 fade_tex = v_data0.zw;
+ float gamma_scale = v_data1.x;
+ float size = v_data1.y;
- float fontScale = u_is_text ? v_size / 24.0 : v_size;
+ float fontScale = u_is_text ? size / 24.0 : size;
lowp vec4 color = fill_color;
highp float gamma = EDGE_GAMMA / (fontScale * u_gamma_scale);
@@ -350,9 +270,9 @@ void main() {
buff = (6.0 - halo_width / fontScale) / SDF_PX;
}
- lowp float dist = texture2D(u_texture, v_tex).a;
- lowp float fade_alpha = texture2D(u_fadetexture, v_fade_tex).a;
- highp float gamma_scaled = gamma * v_gamma_scale;
+ lowp float dist = texture2D(u_texture, tex).a;
+ lowp float fade_alpha = texture2D(u_fadetexture, fade_tex).a;
+ highp float gamma_scaled = gamma * gamma_scale;
highp float alpha = smoothstep(buff - gamma_scaled, buff + gamma_scaled, dist) * fade_alpha;
gl_FragColor = color * (alpha * opacity);