2
$\begingroup$

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;
}

How to apply Anti-Aliasing? from this to this.

$\endgroup$
2
  • $\begingroup$ This might sound like it is a specific question, but it is actually extremely broad. Do you want a solution specific to this problem? Or something more general? In which case there are many choices. FSAA, Morphological, MSAA, TXAA, this list goes on and on. $\endgroup$
    – pmw1234
    Commented May 29, 2022 at 19:48
  • $\begingroup$ @pmw1234 All Anti-Alias articles I've found so far aren't beginner friendly. So I want to start from simplest technique and build upon it. I want a solution specific to this problem. $\endgroup$ Commented May 30, 2022 at 3:13

2 Answers 2

1
$\begingroup$

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;

}
$\endgroup$
3
$\begingroup$

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);
$\endgroup$
4
  • 1
    $\begingroup$ This is a great technique. I used something almost exactly like this on a low end SOC (commercial project) at low resolution (~720p) and the results were near perfect. $\endgroup$
    – PaulHK
    Commented May 30, 2022 at 11:25
  • $\begingroup$ @PaulHK Yep, in most cases when rendering simple geometry like lines & circles one can do manual AA without heavy MSAA or similar stuff. $\endgroup$
    – lisyarus
    Commented May 30, 2022 at 14:30
  • $\begingroup$ This works well because the implicit function is essentially the distance to the object. In general, you need to use the distance function or an approximation. See math.stackexchange.com/questions/59034/… $\endgroup$
    – lhf
    Commented May 30, 2022 at 21:33
  • $\begingroup$ @lhf Naturally. However, the OP asked specifically about a circle. $\endgroup$
    – lisyarus
    Commented May 31, 2022 at 8:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.