feat(postfx): afegir push constants i efectes chromatic aberration + scanlines
- 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 <noreply@anthropic.com>
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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 <metal_stdlib>
|
||||
@@ -96,14 +101,32 @@ struct PostVOut {
|
||||
float2 uv;
|
||||
};
|
||||
|
||||
fragment float4 postfx_fs(PostVOut in [[stage_in]],
|
||||
texture2d<float> 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<float> 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);
|
||||
|
||||
@@ -2,6 +2,18 @@
|
||||
|
||||
#include <SDL3/SDL_gpu.h>
|
||||
|
||||
// ============================================================================
|
||||
// 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:
|
||||
|
||||
Reference in New Issue
Block a user