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

Use a nicer approximation for anti-aliasing. #1822

Merged
merged 4 commits into from Oct 13, 2017
Merged
Changes from 1 commit
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

Next

Fix the math behind antialiasing in the shaders.

  • Loading branch information
nical committed Oct 13, 2017
commit 925354578aad7f571f76bce77e083627a8235ad7
@@ -155,8 +155,7 @@ void main(void) {
clip_relative_pos);

// Get AA widths based on zoom / scale etc.
vec2 fw = fwidth(local_pos);
float afwidth = length(fw);
float aa_range = 0.4 * length(fwidth(local_pos));

This comment has been minimized.

@kvark

kvark Oct 12, 2017

Member

can we have 0.4 as a constant defined somewhere with a proper name + comments?


// SDF subtract edges for dash clip
float dash_distance = max(d0, -d1);
@@ -167,8 +166,8 @@ void main(void) {
// Select between dot/dash clip based on mode.
float d = mix(dash_distance, dot_distance, vAlphaMask.x);

// Apply AA over half a device pixel for the clip.
d = 1.0 - smoothstep(0.0, 0.5 * afwidth, d);
// Apply AA.
d = 1.0 - smoothstep(-aa_range, aa_range, d);

// Completely mask out clip if zero'ing out the rect.
d = d * vAlphaMask.y;
@@ -101,50 +101,47 @@ void main(void) {
float clip_against_ellipse_if_needed(vec2 pos,
float current_distance,
vec4 ellipse_center_radius,
vec2 sign_modifier,
float afwidth) {
vec2 sign_modifier) {
float ellipse_distance = distance_to_ellipse(pos - ellipse_center_radius.xy,
ellipse_center_radius.zw);

return mix(current_distance,
ellipse_distance + afwidth,
ellipse_distance,
all(lessThan(sign_modifier * pos, sign_modifier * ellipse_center_radius.xy)));
}

float rounded_rect(vec2 pos) {
float current_distance = 0.0;

// Apply AA
float afwidth = 0.5 * length(fwidth(pos));
// Start with a negative value (means "inside") for all fragments that are not
// in a corner. If the fragment is in a corner, one of the clip_against_ellipse_if_needed
// calls below will update it.
float current_distance = -1.0;

// Clip against each ellipse.
current_distance = clip_against_ellipse_if_needed(pos,
current_distance,
vClipCenter_Radius_TL,
vec2(1.0),
afwidth);
vec2(1.0));

current_distance = clip_against_ellipse_if_needed(pos,
current_distance,
vClipCenter_Radius_TR,
vec2(-1.0, 1.0),
afwidth);
vec2(-1.0, 1.0));

current_distance = clip_against_ellipse_if_needed(pos,
current_distance,
vClipCenter_Radius_BR,
vec2(-1.0),
afwidth);
vec2(-1.0));

current_distance = clip_against_ellipse_if_needed(pos,
current_distance,
vClipCenter_Radius_BL,
vec2(1.0, -1.0),
afwidth);
vec2(1.0, -1.0));

return smoothstep(0.0, afwidth, 1.0 - current_distance);
}
// Apply AA
// See comment in ps_border_corner about the choice of constants.
float aa_range = 0.4 * length(fwidth(pos));

return 1.0 - smoothstep(-aa_range, aa_range, current_distance);

This comment has been minimized.

@kvark

kvark Oct 12, 2017

Member

would be great to share these 2 lines between shaders

}

