Search code examples
graphicsglslshaderwebgl

How to perform smoothstep antialiasing with rounded rectangles?


I'm drawing a rounded rectangle with a GLSL shader using the following pixel shader:

float roundedBoxSDF(vec2 center, vec2 size, float radius) {
  return length(max(abs(center) - size + radius, 0.0)) - radius;
}

void main() {
  float edgeSoftness = 1.0;
  float distance = roundedBoxSDF(v_pos.xy - v_loc - (v_size / 2.0), v_size / 2.0, v_border_radius);
  float smoothing = smoothstep(0.0, edgeSoftness * 2.0, distance);

  outputColor = mix(vec4(0), v_color, 1.0 - smoothing);
}

and the corner looks like this at the moment:

enter image description here

Notice the black streak. I think it has to do with the vec4(0) in the final line, because if I change that to vec4(1, 1, 1, 0), then I get the following result:

enter image description here

Even more unsightly. What am I doing wrong? If I change edgeSoftness to 0.0, then it looks decent:

enter image description here

But it doesn't have any anti-aliasing. Is there any way to have an anti-aliased rounded rectangle without the unsightly edges? I'm not sure what I'm doing wrong.


Solution

  • The issue you see is because you are interpolating from solid base color to transparent black. Now, for the pixels in-between the interpolation, that are not yet fully transparent, the base color will still be slightly shifted towards black and you will get the results you see. What you likely want to do is keep the RGB values for the base color, and only change the alpha channel.

    outputColor = vec4(v_color.rgb, mix(v_color.a, 0., smoothing));