feat(bloom): glow separable two-pass amb composite preserve-core i paleta neon
This commit is contained in:
1 parent
8b4683b77b
commit
ae946b578e
17 files changed
+3683
-2159
No files matched your search
@@ -0,0 +1,72 @@
|
||||
// bloom_frag.msl.h - Metal Shading Language del fragment shader del bloom
|
||||
// © 2026 JailDesigner
|
||||
//
|
||||
// IMPORTANT: mantenir sincronitzat a mà amb shaders/bloom.frag.glsl. SDL3 GPU
|
||||
// compila aquest string MSL en runtime; qualsevol canvi al GLSL o al struct
|
||||
// BloomUniforms (gpu_bloom_pipeline.hpp) cal replicar-lo aquí al mateix commit.
|
||||
//
|
||||
// Pass 1D del bloom separable: high-pass + gaussiana en una direcció.
|
||||
// Recursos:
|
||||
// - texture2d<float> src [[texture(0)]] + sampler [[sampler(0)]]
|
||||
// - constant BloomUBO& ubo [[buffer(0)]]
|
||||
|
||||
#pragma once
|
||||
#ifdef __APPLE__
|
||||
|
||||
namespace Rendering::GPU::Msl {
|
||||
|
||||
inline constexpr const char* BLOOM_FRAG_MSL = R"(
|
||||
#include <metal_stdlib>
|
||||
using namespace metal;
|
||||
|
||||
struct PostVOut {
|
||||
float4 pos [[position]];
|
||||
float2 uv;
|
||||
};
|
||||
|
||||
struct BloomUBO {
|
||||
float2 texel_size;
|
||||
float2 direction;
|
||||
float threshold;
|
||||
float extract;
|
||||
float sigma;
|
||||
float pad_a;
|
||||
};
|
||||
|
||||
fragment float4 bloom_fs(PostVOut in [[stage_in]],
|
||||
texture2d<float> src [[texture(0)]],
|
||||
sampler samp [[sampler(0)]],
|
||||
constant BloomUBO& ubo [[buffer(0)]]) {
|
||||
float3 sum = float3(0.0);
|
||||
float total_weight = 0.0;
|
||||
|
||||
constexpr int RADIUS = 7;
|
||||
constexpr float TWO_SIGMA_SQ_FACTOR = 2.0;
|
||||
|
||||
for (int i = -RADIUS; i <= RADIUS; ++i) {
|
||||
float2 offset = ubo.direction * float(i) * ubo.texel_size;
|
||||
float3 c = src.sample(samp, in.uv + offset).rgb;
|
||||
|
||||
if (ubo.extract > 0.5) {
|
||||
float luma = max(c.r, max(c.g, c.b));
|
||||
float high_pass = max(0.0, luma - ubo.threshold);
|
||||
c *= high_pass;
|
||||
}
|
||||
|
||||
float fi = float(i);
|
||||
float w = exp(-(fi * fi) / (TWO_SIGMA_SQ_FACTOR * ubo.sigma * ubo.sigma));
|
||||
sum += c * w;
|
||||
total_weight += w;
|
||||
}
|
||||
|
||||
if (total_weight > 0.0) {
|
||||
sum /= total_weight;
|
||||
}
|
||||
|
||||
return float4(sum, 1.0);
|
||||
}
|
||||
)";
|
||||
|
||||
} // namespace Rendering::GPU::Msl
|
||||
|
||||
#endif // __APPLE__
|
||||
@@ -1,4 +1,4 @@
|
||||
// postfx_frag.msl.h - Metal Shading Language del fragment shader del postpro
|
||||
// postfx_frag.msl.h - Metal Shading Language del fragment shader del composite
|
||||
// © 2026 JailDesigner
|
||||
//
|
||||
// IMPORTANT: mantenir sincronitzat a mà amb shaders/postfx.frag.glsl. SDL3 GPU
|
||||
@@ -6,19 +6,18 @@
|
||||
// canvi al struct PostFxUniforms (gpu_postfx_pipeline.hpp), al GLSL o al MSL
|
||||
// cal replicar-lo a totes tres al mateix commit.
|
||||
//
|
||||
// Composició final: bloom 5×5 amb high-pass, flicker sinusoidal global,
|
||||
// background pulse sumat. Recursos:
|
||||
// Composite final: llegeix escena + bloom pre-calculat (per bloom.frag.glsl en
|
||||
// separable two-pass) i aplica flicker + background pulse. Recursos:
|
||||
// - texture2d<float> scene [[texture(0)]] + sampler [[sampler(0)]]
|
||||
// - texture2d<float> bloom_tex [[texture(1)]] + sampler [[sampler(1)]]
|
||||
// - constant PostFxUBO& ubo [[buffer(0)]] (slot 0 SDL → buffer(0) MSL)
|
||||
//
|
||||
// L'struct PostFxUBO té layout idèntic a PostFxUniforms (5×vec4 = 80 bytes).
|
||||
|
||||
#pragma once
|
||||
#ifdef __APPLE__
|
||||
|
||||
namespace Rendering::GPU::Msl {
|
||||
|
||||
inline constexpr const char* POSTFX_FRAG_MSL = R"(
|
||||
inline constexpr const char* POSTFX_FRAG_MSL = R"(
|
||||
#include <metal_stdlib>
|
||||
using namespace metal;
|
||||
|
||||
@@ -30,46 +29,28 @@ struct PostVOut {
|
||||
struct PostFxUBO {
|
||||
float time;
|
||||
float bloom_intensity;
|
||||
float bloom_threshold;
|
||||
float bloom_radius_px;
|
||||
|
||||
float flicker_amplitude;
|
||||
float flicker_frequency_hz;
|
||||
|
||||
float background_pulse_freq_hz;
|
||||
float pad_a;
|
||||
float pad_b;
|
||||
float pad_c;
|
||||
|
||||
float4 background_min;
|
||||
float4 background_max;
|
||||
|
||||
float2 texel_size;
|
||||
float2 pad_b;
|
||||
};
|
||||
|
||||
constant float TAU = 6.28318530718;
|
||||
|
||||
fragment float4 postfx_fs(PostVOut in [[stage_in]],
|
||||
texture2d<float> scene [[texture(0)]],
|
||||
sampler samp [[sampler(0)]],
|
||||
texture2d<float> scene [[texture(0)]],
|
||||
sampler samp_s [[sampler(0)]],
|
||||
texture2d<float> bloom_tex [[texture(1)]],
|
||||
sampler samp_b [[sampler(1)]],
|
||||
constant PostFxUBO& ubo [[buffer(0)]]) {
|
||||
// === BLOOM ===
|
||||
float3 src = scene.sample(samp, in.uv).rgb;
|
||||
float3 bloom = float3(0.0);
|
||||
float total_weight = 0.0;
|
||||
for (int dy = -2; dy <= 2; ++dy) {
|
||||
for (int dx = -2; dx <= 2; ++dx) {
|
||||
float2 offset = float2(float(dx), float(dy)) * ubo.texel_size * ubo.bloom_radius_px;
|
||||
float3 c = scene.sample(samp, in.uv + offset).rgb;
|
||||
float luma = max(c.r, max(c.g, c.b));
|
||||
float high_pass = max(0.0, luma - ubo.bloom_threshold);
|
||||
float w = exp(-float(dx * dx + dy * dy) / 4.0);
|
||||
bloom += c * high_pass * w;
|
||||
total_weight += w;
|
||||
}
|
||||
}
|
||||
if (total_weight > 0.0) {
|
||||
bloom /= total_weight;
|
||||
}
|
||||
bloom *= ubo.bloom_intensity;
|
||||
float3 src = scene.sample(samp_s, in.uv).rgb;
|
||||
float3 bloom = bloom_tex.sample(samp_b, in.uv).rgb * ubo.bloom_intensity;
|
||||
|
||||
// === FLICKER ===
|
||||
float pulse = (sin(ubo.time * ubo.flicker_frequency_hz * TAU) * 0.5) + 0.5;
|
||||
@@ -79,8 +60,12 @@ fragment float4 postfx_fs(PostVOut in [[stage_in]],
|
||||
float bg_pulse = (sin(ubo.time * ubo.background_pulse_freq_hz * TAU) * 0.5) + 0.5;
|
||||
float3 background = mix(ubo.background_min.rgb, ubo.background_max.rgb, bg_pulse);
|
||||
|
||||
// === COMPOSICIÓ ===
|
||||
float3 lines_and_glow = (src + bloom) * flicker;
|
||||
// === COMPOSICIÓ (preserve-core) ===
|
||||
// Bloom additiu atenuat per (1 - luma_src) — manté el color del core
|
||||
// i posa el halo intens només als píxels foscos del voltant.
|
||||
float src_luma = max(src.r, max(src.g, src.b));
|
||||
float3 bloom_contribution = bloom * (1.0 - src_luma);
|
||||
float3 lines_and_glow = (src + bloom_contribution) * flicker;
|
||||
return float4(background + lines_and_glow, 1.0);
|
||||
}
|
||||
)";
|
||||
|
||||
Reference in new issue
Block a user