void main(void) {
float alpha = 1.f;
@@ -733,10 +733,10 @@ vec2 init_transform_fs(vec3 local_pos, out float fragment_alpha) {
float d = signed_distance_rect(pos, vLocalBounds.xy, vLocalBounds.zw);

// Find the appropriate distance to apply the AA smoothstep over.
float afwidth = 0.5 * length(fwidth(pos.xy));
float aa_range = 0.4 * length(fwidth(pos.xy));

// Only apply AA to fragments outside the signed distance field.
fragment_alpha = 1.0 - smoothstep(0.0, afwidth, d);
fragment_alpha = 1.0 - smoothstep(-aa_range, aa_range, d);

return pos;
}
@@ -324,11 +324,19 @@ void main(void) {

alpha = min(alpha, do_clip());

// Find the appropriate distance to apply the AA smoothstep over.
// Using 0.7 instead of 0.5 for the step compensates for the fact that smoothstep
// is smooth at its endpoints and has a steeper maximum slope than a linear ramp.
vec2 fw = fwidth(local_pos);
float aa_step = 0.7 * length(fw);
// Find the appropriate range to apply the AA smoothstep over.
// the aa step represents a coefficient to go from one CSS pixel to half a device pixel.
// We use 0.4 here to compensate for the fact that length(fw) is equal to sqrt(2) times
// the device pixel ratio in the typical case.
// Using larger aa steps is quite common when rendering shapes with distance fields.
// It gives a smoother (although a bit blurrier look) by extending the range that is
// smoothed to produce the anti aliasing. In our case, however, extending the range inside
// of the shape causes noticeable artifacts at the junction between an antialiased corner
// and a straight edge.
// The coefficient below is chosen to ensure that a sample that is 0.5 pixels or more inside of the
// curve shape has no anti-aliasing applied to it (since pixels are sampled at their center, such a
// pixel is fully inside the border.
float aa_range = 0.4 * length(fwidth(local_pos));

float distance_for_color;
float color_mix_factor;
@@ -349,29 +357,26 @@ void main(void) {
// To correct this exactly we would need to offset p by half a pixel in the
// direction of the center of the ellipse (a different offset for each corner).

// A half device pixel in css pixels (using the average of width and height in case
// there is any kind of transform applied).
float half_px = 0.25 * (fw.x + fw.y);
// Get signed distance from the inner/outer clips.
float d0 = distance_to_ellipse(p, vRadii0.xy) + half_px;
float d1 = distance_to_ellipse(p, vRadii0.zw) + half_px;
float d2 = distance_to_ellipse(p, vRadii1.xy) + half_px;
float d3 = distance_to_ellipse(p, vRadii1.zw) + half_px;
float d0 = distance_to_ellipse(p, vRadii0.xy);
float d1 = distance_to_ellipse(p, vRadii0.zw);
float d2 = distance_to_ellipse(p, vRadii1.xy);
float d3 = distance_to_ellipse(p, vRadii1.zw);

// SDF subtract main radii
float d_main = max(d0, aa_step - d1);
float d_main = max(d0, -d1);

// SDF subtract inner radii (double style borders)
float d_inner = max(d2 - aa_step, -d3);
float d_inner = max(d2, -d3);

// Select how to combine the SDF based on border style.
float d = mix(max(d_main, -d_inner), d_main, vSDFSelect);

// Only apply AA to fragments outside the signed distance field.
alpha = min(alpha, 1.0 - smoothstep(0.0, aa_step, d));
alpha = min(alpha, 1.0 - smoothstep(-aa_range, aa_range, d));

// Get the groove/ridge mix factor.
color_mix_factor = smoothstep(-aa_step, aa_step, -d2);
color_mix_factor = smoothstep(-aa_range, aa_range, -d2);
} else {
// Handle the case where the fragment is outside the clip
// region in a corner. This occurs when border width is
@@ -403,7 +408,7 @@ void main(void) {
// Select color based on side of line. Get distance from the
// reference line, and then apply AA along the edge.
float ld = distance_to_line(vColorEdgeLine.xy, vColorEdgeLine.zw, local_pos);
float m = smoothstep(-aa_step, aa_step, ld);
float m = smoothstep(-aa_range, aa_range, ld);
vec4 color = mix(color0, color1, m);

oFragColor = color * vec4(1.0, 1.0, 1.0, alpha);
@@ -253,8 +253,7 @@ void main(void) {
alpha = min(alpha, do_clip());

// Find the appropriate distance to apply the step over.
vec2 fw = fwidth(local_pos);
float afwidth = length(fw);
float aa_range = 0.4 * length(fwidth(local_pos));

// Applies the math necessary to draw a style: double
// border. In the case of a solid border, the vertex
@@ -291,9 +290,7 @@ void main(void) {
// Get the dot alpha
vec2 dot_relative_pos = vec2(x, pos.x) - vClipParams.zw;
float dot_distance = length(dot_relative_pos) - vClipParams.z;
float dot_alpha = 1.0 - smoothstep(-0.5 * afwidth,
0.5 * afwidth,
dot_distance);
float dot_alpha = 1.0 - smoothstep(-aa_range, aa_range, dot_distance);

// Select between dot/dash alpha based on clip mode.
alpha = min(alpha, mix(dash_alpha, dot_alpha, vClipSelect));
@@ -190,8 +190,7 @@ void main(void) {
#endif

// Find the appropriate distance to apply the step over.
vec2 fw = fwidth(local_pos);
float afwidth = length(fw);
float aa_range = 0.4 * length(fwidth(local_pos));

// Select the x/y coord, depending on which axis this edge is.
vec2 pos = mix(local_pos.xy, local_pos.yx, vAxisSelect);
@@ -215,9 +214,7 @@ void main(void) {
// Get the dot alpha
vec2 dot_relative_pos = vec2(x, pos.y) - vParams.yz;
float dot_distance = length(dot_relative_pos) - vParams.y;
alpha = min(alpha, 1.0 - smoothstep(-0.5 * afwidth,
0.5 * afwidth,
dot_distance));
alpha = min(alpha, 1.0 - smoothstep(-aa_range, aa_range, dot_distance));
break;
}
case LINE_STYLE_WAVY: {
@@ -251,8 +248,8 @@ void main(void) {
float d = min(d1, d2);

// Apply AA based on the thickness of the wave.
alpha = 1.0 - smoothstep(vParams.x - 0.5 * afwidth,
vParams.x + 0.5 * afwidth,
alpha = 1.0 - smoothstep(vParams.x - aa_range,
vParams.x + aa_range,
d);
break;
}
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.