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 all commits
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

@@ -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 = compute_aa_range(local_pos);

// 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 = distance_aa(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 = compute_aa_range(pos);

return distance_aa(aa_range, current_distance);
}

void main(void) {
float alpha = 1.f;
@@ -719,6 +719,35 @@ void write_clip(vec2 global_pos, ClipArea area) {

#ifdef WR_FRAGMENT_SHADER

/// Find the appropriate half range to apply the AA smoothstep over.
/// This range represents a coefficient to go from one CSS pixel to half a device pixel.
float compute_aa_range(vec2 position) {
// The constant factor is chosen to compensate for the fact that length(fw) is equal
// to sqrt(2) times the device pixel ratio in the typical case. 0.5/sqrt(2) = 0.35355.
//
// This coefficient is chosen to ensure that any sample 0.5 pixels or more inside of
// the shape has no anti-aliasing applied to it (since pixels are sampled at their center,
// such a pixel (axis aligned) is fully inside the border). We need this so that antialiased
// curves properly connect with non-antialiased vertical or horizontal lines, among other things.
//
// Using larger aa steps is quite common when rendering shapes with distance fields.
// It gives a smoother (although 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.
// We may want to adjust this constant in specific scenarios (for example keep the principled
// value for straight edges where we want pixel-perfect equivalence with non antialiased lines
// when axis aligned, while selecting a larger and smoother aa range on curves).
return 0.35355 * length(fwidth(position));
}

/// Return the blending coefficient to for distance antialiasing.
///
/// 0.0 means inside the shape, 1.0 means outside.
float distance_aa(float aa_range, float signed_distance) {
return 1.0 - smoothstep(-aa_range, aa_range, signed_distance);
}

#ifdef WR_FEATURE_TRANSFORM
float signed_distance_rect(vec2 pos, vec2 p0, vec2 p1) {
vec2 d = max(p0 - pos, pos - p1);
@@ -733,10 +762,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 = compute_aa_range(pos.xy);

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

return pos;
}
@@ -324,11 +324,7 @@ 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);
float aa_range = compute_aa_range(local_pos);

float distance_for_color;
float color_mix_factor;
@@ -349,29 +345,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, distance_aa(aa_range, d));

// Get the groove/ridge mix factor.
color_mix_factor = smoothstep(-aa_step, aa_step, -d2);
color_mix_factor = distance_aa(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 +396,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 = distance_aa(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 = compute_aa_range(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 = distance_aa(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 = compute_aa_range(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, distance_aa(aa_range, dot_distance));
break;
}
case LINE_STYLE_WAVY: {
@@ -251,9 +248,7 @@ 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,
d);
alpha = distance_aa(aa_range, d - vParams.x);
break;
}
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.