#version 450 // Fragment shader del pase final de composite. // Llegeix dos samplers: l'escena vectorial i el bloom ja pre-calculat (resultat // del separable blur de dues passes a bloom.frag.glsl). Aplica: // 1. Mescla del bloom amb la intensitat configurada. // 2. Flicker: multiplicador global de brillo modulat per temps. // 3. Background pulse: color de fons additiu que oscil·la entre min/max. // // L'arquitectura anterior tenia el bloom inline (kernel 7×7 single-pass), que // produïa moiré per radis grans. Ara el bloom és pre-computed via separable // gaussian (equivalent a kernel 15×15 dens) i aquí només cal samplejar-lo. // // Resource sets (SDL_gpu): // set=2, binding=0 → sampler2D (escena offscreen) // set=2, binding=1 → sampler2D (bloom pre-calculat) // set=3, binding=0 → uniform buffer (paràmetres del postpro) layout(set = 2, binding = 0) uniform sampler2D scene; layout(set = 2, binding = 1) uniform sampler2D bloom_tex; layout(set = 3, binding = 0) uniform PostFxUBO { float time; float bloom_intensity; float flicker_amplitude; float flicker_frequency_hz; float background_pulse_freq_hz; float _pad_a; float _pad_b; float _pad_c; vec4 background_min; // RGB en [0..1], A=1 vec4 background_max; // RGB en [0..1], A=1 } ubo; layout(location = 0) in vec2 v_uv; layout(location = 0) out vec4 frag; const float TAU = 6.28318530718; void main() { vec3 src = texture(scene, v_uv).rgb; vec3 bloom = texture(bloom_tex, v_uv).rgb * ubo.bloom_intensity; // === FLICKER === // Multiplicador global de brillo. Oscil·la entre (1.0 - amplitude) i 1.0. float pulse = (sin(ubo.time * ubo.flicker_frequency_hz * TAU) * 0.5) + 0.5; float flicker = 1.0 - (ubo.flicker_amplitude * (1.0 - pulse)); // === BACKGROUND PULSE === float bg_pulse = (sin(ubo.time * ubo.background_pulse_freq_hz * TAU) * 0.5) + 0.5; vec3 background = mix(ubo.background_min.rgb, ubo.background_max.rgb, bg_pulse); // === COMPOSICIÓ (preserve-core) === // Bloom additiu però atenuat per (1 - luma_src): no contribueix als píxels // on la línia ja és brillant (manté el color del core sense rentar-lo cap a // blanc) i contribueix al màxim als píxels foscos del voltant (halo intens). // El flicker només multiplica (línies + bloom); el fons va a banda perquè // els píxels foscos no han de pulsar. float src_luma = max(src.r, max(src.g, src.b)); vec3 bloom_contribution = bloom * (1.0 - src_luma); vec3 lines_and_glow = (src + bloom_contribution) * flicker; frag = vec4(background + lines_and_glow, 1.0); }