@@ -110,10 +110,10 @@ void write_color(vec4 color0, vec4 color1, int style, vec2 delta, int instance_k
110
110
break ;
111
111
}
112
112
113
- vColor00 = vec4 (color0.rgb * modulate.x, color0.a);
114
- vColor01 = vec4 (color0.rgb * modulate.y, color0.a);
115
- vColor10 = vec4 (color1.rgb * modulate.z, color1.a);
116
- vColor11 = vec4 (color1.rgb * modulate.w, color1.a);
113
+ vColor00 = vec4 (clamp ( color0.rgb * modulate.x, vec3 ( 0.0 ), vec3 ( 1.0 )) , color0.a);
114
+ vColor01 = vec4 (clamp ( color0.rgb * modulate.y, vec3 ( 0.0 ), vec3 ( 1.0 )) , color0.a);
115
+ vColor10 = vec4 (clamp ( color1.rgb * modulate.z, vec3 ( 0.0 ), vec3 ( 1.0 )) , color1.a);
116
+ vColor11 = vec4 (clamp ( color1.rgb * modulate.w, vec3 ( 0.0 ), vec3 ( 1.0 )) , color1.a);
117
117
}
118
118
119
119
int select_style(int color_select, vec2 fstyle) {
@@ -325,8 +325,11 @@ void main(void) {
325
325
alpha = min (alpha, do_clip());
326
326
327
327
// Find the appropriate distance to apply the AA smoothstep over.
328
+ // Using 0.7 instead of 0.5 for the step compensates for the fact that smoothstep
329
+ // is smooth at its endpoints and has a steeper maximum slope than a linear ramp.
328
330
vec2 fw = fwidth (local_pos);
329
- float afwidth = length (fw);
331
+ float aa_step = 0.7 * length (fw);
332
+
330
333
float distance_for_color;
331
334
float color_mix_factor;
332
335
@@ -336,28 +339,39 @@ void main(void) {
336
339
if (all (lessThan (local_pos * vClipSign, vClipCenter * vClipSign))) {
337
340
vec2 p = local_pos - vClipCenter;
338
341
342
+ // The coordinate system is snapped to pixel boundaries. To sample the distance,
343
+ // however, we are interested in the center of the pixels which introduces an
344
+ // error of half a pixel towards the exterior of the curve (See issue #1750).
345
+ // This error is corrected by offsetting the distance by half a device pixel.
346
+ // This not entirely correct: it leaves an error that varries between
347
+ // 0 and (sqrt(2) - 1)/2 = 0.2 pixels but it is hardly noticeable and is better
348
+ // than the constant sqrt(2)/2 px error without the correction.
349
+ // To correct this exactly we would need to offset p by half a pixel in the
350
+ // direction of the center of the ellipse (a different offset for each corner).
351
+
352
+ // A half device pixel in css pixels (using the average of width and height in case
353
+ // there is any kind of transform applied).
354
+ float half_px = 0.25 * (fw.x + fw.y);
339
355
// Get signed distance from the inner/outer clips.
340
- float d0 = distance_to_ellipse(p, vRadii0.xy);
341
- float d1 = distance_to_ellipse(p, vRadii0.zw);
342
- float d2 = distance_to_ellipse(p, vRadii1.xy);
343
- float d3 = distance_to_ellipse(p, vRadii1.zw);
356
+ float d0 = distance_to_ellipse(p, vRadii0.xy) + half_px ;
357
+ float d1 = distance_to_ellipse(p, vRadii0.zw) + half_px ;
358
+ float d2 = distance_to_ellipse(p, vRadii1.xy) + half_px ;
359
+ float d3 = distance_to_ellipse(p, vRadii1.zw) + half_px ;
344
360
345
361
// SDF subtract main radii
346
- float d_main = max (d0, 0.5 * afwidth - d1);
362
+ float d_main = max (d0, aa_step - d1);
347
363
348
364
// SDF subtract inner radii (double style borders)
349
- float d_inner = max (d2 - 0.5 * afwidth , - d3);
365
+ float d_inner = max (d2 - aa_step , - d3);
350
366
351
367
// Select how to combine the SDF based on border style.
352
368
float d = mix (max (d_main, - d_inner), d_main, vSDFSelect);
353
369
354
370
// Only apply AA to fragments outside the signed distance field.
355
- alpha = min (alpha, 1.0 - smoothstep (0.0 , 0.5 * afwidth , d));
371
+ alpha = min (alpha, 1.0 - smoothstep (0.0 , aa_step , d));
356
372
357
373
// Get the groove/ridge mix factor.
358
- color_mix_factor = smoothstep (- 0.5 * afwidth,
359
- 0.5 * afwidth,
360
- - d2);
374
+ color_mix_factor = smoothstep (- aa_step, aa_step, - d2);
361
375
} else {
362
376
// Handle the case where the fragment is outside the clip
363
377
// region in a corner. This occurs when border width is
@@ -389,7 +403,7 @@ void main(void) {
389
403
// Select color based on side of line. Get distance from the
390
404
// reference line, and then apply AA along the edge.
391
405
float ld = distance_to_line(vColorEdgeLine.xy, vColorEdgeLine.zw, local_pos);
392
- float m = smoothstep (- 0.5 * afwidth, 0.5 * afwidth , ld);
406
+ float m = smoothstep (- aa_step, aa_step , ld);
393
407
vec4 color = mix (color0, color1, m);
394
408
395
409
oFragColor = color * vec4 (1.0 , 1.0 , 1.0 , alpha);
0 commit comments