In this tutorial I'll show you what Anti-Aliasing is and how
you can implement it in your OpenGL project. So you might have noticed that while horizontal
and vertical edges look extremely crisp, diagonal edges tend to look a bit choppy,
like a flight of stairs. This is due to how we display images on our screens.
Since our displays are made out of a bunch of tiny squares, aka pixels, it is impossible to have a
smooth line on the diagonal. But thankfully, we can fake smoothness by bleeding the color
of an edge into the adjacent pixels like so. Now, these jagged edges are called Aliasing,
and an Anti-Aliasing technique is what helps us get better edges. There are multiple techniques
for Anti-Aliasing each with their advantages and disadvantages, but today I'll focus on MSAA
which stands for Multi Sampling Anti-Aliasing. So what does this Multi Sampling refer too?
Well in the rasterization part of the pipeline primitives are filled in. The way it is decided
which pixels should be given a color and which should not, is by checking if the sample point
of a pixel, which is normally in the center of it, is inside the shape of the primitive. This means
that if the sample point is even just slightly outside the triangle, it won't get sampled,
even though you would think it should at least do so partially. Well, that is where MSAA comes in.
As you might have guessed, this technique simply adds multiple sampling points so
that a more accurate result can be reached. Here for example, two out of the 4 sampling points
are inside the triangle, and so the color of that pixel will be somewhere between the color of the
background and the color of the primitive. Now let's actually implement this. Let's start
off by creating a variable where we specify how many samples we desire. Now, if you don't have a
framebuffer, then you can just give a window hint to GLFW saying you want GLFW_SAMPLES and then the
number of samples you want, and then activate GL_MULTISAMPLE. That was it for this tutorial,
as... nah I'm joking. But for real though, if you don't have a framebuffer that's all
you have to do, you are done. If you do have a framebuffer, then you'll want to delete the
GLFW part. Instead you need to go to your framebuffer and replace all GL_TEXTURE_2D
with GL_TEXTURE_2D_MULTISAMPLE. Then replace glTexImage2D with glTexImage2DMultisamples,
plugging in the type of texture, the number of samples, the color format, the width, the height,
and whether or not you want all samples to be in the exact same position in the pixels.
Then for the renderbuffer object we need to change from glRenderbufferStorage
to glRenderbufferStorageMultismaple and add the number of samples we want.
Now the problem is that we can't do any sort of post-processing on this framebuffer anymore
since it has multisampling enabled. So to get around that we'll need a normal framebuffer
which we can post-process. This is just like the one I made in the framebuffer tutorial.
Now in the main function we want to make sure we first bind the multisampling FBO,
clear the screen, clear the buffers, and enable depth testing. Then we draw everything we want
to draw. After that we bind the multisampling FBO as read only, and the postprocessing FBO as
draw only. Now using glBlitFramebuffer we'll resolve all the multisampling and copy the result
onto the post-processing FBO. Now make sure you bind the default
framebuffer and draw the framebuffer rectangle using the postprocessing texture. Run the program
and you'll see that the edges of primitives are a lot smoother and nicer. Just be aware
that applying kernels in the post processing will essentially overwrite the anti aliasing and so
you may end up with aliasing again. As for the number of samples you should use,
I suggest using either 2, 4, or 8. You can go up to 16 and 32 on some GPUs but the
improvement/performance ratio is not worth it. That was it for this tutorial, as always
the source code and all resources used are in the description. Bye!