diff --git a/shaders/pp_frag.glsl b/shaders/pp_frag.glsl new file mode 100644 index 0000000..c9de194 --- /dev/null +++ b/shaders/pp_frag.glsl @@ -0,0 +1,18 @@ +#version 330 core + +struct Material { + sampler2D diffuse1; + sampler2D specular1; + float shininess; +}; + +in vec2 uv_coords; + +uniform Material material; +// uniform sampler2D image_texture; + +out vec4 color; + +void main() { + color = vec4(vec3(texture(material.diffuse1, uv_coords)), 1.0); +} diff --git a/shaders/pp_vert.glsl b/shaders/pp_vert.glsl new file mode 100644 index 0000000..5643ec6 --- /dev/null +++ b/shaders/pp_vert.glsl @@ -0,0 +1,12 @@ +#version 330 core + +layout(location=0) in vec3 position; +layout(location=1) in vec3 normal; +layout(location=2) in vec2 uv; + +out vec2 uv_coords; + +void main() { + gl_Position = vec4(position.x, position.y, 0.0, 1.0); + uv_coords = uv; +} diff --git a/src/main.cc b/src/main.cc index cadf204..47b9550 100644 --- a/src/main.cc +++ b/src/main.cc @@ -54,6 +54,7 @@ enum exit_codes : int { EXIT_CODE_WINDOW_CREATION_FAILED, EXIT_CODE_OPENGL_CONTEXT_FAILED, EXIT_CODE_GLAD_LOADER_FAILED, + EXIT_CODE_INCOMPLETE_FRAME_BUFFER, }; class Shader { @@ -135,6 +136,15 @@ class Model { std::vector load_material_textures(aiMaterial *mat, aiTextureType type); }; +struct FrameBuffer { + GLuint fbo; + GLuint color; + GLuint depth_stencil; +}; + +FrameBuffer create_frame_buffer(unsigned int width, unsigned int height); +void delete_frame_buffer(FrameBuffer &buffer); + int main() { if (SDL_Init(SDL_INIT_EVERYTHING) != 0) { return EXIT_CODE_SDL_INIT_FAILED; @@ -166,8 +176,7 @@ int main() { glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT); - glEnable(GL_DEPTH_TEST); - glEnable(GL_CULL_FACE); + FrameBuffer offscreen_buffer = create_frame_buffer(WINDOW_WIDTH, WINDOW_HEIGHT); std::vector vertices = { // positions // normals // texture coords @@ -215,8 +224,23 @@ int main() { Model backpack = {"models/suzanne/suzanne.obj"}; Mesh light = {vertices, indices, {}}; - Shader main_shader {"shaders/vert.glsl", "shaders/frag.glsl"}; - Shader light_shader {"shaders/vert.glsl", "shaders/light_frag.glsl"}; + std::vector screen_vertices = { + Vertex{glm::vec3(-1.0f, -1.0f, 0.0f), glm::vec3(1.0f, 1.0f, 1.0f), glm::vec2(0.0f, 0.0f)}, + Vertex{glm::vec3( 1.0f, -1.0f, 0.0f), glm::vec3(1.0f, 1.0f, 1.0f), glm::vec2(1.0f, 0.0f)}, + Vertex{glm::vec3(-1.0f, 1.0f, 0.0f), glm::vec3(1.0f, 1.0f, 1.0f), glm::vec2(0.0f, 1.0f)}, + Vertex{glm::vec3( 1.0f, 1.0f, 0.0f), glm::vec3(1.0f, 1.0f, 1.0f), glm::vec2(1.0f, 1.0f)}, + }; + + std::vector screen_indices = { + 0, 1, 2, + 2, 1, 3, + }; + + Mesh screen = {screen_vertices, screen_indices, {}}; + + Shader main_shader {"shaders/vert.glsl", "shaders/frag.glsl"}; + Shader light_shader {"shaders/vert.glsl", "shaders/light_frag.glsl"}; + Shader post_processing {"shaders/pp_vert.glsl", "shaders/pp_frag.glsl"}; const float camera_speed = 25.0f; glm::vec3 camera_position = glm::vec3(-2.0f, 0.0f, 6.0f); @@ -356,6 +380,10 @@ int main() { SDL_GL_GetDrawableSize(wnd, &w, &h); glViewport(0, 0, w, h); SDL_WarpMouseInWindow(wnd, (int)(w * 0.5f), (int)(h * 0.5f)); + + // Recreate offscreen frame buffer + delete_frame_buffer(offscreen_buffer); + offscreen_buffer = create_frame_buffer(w, h); } break; } @@ -375,8 +403,13 @@ int main() { main_shader.set_mat4("view", view); light_shader.set_mat4("view", view); + // Main render pass + glBindFramebuffer(GL_FRAMEBUFFER, offscreen_buffer.fbo); + glClearColor(0.04f, 0.08f, 0.08f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glEnable(GL_DEPTH_TEST); + glEnable(GL_CULL_FACE); model = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, 0.0f)); normal_mat = glm::transpose(glm::inverse(model)); @@ -395,6 +428,23 @@ int main() { light.draw(light_shader); } + // wireframe mode + // glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + + // Post processing pass + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + glClearColor(1.0f, 1.0f, 1.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); + glDisable(GL_DEPTH_TEST); + glDisable(GL_CULL_FACE); + + post_processing.activate(); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, offscreen_buffer.color); + post_processing.set_int("image_texture", 0); + screen.draw(post_processing); + SDL_GL_SwapWindow(window); } @@ -726,3 +776,43 @@ std::vector Model::load_material_textures(aiMaterial *material, aiTex return textures; } + +FrameBuffer create_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, buffer.color); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, buffer.color, 0); + + // Create depth and stencil buffers + glGenRenderbuffers(1, &buffer.depth_stencil); + glBindRenderbuffer(GL_RENDERBUFFER, buffer.depth_stencil); + glRenderbufferStorage(GL_RENDERBUFFER, 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, 0); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + + return buffer; +} + +void delete_frame_buffer(FrameBuffer &buffer) { + glDeleteFramebuffers(1, &buffer.fbo); + glDeleteTextures(1, &buffer.color); + glDeleteRenderbuffers(1, &buffer.depth_stencil); +}