From 71f6d0363562c9d80816790e5da6cd3cb8440af3 Mon Sep 17 00:00:00 2001 From: Abdelrahman Date: Mon, 30 Dec 2024 21:00:10 +0000 Subject: [PATCH] Implement Multi-Sample Anti Aliasing (MSAA) --- src/main.cc | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 93 insertions(+), 4 deletions(-) diff --git a/src/main.cc b/src/main.cc index 4897da6..9eb9e35 100644 --- a/src/main.cc +++ b/src/main.cc @@ -50,8 +50,13 @@ #define WIREFRAME 0 #define NORMALS 0 +#define MSAA 1 #define POINT_LIGHTS 1 +#if MSAA +#define MSAA_SAMPLE_COUNT 4 +#endif + enum exit_codes : int { EXIT_CODE_SUCCESS, EXIT_CODE_SDL_INIT_FAILED, @@ -149,9 +154,15 @@ struct FrameBuffer { GLuint fbo; GLuint color; GLuint depth_stencil; + GLuint width; + GLuint height; }; -FrameBuffer create_frame_buffer(unsigned int width, unsigned int height); +FrameBuffer create_normal_frame_buffer(unsigned int width, unsigned int height); +#if MSAA +FrameBuffer create_multisample_frame_buffer(unsigned int width, unsigned int height); +void blit_multisample_frame_buffer(const FrameBuffer &multisample_buffer, const FrameBuffer &normal_buffer); +#endif void delete_frame_buffer(FrameBuffer &buffer); GLuint load_cubemap(std::vector textures); @@ -166,6 +177,11 @@ int main() { SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); +#if MSAA + SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1); + SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, MSAA_SAMPLE_COUNT); +#endif + SDL_Window *window = SDL_CreateWindow("Window", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE); if (!window) { @@ -181,12 +197,21 @@ int main() { return EXIT_CODE_GLAD_LOADER_FAILED; } +#if MSAA + glEnable(GL_MULTISAMPLE); +#endif + SDL_SetRelativeMouseMode(SDL_TRUE); SDL_WarpMouseInWindow(window, WINDOW_HALF_WIDTH, WINDOW_HALF_HEIGHT); glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT); - FrameBuffer offscreen_buffer = create_frame_buffer(WINDOW_WIDTH, WINDOW_HEIGHT); +#if MSAA + FrameBuffer multisample_buffer = create_multisample_frame_buffer(WINDOW_WIDTH, WINDOW_HEIGHT); + FrameBuffer offscreen_buffer = create_normal_frame_buffer(WINDOW_WIDTH, WINDOW_HEIGHT); +#else + FrameBuffer offscreen_buffer = create_normal_frame_buffer(WINDOW_WIDTH, WINDOW_HEIGHT); +#endif std::vector vertices = { // positions // normals // texture coords @@ -497,7 +522,11 @@ int main() { // Recreate offscreen frame buffer delete_frame_buffer(offscreen_buffer); - offscreen_buffer = create_frame_buffer(w, h); + offscreen_buffer = create_normal_frame_buffer(w, h); +#if MSAA + delete_frame_buffer(multisample_buffer); + multisample_buffer = create_multisample_frame_buffer(w, h); +#endif } break; } @@ -523,7 +552,11 @@ int main() { skybox_shader.set_mat4("sb_view", glm::mat4(glm::mat3(view))); // Main render pass +#if MSAA + glBindFramebuffer(GL_FRAMEBUFFER, multisample_buffer.fbo); +#else glBindFramebuffer(GL_FRAMEBUFFER, offscreen_buffer.fbo); +#endif glClearColor(0.04f, 0.08f, 0.08f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); @@ -578,6 +611,10 @@ int main() { glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); #endif +#if MSAA + blit_multisample_frame_buffer(multisample_buffer, offscreen_buffer); +#endif + // Post processing pass glBindFramebuffer(GL_FRAMEBUFFER, 0); @@ -959,7 +996,7 @@ std::vector Model::load_material_textures(aiMaterial *material, aiTex return textures; } -FrameBuffer create_frame_buffer(unsigned int width, unsigned int height) { +FrameBuffer create_normal_frame_buffer(unsigned int width, unsigned int height) { FrameBuffer buffer = {}; glGenFramebuffers(1, &buffer.fbo); @@ -990,9 +1027,61 @@ FrameBuffer create_frame_buffer(unsigned int width, unsigned int height) { glBindTexture(GL_TEXTURE_2D, 0); glBindRenderbuffer(GL_RENDERBUFFER, 0); + buffer.width = width; + buffer.height = height; + return buffer; } +#if MSAA +FrameBuffer create_multisample_frame_buffer(unsigned int width, unsigned int height) { + FrameBuffer buffer = {}; + + glGenFramebuffers(1, &buffer.fbo); + glBindFramebuffer(GL_FRAMEBUFFER, buffer.fbo); + + // Create color texture + glGenTextures(1, &buffer.color); + glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, buffer.color); + glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, MSAA_SAMPLE_COUNT, GL_RGB, width, height, GL_TRUE); + glTexParameteri(GL_TEXTURE_2D_MULTISAMPLE, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D_MULTISAMPLE, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, buffer.color, 0); + + // Create depth and stencil buffers + glGenRenderbuffers(1, &buffer.depth_stencil); + glBindRenderbuffer(GL_RENDERBUFFER, buffer.depth_stencil); + glRenderbufferStorageMultisample(GL_RENDERBUFFER, MSAA_SAMPLE_COUNT, GL_DEPTH24_STENCIL8, width, height); + + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, buffer.depth_stencil); + + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { + printf("Incomplete frame buffer\n"); + exit(EXIT_CODE_INCOMPLETE_FRAME_BUFFER); + } + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + + buffer.width = width; + buffer.height = height; + + return buffer; +} + +void blit_multisample_frame_buffer(const FrameBuffer &multisample_buffer, const FrameBuffer &normal_buffer) { + glBindFramebuffer(GL_READ_FRAMEBUFFER, multisample_buffer.fbo); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, normal_buffer.fbo); + glBlitFramebuffer( + 0, 0, multisample_buffer.width, multisample_buffer.height, + 0, 0, normal_buffer.width, normal_buffer.height, + GL_COLOR_BUFFER_BIT, GL_NEAREST + ); +} +#endif + void delete_frame_buffer(FrameBuffer &buffer) { glDeleteFramebuffers(1, &buffer.fbo); glDeleteTextures(1, &buffer.color);