From 8ed65ca51e7eca35a25642b3a6103e8aa2e8d852 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Fri, 8 Mar 2024 21:49:38 +0300 Subject: [PATCH] post-processing test --- res/shaders/screen.glslf | 13 ++ res/shaders/screen.glslv | 12 ++ src/assets/AssetsLoader.cpp | 1 + src/frontend/WorldRenderer.cpp | 210 +++++++++++++++++--------------- src/frontend/WorldRenderer.h | 3 +- src/graphics/Framebuffer.cpp | 12 +- src/graphics/Framebuffer.h | 39 ++++-- src/graphics/GfxContext.cpp | 2 +- src/graphics/PostProcessing.cpp | 42 +++++++ src/graphics/PostProcessing.h | 37 ++++++ src/graphics/Shader.cpp | 5 + src/graphics/Shader.h | 1 + src/graphics/Viewport.h | 4 +- 13 files changed, 268 insertions(+), 113 deletions(-) create mode 100644 res/shaders/screen.glslf create mode 100644 res/shaders/screen.glslv create mode 100644 src/graphics/PostProcessing.cpp create mode 100644 src/graphics/PostProcessing.h diff --git a/res/shaders/screen.glslf b/res/shaders/screen.glslf new file mode 100644 index 00000000..a3bb7ff9 --- /dev/null +++ b/res/shaders/screen.glslf @@ -0,0 +1,13 @@ +in vec2 v_coord; +out vec4 f_color; + +uniform sampler2D u_texture0; +uniform float u_timer; + +void main(){ + vec2 coord = v_coord; + coord.x += sin(u_timer*5.0+coord.x*4.0) * 0.02; + coord.y += cos(u_timer*5.0+coord.y*4.0) * 0.02; + f_color = texture(u_texture0, coord); +} + diff --git a/res/shaders/screen.glslv b/res/shaders/screen.glslv new file mode 100644 index 00000000..772e5f06 --- /dev/null +++ b/res/shaders/screen.glslv @@ -0,0 +1,12 @@ +layout (location = 0) in vec2 v_position; + +out vec2 v_coord; + +uniform ivec2 u_screenSize; +uniform float u_timer; + +void main(){ + v_coord = v_position * 0.5 + 0.5; + gl_Position = vec4(v_position, 0.0, 1.0); +} + diff --git a/src/assets/AssetsLoader.cpp b/src/assets/AssetsLoader.cpp index 16bf1afc..fe837533 100644 --- a/src/assets/AssetsLoader.cpp +++ b/src/assets/AssetsLoader.cpp @@ -74,6 +74,7 @@ void AssetsLoader::addDefaults(AssetsLoader& loader, const Content* content) { loader.add(ASSET_TEXTURE, TEXTURES_FOLDER"/gui/cross.png", "gui/cross"); if (content) { loader.add(ASSET_SHADER, SHADERS_FOLDER"/ui3d", "ui3d"); + loader.add(ASSET_SHADER, SHADERS_FOLDER"/screen", "screen"); loader.add(ASSET_SHADER, SHADERS_FOLDER"/background", "background"); loader.add(ASSET_SHADER, SHADERS_FOLDER"/skybox_gen", "skybox_gen"); loader.add(ASSET_TEXTURE, TEXTURES_FOLDER"/misc/moon.png", "misc/moon"); diff --git a/src/frontend/WorldRenderer.cpp b/src/frontend/WorldRenderer.cpp index cfd25b56..69888891 100644 --- a/src/frontend/WorldRenderer.cpp +++ b/src/frontend/WorldRenderer.cpp @@ -14,6 +14,7 @@ #include "../graphics/Batch3D.h" #include "../graphics/Texture.h" #include "../graphics/LineBatch.h" +#include "../graphics/PostProcessing.h" #include "../voxels/Chunks.h" #include "../voxels/Chunk.h" #include "../voxels/Block.h" @@ -39,6 +40,7 @@ WorldRenderer::WorldRenderer(Engine* engine, LevelFrontend* frontend, Player* pl level(frontend->getLevel()), player(player) { + postProcessing = std::make_unique(); frustumCulling = std::make_unique(); lineBatch = std::make_unique(); renderer = std::make_unique( @@ -139,8 +141,6 @@ void WorldRenderer::drawChunks(Chunks* chunks, Camera* camera, Shader* shader) { void WorldRenderer::draw(const GfxContext& pctx, Camera* camera, bool hudVisible){ EngineSettings& settings = engine->getSettings(); - - Window::clearDepth(); skybox->refresh(pctx, level->world->daytime, 1.0f+fog*2.0f, 4); const Content* content = level->content; @@ -153,116 +153,136 @@ void WorldRenderer::draw(const GfxContext& pctx, Camera* camera, bool hudVisible const Viewport& viewport = pctx.getViewport(); int displayWidth = viewport.getWidth(); int displayHeight = viewport.getHeight(); - - // Drawing background sky plane - skybox->draw(pctx, camera, assets, level->getWorld()->daytime, fog); - // Actually world render with depth buffer on + // World render scope with diegetic HUD included { - GfxContext ctx = pctx.sub(); - ctx.setDepthTest(true); - ctx.setCullFace(true); + GfxContext wctx = pctx.sub(); + postProcessing->use(wctx); - float fogFactor = 15.0f / ((float)settings.chunks.loadDistance-2); + Window::clearDepth(); - // Setting up main shader - shader->use(); - shader->uniformMatrix("u_proj", camera->getProjection()); - shader->uniformMatrix("u_view", camera->getView()); - shader->uniform1f("u_gamma", settings.graphics.gamma); - shader->uniform1f("u_fogFactor", fogFactor); - shader->uniform1f("u_fogCurve", settings.graphics.fogCurve); - shader->uniform1f("u_dayTime", level->world->daytime); - shader->uniform3f("u_cameraPos", camera->position); - shader->uniform1i("u_cubemap", 1); - - // Light emission when an emissive item is chosen + // Drawing background sky plane + skybox->draw(pctx, camera, assets, level->getWorld()->daytime, fog); + + // Actually world render with depth buffer on { - auto inventory = player->getInventory(); - ItemStack& stack = inventory->getSlot(player->getChosenSlot()); - auto item = indices->getItemDef(stack.getItemId()); - float multiplier = 0.5f; - shader->uniform3f("u_torchlightColor", - item->emission[0] / 15.0f * multiplier, - item->emission[1] / 15.0f * multiplier, - item->emission[2] / 15.0f * multiplier - ); - shader->uniform1f("u_torchlightDistance", 6.0f); + GfxContext ctx = wctx.sub(); + ctx.setDepthTest(true); + ctx.setCullFace(true); + + float fogFactor = 15.0f / ((float)settings.chunks.loadDistance-2); + + // Setting up main shader + shader->use(); + shader->uniformMatrix("u_proj", camera->getProjection()); + shader->uniformMatrix("u_view", camera->getView()); + shader->uniform1f("u_gamma", settings.graphics.gamma); + shader->uniform1f("u_fogFactor", fogFactor); + shader->uniform1f("u_fogCurve", settings.graphics.fogCurve); + shader->uniform1f("u_dayTime", level->world->daytime); + shader->uniform3f("u_cameraPos", camera->position); + shader->uniform1i("u_cubemap", 1); + + // Light emission when an emissive item is chosen + { + auto inventory = player->getInventory(); + ItemStack& stack = inventory->getSlot(player->getChosenSlot()); + auto item = indices->getItemDef(stack.getItemId()); + float multiplier = 0.5f; + shader->uniform3f("u_torchlightColor", + item->emission[0] / 15.0f * multiplier, + item->emission[1] / 15.0f * multiplier, + item->emission[2] / 15.0f * multiplier + ); + shader->uniform1f("u_torchlightDistance", 6.0f); + } + + // Binding main shader textures + skybox->bind(); + atlas->getTexture()->bind(); + + drawChunks(level->chunks.get(), camera, shader); + + // Selected block + if (PlayerController::selectedBlockId != -1 && hudVisible){ + blockid_t id = PlayerController::selectedBlockId; + auto block = indices->getBlockDef(id); + const glm::vec3 pos = PlayerController::selectedBlockPosition; + const glm::vec3 point = PlayerController::selectedPointPosition; + const glm::vec3 norm = PlayerController::selectedBlockNormal; + + std::vector& hitboxes = block->rotatable + ? block->rt.hitboxes[PlayerController::selectedBlockStates] + : block->hitboxes; + + linesShader->use(); + linesShader->uniformMatrix("u_projview", camera->getProjView()); + lineBatch->lineWidth(2.0f); + for (auto& hitbox: hitboxes) { + const glm::vec3 center = pos + hitbox.center(); + const glm::vec3 size = hitbox.size(); + lineBatch->box(center, size + glm::vec3(0.02), glm::vec4(0.f, 0.f, 0.f, 0.5f)); + if (player->debug) { + lineBatch->line(point, point+norm*0.5f, glm::vec4(1.0f, 0.0f, 1.0f, 1.0f)); + } + } + lineBatch->render(); + } + skybox->unbind(); } - // Binding main shader textures - skybox->bind(); - atlas->getTexture()->bind(); - - drawChunks(level->chunks.get(), camera, shader); - - // Selected block - if (PlayerController::selectedBlockId != -1 && hudVisible){ - blockid_t id = PlayerController::selectedBlockId; - auto block = indices->getBlockDef(id); - const glm::vec3 pos = PlayerController::selectedBlockPosition; - const glm::vec3 point = PlayerController::selectedPointPosition; - const glm::vec3 norm = PlayerController::selectedBlockNormal; - - std::vector& hitboxes = block->rotatable - ? block->rt.hitboxes[PlayerController::selectedBlockStates] - : block->hitboxes; + if (hudVisible && player->debug) { + GfxContext ctx = pctx.sub(); + ctx.setDepthTest(true); linesShader->use(); - linesShader->uniformMatrix("u_projview", camera->getProjView()); - lineBatch->lineWidth(2.0f); - for (auto& hitbox: hitboxes) { - const glm::vec3 center = pos + hitbox.center(); - const glm::vec3 size = hitbox.size(); - lineBatch->box(center, size + glm::vec3(0.02), glm::vec4(0.f, 0.f, 0.f, 0.5f)); - if (player->debug) { - lineBatch->line(point, point+norm*0.5f, glm::vec4(1.0f, 0.0f, 1.0f, 1.0f)); - } + + if (settings.debug.showChunkBorders){ + linesShader->uniformMatrix("u_projview", camera->getProjView()); + glm::vec3 coord = player->camera->position; + if (coord.x < 0) coord.x--; + if (coord.z < 0) coord.z--; + int cx = floordiv((int)coord.x, CHUNK_W); + int cz = floordiv((int)coord.z, CHUNK_D); + + drawBorders(cx * CHUNK_W, 0, cz * CHUNK_D, + (cx + 1) * CHUNK_W, CHUNK_H, (cz + 1) * CHUNK_D); } + + float length = 40.f; + glm::vec3 tsl(displayWidth/2, displayHeight/2, 0.f); + glm::mat4 model(glm::translate(glm::mat4(1.f), tsl)); + linesShader->uniformMatrix("u_projview", glm::ortho( + 0.f, (float)displayWidth, + 0.f, (float)displayHeight, + -length, length) * model * glm::inverse(camera->rotation)); + + ctx.setDepthTest(false); + lineBatch->lineWidth(4.0f); + lineBatch->line(0.f, 0.f, 0.f, length, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f); + lineBatch->line(0.f, 0.f, 0.f, 0.f, length, 0.f, 0.f, 0.f, 0.f, 1.f); + lineBatch->line(0.f, 0.f, 0.f, 0.f, 0.f, length, 0.f, 0.f, 0.f, 1.f); + lineBatch->render(); + + ctx.setDepthTest(true); + lineBatch->lineWidth(2.0f); + lineBatch->line(0.f, 0.f, 0.f, length, 0.f, 0.f, 1.f, 0.f, 0.f, 1.f); + lineBatch->line(0.f, 0.f, 0.f, 0.f, length, 0.f, 0.f, 1.f, 0.f, 1.f); + lineBatch->line(0.f, 0.f, 0.f, 0.f, 0.f, length, 0.f, 0.f, 1.f, 1.f); lineBatch->render(); } - skybox->unbind(); } - if (hudVisible && player->debug) { + { GfxContext ctx = pctx.sub(); - ctx.setDepthTest(true); - - linesShader->use(); - - if (settings.debug.showChunkBorders){ - linesShader->uniformMatrix("u_projview", camera->getProjView()); - glm::vec3 coord = player->camera->position; - if (coord.x < 0) coord.x--; - if (coord.z < 0) coord.z--; - int cx = floordiv((int)coord.x, CHUNK_W); - int cz = floordiv((int)coord.z, CHUNK_D); - - drawBorders(cx * CHUNK_W, 0, cz * CHUNK_D, - (cx + 1) * CHUNK_W, CHUNK_H, (cz + 1) * CHUNK_D); - } - - float length = 40.f; - glm::vec3 tsl(displayWidth/2, displayHeight/2, 0.f); - glm::mat4 model(glm::translate(glm::mat4(1.f), tsl)); - linesShader->uniformMatrix("u_projview", glm::ortho( - 0.f, (float)displayWidth, - 0.f, (float)displayHeight, - -length, length) * model * glm::inverse(camera->rotation)); - ctx.setDepthTest(false); - lineBatch->lineWidth(4.0f); - lineBatch->line(0.f, 0.f, 0.f, length, 0.f, 0.f, 0.f, 0.f, 0.f, 1.f); - lineBatch->line(0.f, 0.f, 0.f, 0.f, length, 0.f, 0.f, 0.f, 0.f, 1.f); - lineBatch->line(0.f, 0.f, 0.f, 0.f, 0.f, length, 0.f, 0.f, 0.f, 1.f); - lineBatch->render(); + + auto shader = assets->getShader("screen"); + shader->use(); + shader->uniform1f("u_timer", Window::time()); + shader->uniform1f("u_dayTime", level->world->daytime); - ctx.setDepthTest(true); - lineBatch->lineWidth(2.0f); - lineBatch->line(0.f, 0.f, 0.f, length, 0.f, 0.f, 1.f, 0.f, 0.f, 1.f); - lineBatch->line(0.f, 0.f, 0.f, 0.f, length, 0.f, 0.f, 1.f, 0.f, 1.f); - lineBatch->line(0.f, 0.f, 0.f, 0.f, 0.f, length, 0.f, 0.f, 1.f, 1.f); - lineBatch->render(); + postProcessing->render(ctx, shader); } } diff --git a/src/frontend/WorldRenderer.h b/src/frontend/WorldRenderer.h index 2359f139..7c56c3e7 100644 --- a/src/frontend/WorldRenderer.h +++ b/src/frontend/WorldRenderer.h @@ -20,17 +20,18 @@ class Batch3D; class LineBatch; class ChunksRenderer; class Shader; -class Texture; class Frustum; class Engine; class Chunks; class LevelFrontend; class Skybox; +class PostProcessing; class WorldRenderer { Engine* engine; Level* level; Player* player; + std::unique_ptr postProcessing; std::unique_ptr frustumCulling; std::unique_ptr lineBatch; std::unique_ptr renderer; diff --git a/src/graphics/Framebuffer.cpp b/src/graphics/Framebuffer.cpp index e70b3628..7e19c4f5 100644 --- a/src/graphics/Framebuffer.cpp +++ b/src/graphics/Framebuffer.cpp @@ -23,7 +23,7 @@ Framebuffer::Framebuffer(uint width, uint height, bool alpha) // Setup color attachment (texture) GLuint tex; - GLuint format = alpha ? GL_RGBA : GL_RGB; + format = alpha ? GL_RGBA : GL_RGB; glGenTextures(1, &tex); glBindTexture(GL_TEXTURE_2D, tex); glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, nullptr); @@ -55,6 +55,16 @@ void Framebuffer::unbind() { glBindFramebuffer(GL_FRAMEBUFFER, 0); } +void Framebuffer::resize(uint width, uint height) { + if (this->width == width && this->height == height) { + return; + } + GLuint texid = texture->getId(); + texture->bind(); + glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, nullptr); + texture->unbind(); +} + Texture* Framebuffer::getTexture() const { return texture.get(); } diff --git a/src/graphics/Framebuffer.h b/src/graphics/Framebuffer.h index d5bf7a74..65680504 100644 --- a/src/graphics/Framebuffer.h +++ b/src/graphics/Framebuffer.h @@ -8,22 +8,35 @@ class Texture; class Framebuffer { - uint fbo; - uint depth; - uint width; - uint height; - std::unique_ptr texture; + uint fbo; + uint depth; + uint width; + uint height; + uint format; + std::unique_ptr texture; public: - Framebuffer(uint fbo, uint depth, std::unique_ptr texture); - Framebuffer(uint width, uint height, bool alpha=false); - ~Framebuffer(); + Framebuffer(uint fbo, uint depth, std::unique_ptr texture); + Framebuffer(uint width, uint height, bool alpha=false); + ~Framebuffer(); - void bind(); - void unbind(); + /// @brief Use framebuffer + void bind(); - Texture* getTexture() const; - uint getWidth() const; - uint getHeight() const; + /// @brief Stop using framebuffer + void unbind(); + + /// @brief Update framebuffer texture size + /// @param width new width + /// @param height new height + void resize(uint width, uint height); + + /// @brief Get framebuffer color attachment + Texture* getTexture() const; + + /// @brief Get framebuffer width + uint getWidth() const; + /// @brief Get framebuffer height + uint getHeight() const; }; #endif /* SRC_GRAPHICS_FRAMEBUFFER_H_ */ diff --git a/src/graphics/GfxContext.cpp b/src/graphics/GfxContext.cpp index dc3b8ee1..57557942 100644 --- a/src/graphics/GfxContext.cpp +++ b/src/graphics/GfxContext.cpp @@ -31,7 +31,7 @@ GfxContext::~GfxContext() { fbo->unbind(); } if (parent->fbo) { - fbo->bind(); + parent->fbo->bind(); } } diff --git a/src/graphics/PostProcessing.cpp b/src/graphics/PostProcessing.cpp new file mode 100644 index 00000000..3c33fad4 --- /dev/null +++ b/src/graphics/PostProcessing.cpp @@ -0,0 +1,42 @@ +#include "PostProcessing.h" +#include "Mesh.h" +#include "Shader.h" +#include "Texture.h" +#include "Framebuffer.h" + +#include + +PostProcessing::PostProcessing() { + // Fullscreen quad mesh bulding + float vertices[] { + -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, + -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, -1.0f + }; + vattr attrs[] {{2}, {0}}; + quadMesh = std::make_unique(vertices, 6, attrs); +} + +PostProcessing::~PostProcessing() { +} + +void PostProcessing::use(GfxContext& context) { + const auto& vp = context.getViewport(); + if (fbo) { + fbo->resize(vp.getWidth(), vp.getHeight()); + } else { + fbo = std::make_unique(vp.getWidth(), vp.getHeight()); + } + context.setFramebuffer(fbo.get()); +} + +void PostProcessing::render(GfxContext& context, Shader* screenShader) { + if (fbo == nullptr) { + throw std::runtime_error("'use(...)' was never called"); + } + + const auto& viewport = context.getViewport(); + screenShader->use(); + screenShader->uniform2i("u_screenSize", viewport.size()); + fbo->getTexture()->bind(); + quadMesh->draw(); +} diff --git a/src/graphics/PostProcessing.h b/src/graphics/PostProcessing.h new file mode 100644 index 00000000..efd1e36a --- /dev/null +++ b/src/graphics/PostProcessing.h @@ -0,0 +1,37 @@ +#ifndef GRAPHICS_POST_PROCESSING_H_ +#define GRAPHICS_POST_PROCESSING_H_ + +#include "Viewport.h" +#include "GfxContext.h" + +#include + +class Mesh; +class Shader; +class Framebuffer; + +/// @brief Framebuffer with blitting with shaders. +/// @attention Current implementation does not support multiple render passes +/// for multiple effects. Will be implemented in v0.21 +class PostProcessing { + /// @brief Main framebuffer (lasy field) + std::unique_ptr fbo; + /// @brief Fullscreen quad mesh as the post-processing canvas + std::unique_ptr quadMesh; +public: + PostProcessing(); + ~PostProcessing(); + + /// @brief Prepare and bind framebuffer + /// @param context graphics context will be modified + void use(GfxContext& context); + + /// @brief Render fullscreen quad using the passed shader + /// with framebuffer texture bound + /// @param context graphics context + /// @param screenShader shader used for fullscreen quad + /// @throws std::runtime_error if use(...) wasn't called before + void render(GfxContext& context, Shader* screenShader); +}; + +#endif // GRAPHICS_POST_PROCESSING_H_ diff --git a/src/graphics/Shader.cpp b/src/graphics/Shader.cpp index 7d620906..ff68ddad 100644 --- a/src/graphics/Shader.cpp +++ b/src/graphics/Shader.cpp @@ -52,6 +52,11 @@ void Shader::uniform2f(std::string name, glm::vec2 xy){ glUniform2f(transformLoc, xy.x, xy.y); } +void Shader::uniform2i(std::string name, glm::ivec2 xy){ + GLuint transformLoc = glGetUniformLocation(id, name.c_str()); + glUniform2i(transformLoc, xy.x, xy.y); +} + void Shader::uniform3f(std::string name, float x, float y, float z){ GLuint transformLoc = glGetUniformLocation(id, name.c_str()); glUniform3f(transformLoc, x,y,z); diff --git a/src/graphics/Shader.h b/src/graphics/Shader.h index 851a2806..e2052937 100644 --- a/src/graphics/Shader.h +++ b/src/graphics/Shader.h @@ -21,6 +21,7 @@ public: void uniform1f(std::string name, float x); void uniform2f(std::string name, float x, float y); void uniform2f(std::string name, glm::vec2 xy); + void uniform2i(std::string name, glm::ivec2 xy); void uniform3f(std::string name, float x, float y, float z); void uniform3f(std::string name, glm::vec3 xyz); diff --git a/src/graphics/Viewport.h b/src/graphics/Viewport.h index da027b8e..3bfee7ca 100644 --- a/src/graphics/Viewport.h +++ b/src/graphics/Viewport.h @@ -14,8 +14,8 @@ public: virtual uint getWidth() const; virtual uint getHeight() const; - glm::vec2 size() const { - return glm::vec2(width, height); + glm::ivec2 size() const { + return glm::ivec2(width, height); } };