From 95d845bce5e39a9d997a400f00ddb5497fde5768 Mon Sep 17 00:00:00 2001 From: Nigel Date: Thu, 20 Oct 2022 15:40:28 +0200 Subject: [PATCH] PostProcessing --- postprocessing.fs | 45 ++++++++++++++++ postprocessing.vs | 36 +++++++++++++ src/game.cpp | 47 ++++++++++++---- src/postprocessor.cpp | 123 ++++++++++++++++++++++++++++++++++++++++++ src/postprocessor.h | 32 +++++++++++ 5 files changed, 273 insertions(+), 10 deletions(-) create mode 100644 postprocessing.fs create mode 100644 postprocessing.vs create mode 100644 src/postprocessor.cpp create mode 100644 src/postprocessor.h diff --git a/postprocessing.fs b/postprocessing.fs new file mode 100644 index 0000000..f3d7372 --- /dev/null +++ b/postprocessing.fs @@ -0,0 +1,45 @@ +#version 330 core +in vec2 TexCoords; +out vec4 color; + +uniform sampler2D scene; +uniform vec2 offsets[9]; +uniform int edge_kernel[9]; +uniform float blur_kernel[9]; + +uniform bool chaos; +uniform bool confuse; +uniform bool shake; + + +void main () +{ + color = vec4(0.0, 0.0,0.0,1.0); + vec3 sample[9]; + + if(chaos || shake) + for (int i = 0; i < 9; i++) + sample[i] = vec3(texture(scene,TexCoords.st + offsets[i])); + + // process effects + if (chaos) + { + for(int i = 0; i < 9; i ++) + color += vec4(sample[i] * edge_kernel[i], 0.0); + color.a = 1.0; + } + else if (confuse) + { + color = vec4(1.0 - texture(scene, TexCoords).rgb, 1.0); + } + else if (shake) + { + for (int i = 0; i < 9; i++) + color += vec4(sample[i] * blur_kernel[i], 0.0); + color.a = 1.0; + } + else + { + color = texture(scene, TexCoords); + } +} \ No newline at end of file diff --git a/postprocessing.vs b/postprocessing.vs new file mode 100644 index 0000000..303470d --- /dev/null +++ b/postprocessing.vs @@ -0,0 +1,36 @@ +#version 330 core +layout (location = 0) in vec4 vertex; + +out vec2 TexCoords; + +uniform bool chaos; +uniform bool confuse; +uniform bool shake; +uniform float time; + +void main() +{ + gl_Position = vec4(vertex.xy, 0.0, 1.0); + vec2 texture = vertex.zw; + if( chaos) + { + float strength = 0.3; + vec2 pos = vec2(texture.x + sin(time) * strength, texture.y + cos(time) * strength); + TexCoords = pos; + } + else if (confuse) + { + TexCoords = vec2(1.0 - texture.x, 1.0 - texture.y); + } + else + { + TexCoords = texture; + } + + if(shake) + { + float strength = 0.01; + gl_Position.x += cos(time * 10) * strength; + gl_Position.y += cos(time * 15) * strength; + } +} \ No newline at end of file diff --git a/src/game.cpp b/src/game.cpp index 4f8e63e..9ab2675 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -1,5 +1,6 @@ #include "game.h" #include "particleGenerator.h" +#include "postprocessor.h" #include #include @@ -7,6 +8,7 @@ typedef std::tuple Collision; ParticleGenerator* Particles; SpriteRenderer* Renderer; +PostProcessor* effects; // Initial size of the player paddle const glm::vec2 PLAYER_SIZE (100.0f, 20.0f); @@ -89,6 +91,7 @@ Game::~Game() delete player; delete ball; delete Particles; + delete effects; } Game::Game(unsigned int width, unsigned int height) @@ -102,13 +105,17 @@ void Game::Init() // Load shaders ResourceManager::LoadShader("shader.vs", "shader.fs", nullptr, "sprite"); ResourceManager::LoadShader("particle.vs", "particle.fs", nullptr, "particle"); + ResourceManager::LoadShader("postprocessing.vs", "postprocessing.fs", nullptr, "postprocessing"); // configure shaders glm::mat4 projection = glm::ortho(0.0f, static_cast(this->Width), static_cast(this->Height), 0.0f, -1.0f, 1.0f); ResourceManager::GetShader("sprite").Use().SetInteger("image", 0); ResourceManager::GetShader("sprite").SetMatrix4("projection", projection); - ResourceManager::GetShader("particle").Use().SetMatrix4("projection", projection); + ResourceManager::GetShader("particle").Use().SetInteger("sprite", 0); + ResourceManager::GetShader("particle").SetMatrix4("projection", projection); // set render-specific controls Renderer = new SpriteRenderer(ResourceManager::GetShader("sprite")); + Particles = new ParticleGenerator(ResourceManager::GetShader("particle"), ResourceManager::GetTexture("particle"), 500); + effects = new PostProcessor(ResourceManager::GetShader("postprocessing"), this->Width, this->Height); // load textures ResourceManager::LoadTexture("textures/awesomeface.png", true, "face"); ResourceManager::LoadTexture("textures/background.jpg", false, "background"); @@ -135,10 +142,10 @@ void Game::Init() ball = new BallObject(ballPos, BALL_RADIUS, INITIAL_BALL_VELOCITY, ResourceManager::GetTexture("face")); - Particles = new ParticleGenerator(ResourceManager::GetShader("particle"), ResourceManager::GetTexture("particle"), 500); } +float ShakeTime = 0.0f; void Game::DoCollisions() { @@ -153,6 +160,11 @@ void Game::DoCollisions() { box.Destroyed = true; } + else + { + ShakeTime = 0.05f; + effects->Shake = true; + } // Collision resolution Direction dir = std::get<1>(collision); glm::vec2 diff_vector = std::get<2>(collision); @@ -236,28 +248,43 @@ void Game::Update(float dt) this->DoCollisions(); Particles->Update(dt, *ball, 2, glm::vec2(ball->Radius /2.0f)); + + if(ShakeTime > 0.0f) + { + ShakeTime -= dt; + if (ShakeTime <= 0.0f) + effects->Shake = false; + } if(ball->Position.y >= this->Height) { this->ResetLevel(); this->ResetPlayer(); } + + } void Game::Render() { if(this->State == GAME_ACTIVE) { - // draw background - Renderer->DrawSprite(ResourceManager::GetTexture("background"), - glm::vec2(0.0f, 0.0f), glm::vec2(this->Width, this->Height), 0.0f); + effects->BeginRender(); + // draw background + Renderer->DrawSprite(ResourceManager::GetTexture("background"), + glm::vec2(0.0f, 0.0f), glm::vec2(this->Width, this->Height), 0.0f); - // draw level - this->Levels[this->Level].Draw(*Renderer); + // draw level + this->Levels[this->Level].Draw(*Renderer); + // draw player + player->Draw(*Renderer); + // draw particles + Particles->Draw(); + // draw ball + ball->Draw(*Renderer); - player->Draw(*Renderer); - Particles->Draw(); - ball->Draw(*Renderer); + effects->EndRender(); + effects->Render(glfwGetTime()); } } diff --git a/src/postprocessor.cpp b/src/postprocessor.cpp new file mode 100644 index 0000000..7a6fa13 --- /dev/null +++ b/src/postprocessor.cpp @@ -0,0 +1,123 @@ +#include "postprocessor.h" +#include + +PostProcessor::PostProcessor(Shader shader, unsigned int width, unsigned int height) +: postProcessingShader(shader), Texture(), Width(width), Height(height), Confuse(false), Chaos(false), Shake(false) +{ + // initialize renderbuffer & framebuffer objects + glGenFramebuffers(1, &this->MSFBO); + glGenFramebuffers(1, &this->FBO); + glGenRenderbuffers(1, &this->RBO); + + // initialize renderbuffer storage + glBindFramebuffer(GL_FRAMEBUFFER, this->MSFBO); + glBindRenderbuffer(GL_RENDERBUFFER, this->RBO); + glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_RGB, width, height); + // attach the renderbuffer to our framebuffer as a colour attachment + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, this->RBO); + + if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + { + std::cout << "ERROR::POSTPROCESSOR: Failed to initialize MSFBO" << std::endl; + } + + // init fbo & texture to lit multisampled color-buffer to + glBindFramebuffer(GL_FRAMEBUFFER, this->FBO); + this->Texture.Generate(width, height, NULL); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, this->Texture.ID, 0); + + if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + { + std::cout << "ERROR::POSTPROCESOR: Failed to initialize FBO" << std::endl; + } + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + this->initRenderData(); + this->postProcessingShader.SetInteger("scene", 0 , true); + float offset = 1.0f/ 300.0f; + float offsets[9][2] = { + { -offset, offset }, // top-left + { 0.0f, offset }, // top-center + { offset, offset }, // top-right + { -offset, 0.0f }, // center-left + { 0.0f, 0.0f }, // center-center + { offset, 0.0f }, // center - right + { -offset, -offset }, // bottom-left + { 0.0f, -offset }, // bottom-center + { offset, -offset } // bottom-right + }; + glUniform2fv(glGetUniformLocation(this->postProcessingShader.ID, "offsets"), 9, (float*)offsets); + + int edge_kernel[9] = { + -1, -1, -1, + -1, 8, -1, + -1, -1, -1 + }; + glUniform1iv(glGetUniformLocation(this->postProcessingShader.ID, "edge_kernel"), 9, edge_kernel); + + float blur_kernel[9] = { + 1.0f / 16.0f, 2.0f / 16.0f, 1.0f / 16.0f, + 2.0f / 16.0f, 4.0f / 16.0f, 2.0f / 16.0f, + 1.0f / 16.0f, 2.0f / 16.0f, 1.0f / 16.0f + }; + glUniform1fv(glGetUniformLocation(this->postProcessingShader.ID, "blur_kernel"), 9, blur_kernel); +} + +void PostProcessor::BeginRender() +{ + glBindFramebuffer(GL_FRAMEBUFFER, this->MSFBO); + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); +} + +void PostProcessor::EndRender() +{ + // Resolves multisampled texture into intermediat FBO for the texture + glBindFramebuffer(GL_READ_FRAMEBUFFER, this->MSFBO); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, this->FBO); + glBlitFramebuffer(0,0, this->Width, this->Height, 0, 0, this->Width, this->Height, GL_COLOR_BUFFER_BIT, GL_NEAREST); + glBindFramebuffer(GL_FRAMEBUFFER, 0); +} + +void PostProcessor::Render(float time) +{ + this->postProcessingShader.Use(); + this->postProcessingShader.SetFloat("time", time); + this->postProcessingShader.SetInteger("confuse", this->Confuse); + this->postProcessingShader.SetInteger("chaos", this->Chaos); + this->postProcessingShader.SetInteger("shake", this->Shake); + + // render textured quad + glActiveTexture(GL_TEXTURE0); + this->Texture.Bind(); + glBindVertexArray(this->VAO); + glDrawArrays(GL_TRIANGLES, 0, 6); + glBindVertexArray(0); +} + +void PostProcessor::initRenderData() +{ + unsigned int VBO; + float vertices[] = { + -1.0f, -1.0f, 0.0f, 0.0f, + 1.0f, 1.0f, 1.0f, 1.0f, + -1.0f, 1.0f, 0.0f, 1.0f, + + -1.0f, -1.0f, 0.0f, 0.0f, + 1.0f, -1.0f, 1.0f, 0.0f, + 1.0f, 1.0f, 1.0f, 1.0f + }; + + glGenVertexArrays(1, &this->VAO); + glGenBuffers(1, &VBO); + + glBindBuffer(GL_ARRAY_BUFFER, VBO); + glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); + + glBindVertexArray(this->VAO); + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*) 0); + glBindBuffer(GL_ARRAY_BUFFER,0); + glBindVertexArray(0); + +} \ No newline at end of file diff --git a/src/postprocessor.h b/src/postprocessor.h new file mode 100644 index 0000000..b6e7990 --- /dev/null +++ b/src/postprocessor.h @@ -0,0 +1,32 @@ +#pragma once + +#include +#include + +#include "texture2d.h" +#include "spriterenderer.h" +#include "shader.h" + +class PostProcessor +{ + public: + Shader postProcessingShader; + Texture2D Texture; + unsigned int Width, Height; + + bool Confuse, Chaos, Shake; + + PostProcessor(Shader shader, unsigned int width, unsigned int height); + + void BeginRender(); + + void EndRender(); + + void Render(float time); + private: + unsigned int MSFBO, FBO; // MSFBO = Multisample frame buffer object + unsigned int RBO; + unsigned int VAO; + + void initRenderData(); +}; \ No newline at end of file