Have a fragment shader:
// simply set all pixel white if inside unit circle else transparent.
#pragma fragment frag
float4 frag(float4 Pos : SV_POSITION) : SV_TARGET
{
return Pos.x * Pos.x + Pos.y * Pos.y <= 1;
}
Have a fragment shader:
// simply set all pixel white if inside unit circle else transparent.
#pragma fragment frag
float4 frag(float4 Pos : SV_POSITION) : SV_TARGET
{
return Pos.x * Pos.x + Pos.y * Pos.y <= 1;
}
The "big idea" around most anti aliasing algorithms is taking multiple samples in the region around the fragment in question. These can range from very simple above/below to random samples to complex heuristics.
Another issue is the distance that those samples are taken from the original fragment. Here again it can range from simple fixed distance to "smart" heuristics.
Last but not least is weighting the samples taken. And as you can guess this ranges from a simple average, to weights that compute the distance to other fragments and many other schemes. (weights are like CPU TLB algorithms, everyone has a better one, but we always use the generic version because its good enough)
There is also the issue of diminishing returns where taking more samples doesn't really help the final output.
I wrote a shader toy that demonstrates basic antialiasing using an ellipse (partly because I was to lazy to adjust for aspect ratio) and is very similar to the sample you submitted with your question. Also, I tried to make it easy to change the sampling and turn sampling on/off.
The shader toy can be found here.
Here is the code of the shader toy:
// Comment this out to turn of sampling
#define do_samples
// Average the samples together
float num_samples =0.0;
vec4 GetFragValAt( vec2 uv )
{
num_samples += 1.0;
// dot is same as uv.x*uv.x+uv.y*uv.y
return vec4( dot( uv, uv) <= 0.4);
}
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
// Normalized pixel coordinates (from -1 to 1)
vec2 uv = fragCoord/iResolution.xy*2.0-1.0;
// Change offset to adjust sampling distance
float offset = 0.002;
fragColor = GetFragValAt( uv );
#ifdef do_samples
// samples in +/- x direction
fragColor += GetFragValAt(uv + vec2( offset, 0.0));
fragColor += GetFragValAt(uv + vec2( -offset, 0.0));
// samples in +/- y direction
fragColor += GetFragValAt(uv + vec2( 0.0, offset ));
fragColor += GetFragValAt(uv + vec2( 0.0, -offset));
// samples at diagonals
fragColor += GetFragValAt(uv + vec2(offset, offset));
fragColor += GetFragValAt(uv + vec2(-offset, offset));
fragColor += GetFragValAt(uv + vec2(offset, -offset));
fragColor += GetFragValAt(uv + vec2(-offset, -offset));
#endif
// compute average
fragColor /= num_samples;
}
Probably the simplest way is to use smoothstep to make a transition from white to black:
float R = 0.5 / ScreenSize; // you'll have to pass or hardcode it
return smoothstep(Pos.x * Pos.x + Pos.y * Pos.y, 1.0 - R, 1.0 + R);