feat: post-processing effects

This commit is contained in:
MihailRis
2025-04-05 00:41:25 +03:00
parent 22e97b1766
commit ba170035ef
19 changed files with 216 additions and 84 deletions
+12 -3
View File
@@ -8,10 +8,19 @@ PostEffect::Param::Param(Type type, Value defValue)
: type(type), defValue(std::move(defValue)) {
}
PostEffect::PostEffect(std::unique_ptr<Shader> shader)
: shader(std::move(shader)) {
PostEffect::PostEffect(
std::unique_ptr<Shader> shader,
std::unordered_map<std::string, Param> params
)
: shader(std::move(shader)), params(std::move(params)) {
}
void PostEffect::use() {
Shader& PostEffect::use() {
shader->use();
shader->uniform1f("u_intensity", intensity);
return *shader;
}
void PostEffect::setIntensity(float value) {
intensity = value;
}
+12 -2
View File
@@ -21,10 +21,20 @@ public:
Param(Type type, Value defValue);
};
PostEffect(std::unique_ptr<Shader> shader);
PostEffect(
std::unique_ptr<Shader> shader,
std::unordered_map<std::string, Param> params
);
void use();
Shader& use();
void setIntensity(float value);
bool isActive() {
return intensity > 1e-4f;
}
private:
std::unique_ptr<Shader> shader;
std::unordered_map<std::string, Param> params;
float intensity = 0.0f;
};
+43 -7
View File
@@ -4,13 +4,15 @@
#include "Texture.hpp"
#include "Framebuffer.hpp"
#include "DrawContext.hpp"
#include "PostEffect.hpp"
#include "assets/Assets.hpp"
#include <stdexcept>
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,
-1.0f, -1.0f, 1.0f, 1.0f, 1.0f, -1.0f
};
VertexAttribute attrs[] {{2}, {0}};
@@ -23,22 +25,56 @@ void PostProcessing::use(DrawContext& context) {
const auto& vp = context.getViewport();
if (fbo) {
fbo->resize(vp.x, vp.y);
fboSecond->resize(vp.x, vp.y);
} else {
fbo = std::make_unique<Framebuffer>(vp.x, vp.y);
fboSecond = std::make_unique<Framebuffer>(vp.x, vp.y);
}
context.setFramebuffer(fbo.get());
}
void PostProcessing::render(const DrawContext& context, Shader* screenShader) {
void PostProcessing::render(
const DrawContext& context, const Assets& assets, float timer
) {
if (fbo == nullptr) {
throw std::runtime_error("'use(...)' was never called");
}
int totalPasses = 0;
for (const auto& effect : effectSlots) {
totalPasses += (effect != nullptr && effect->isActive());
}
const auto& viewport = context.getViewport();
screenShader->use();
screenShader->uniform2i("u_screenSize", viewport);
fbo->getTexture()->bind();
quadMesh->draw();
if (totalPasses == 0) {
auto& effect = assets.require<PostEffect>("default");
effect.use();
fbo->getTexture()->bind();
quadMesh->draw();
return;
}
int currentPass = 1;
for (const auto& effect : effectSlots) {
if (effect == nullptr || !effect->isActive()) {
continue;
}
auto& shader = effect->use();
const auto& viewport = context.getViewport();
shader.uniform1i("u_screen", 0);
shader.uniform2i("u_screenSize", viewport);
shader.uniform1f("u_timer", timer);
fbo->getTexture()->bind();
if (currentPass < totalPasses) {
fboSecond->bind();
}
quadMesh->draw();
if (currentPass < totalPasses) {
fboSecond->unbind();
std::swap(fbo, fboSecond);
}
currentPass++;
}
}
std::unique_ptr<ImageData> PostProcessing::toImage() {
+6 -3
View File
@@ -1,12 +1,14 @@
#pragma once
#include <vector>
#include <memory>
class Mesh;
class Shader;
class Assets;
class Framebuffer;
class DrawContext;
class ImageData;
class PostEffect;
/// @brief Framebuffer with blitting with shaders.
/// @attention Current implementation does not support multiple render passes
@@ -14,8 +16,10 @@ class ImageData;
class PostProcessing {
/// @brief Main framebuffer (lasy field)
std::unique_ptr<Framebuffer> fbo;
std::unique_ptr<Framebuffer> fboSecond;
/// @brief Fullscreen quad mesh as the post-processing canvas
std::unique_ptr<Mesh> quadMesh;
std::vector<std::shared_ptr<PostEffect>> effectSlots;
public:
PostProcessing();
~PostProcessing();
@@ -27,9 +31,8 @@ public:
/// @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(const DrawContext& context, Shader* screenShader);
void render(const DrawContext& context, const Assets& assets, float timer);
/// @brief Make an image from the last rendered frame
std::unique_ptr<ImageData> toImage();
+1 -6
View File
@@ -388,12 +388,7 @@ void WorldRenderer::draw(
renderBlockOverlay(wctx);
}
// Rendering fullscreen quad
auto screenShader = assets.get<Shader>("screen");
screenShader->use();
screenShader->uniform1f("u_timer", timer);
screenShader->uniform1f("u_dayTime", worldInfo.daytime);
postProcessing.render(pctx, screenShader);
postProcessing.render(pctx, assets, timer);
}
void WorldRenderer::renderBlockOverlay(const DrawContext& wctx) {