From af0276255ecffb949af5171881a7596e020c1e95 Mon Sep 17 00:00:00 2001 From: Sergio Valor Date: Thu, 19 Mar 2026 22:11:05 +0100 Subject: [PATCH] feat(postfx): afegir push constants i efectes chromatic aberration + scanlines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - PostFXUniforms struct (vignette_strength, chroma_strength, scanline_strength, time) - Shader MSL actualitzat: aberració cromàtica RGB + scanlines sin-wave + vinyeta paramètrica - Pipeline postfx declara num_uniform_buffers=1 (buffer(0) en MSL) - Engine acumula temps i fa SDL_PushGPUFragmentUniformData cada frame - Valors per defecte: vignette=1.5, chroma=0, scanlines=0 (comportament idèntic a l'anterior) Co-Authored-By: Claude Sonnet 4.6 --- source/engine.cpp | 4 ++++ source/engine.hpp | 3 +++ source/gpu/gpu_pipeline.cpp | 39 +++++++++++++++++++++++++++++-------- source/gpu/gpu_pipeline.hpp | 13 +++++++++++++ 4 files changed, 51 insertions(+), 8 deletions(-) diff --git a/source/engine.cpp b/source/engine.cpp index 55dc2a7..24f8537 100644 --- a/source/engine.cpp +++ b/source/engine.cpp @@ -417,6 +417,9 @@ void Engine::calculateDeltaTime() { } void Engine::update() { + // Accumulate time for PostFX uniforms + postfx_uniforms_.time += delta_time_; + // Actualizar visibilidad del cursor (auto-ocultar tras inactividad) Mouse::updateCursorVisibility(); @@ -824,6 +827,7 @@ void Engine::render() { SDL_BindGPUGraphicsPipeline(pass2, gpu_pipeline_->postfxPipeline()); SDL_GPUTextureSamplerBinding scene_tsb = {offscreen_tex_->texture(), offscreen_tex_->sampler()}; SDL_BindGPUFragmentSamplers(pass2, 0, &scene_tsb, 1); + SDL_PushGPUFragmentUniformData(cmd, 0, &postfx_uniforms_, sizeof(PostFXUniforms)); SDL_DrawGPUPrimitives(pass2, 3, 1, 0, 0); // UI overlay (alpha-blended, uses sprite pipeline) diff --git a/source/engine.hpp b/source/engine.hpp index c4235e1..34f56a2 100644 --- a/source/engine.hpp +++ b/source/engine.hpp @@ -163,6 +163,9 @@ class Engine { Uint64 last_frame_time_ = 0; float delta_time_ = 0.0f; + // PostFX uniforms (passed to GPU each frame) + PostFXUniforms postfx_uniforms_ = {1.5f, 0.0f, 0.0f, 0.0f}; + // Sistema de zoom dinámico int current_window_zoom_ = DEFAULT_WINDOW_ZOOM; diff --git a/source/gpu/gpu_pipeline.cpp b/source/gpu/gpu_pipeline.cpp index 6d76008..1c91f6e 100644 --- a/source/gpu/gpu_pipeline.cpp +++ b/source/gpu/gpu_pipeline.cpp @@ -85,7 +85,12 @@ vertex PostVOut postfx_vs(uint vid [[vertex_id]]) { // --------------------------------------------------------------------------- // PostFX fragment shader -// Samples the offscreen scene texture and applies a subtle vignette. +// Effects driven by PostFXUniforms (uniform buffer slot 0): +// - Chromatic aberration: RGB channel UV offset +// - Scanlines: sin-wave intensity modulation +// - Vignette: radial edge darkening +// MSL binding for fragment uniform buffer 0 with 1 sampler, 0 storage: +// constant PostFXUniforms& u [[buffer(0)]] // --------------------------------------------------------------------------- static const char* kPostFXFragMSL = R"( #include @@ -96,14 +101,32 @@ struct PostVOut { float2 uv; }; -fragment float4 postfx_fs(PostVOut in [[stage_in]], - texture2d scene [[texture(0)]], - sampler samp [[sampler(0)]]) { - float4 color = scene.sample(samp, in.uv); +struct PostFXUniforms { + float vignette_strength; + float chroma_strength; + float scanline_strength; + float time; +}; - // Subtle vignette: darkens edges proportionally to distance from centre +fragment float4 postfx_fs(PostVOut in [[stage_in]], + texture2d scene [[texture(0)]], + sampler samp [[sampler(0)]], + constant PostFXUniforms& u [[buffer(0)]]) { + // Chromatic aberration: offset R and B channels horizontally + float ca = u.chroma_strength * 0.005; + float4 color; + color.r = scene.sample(samp, in.uv + float2( ca, 0.0)).r; + color.g = scene.sample(samp, in.uv ).g; + color.b = scene.sample(samp, in.uv - float2( ca, 0.0)).b; + color.a = scene.sample(samp, in.uv ).a; + + // Scanlines: horizontal sine-wave at ~360 lines (one dark band per 2 px at 720p) + float scan = 0.85 + 0.15 * sin(in.uv.y * 3.14159265 * 720.0); + color.rgb *= mix(1.0, scan, u.scanline_strength); + + // Vignette: radial edge darkening float2 d = in.uv - float2(0.5, 0.5); - float vignette = 1.0 - dot(d, d) * 1.5; + float vignette = 1.0 - dot(d, d) * u.vignette_strength; color.rgb *= clamp(vignette, 0.0, 1.0); return color; @@ -215,7 +238,7 @@ bool GpuPipeline::init(SDL_GPUDevice* device, SDL_GPUShader* postfx_vert = createShader(device, kPostFXVertMSL, "postfx_vs", SDL_GPU_SHADERSTAGE_VERTEX, 0, 0); SDL_GPUShader* postfx_frag = createShader(device, kPostFXFragMSL, "postfx_fs", - SDL_GPU_SHADERSTAGE_FRAGMENT, 1, 0); + SDL_GPU_SHADERSTAGE_FRAGMENT, 1, 1); if (!postfx_vert || !postfx_frag) { SDL_Log("GpuPipeline: failed to create postfx shaders"); if (postfx_vert) SDL_ReleaseGPUShader(device, postfx_vert); diff --git a/source/gpu/gpu_pipeline.hpp b/source/gpu/gpu_pipeline.hpp index f48bfd7..8f1e409 100644 --- a/source/gpu/gpu_pipeline.hpp +++ b/source/gpu/gpu_pipeline.hpp @@ -2,6 +2,18 @@ #include +// ============================================================================ +// PostFXUniforms — pushed to the fragment stage each frame via +// SDL_PushGPUFragmentUniformData(pass, 0, &uniforms, sizeof(PostFXUniforms)) +// MSL binding: constant PostFXUniforms& u [[buffer(0)]] +// ============================================================================ +struct PostFXUniforms { + float vignette_strength; // 0 = none, 1.5 = default subtle + float chroma_strength; // 0 = off, 1 = full chromatic aberration + float scanline_strength; // 0 = off, 1 = full scanlines + float time; // accumulated seconds (for future animations) +}; + // ============================================================================ // GpuPipeline — Creates and owns the graphics pipelines used by the engine. // @@ -9,6 +21,7 @@ // Vertex layout: GpuVertex (pos float2, uv float2, col float4). // postfx_pipeline_ : full-screen triangle, no vertex buffer, no blend. // Reads offscreen texture, writes to swapchain. +// Accepts PostFXUniforms via fragment uniform buffer slot 0. // ============================================================================ class GpuPipeline { public: