postfx: scanlines analítiques amb smoothstep a l'estil crtpi, exposant forma per preset YAML
This commit is contained in:
1 parent
4dc2654a66
commit
c9e6261cf1
8 files changed
+1287
-901
No files matched your search
@@ -4,6 +4,11 @@
|
||||
|
||||
// Fragment shader del shader "postfx": vignette, chroma, scanlines, mask,
|
||||
// gamma, curvature, bleeding i flicker. Els paràmetres venen via uniforms.
|
||||
//
|
||||
// IMPORTANT: mantenir sincronitzat a mà amb data/shaders/postfx.frag. SDL3 GPU
|
||||
// compila aquest string MSL en runtime; no hi ha generador automàtic. Qualsevol
|
||||
// canvi a la struct d'uniforms o a la lògica del GLSL cal replicar-lo ací al
|
||||
// mateix commit. Mida total = 64 bytes (4 × vec4).
|
||||
namespace Rendering::Msl {
|
||||
|
||||
inline constexpr const char* kPostfxFrag = R"(
|
||||
@@ -28,6 +33,11 @@ struct PostFXUniforms {
|
||||
float time;
|
||||
float oversample;
|
||||
float flicker;
|
||||
// vec4 #3 — paràmetres de scanlines (exposats per preset YAML)
|
||||
float scan_dark_ratio;
|
||||
float scan_dark_floor;
|
||||
float scan_edge_soft;
|
||||
float pad3;
|
||||
};
|
||||
|
||||
static float3 rgb_to_ycc(float3 rgb) {
|
||||
@@ -93,15 +103,19 @@ fragment float4 postfx_fs(PostVOut in [[stage_in]],
|
||||
colour = mix(colour, lin, u.gamma_strength);
|
||||
}
|
||||
|
||||
const float SCAN_DARK_RATIO = 0.333f;
|
||||
const float SCAN_DARK_FLOOR = 0.42f;
|
||||
// Scanlines — 3 subpíxels per fila lògica (2 brillants + 1 fosca). Transició
|
||||
// suavitzada amb smoothstep d'ample ≈ 1 píxel físic (estil crtpi: filtratge
|
||||
// analític continu). scan_edge_soft = 0 recupera el step dur de l'original.
|
||||
if (u.scanline_strength > 0.0f) {
|
||||
float ps = max(1.0f, round(u.pixel_scale));
|
||||
float frac_in_row = fract(uv.y * u.screen_height);
|
||||
float row_pos = floor(frac_in_row * ps);
|
||||
float bright_rows = (ps < 2.0f) ? ps : ((ps < 3.0f) ? 1.0f : floor(ps * (1.0f - SCAN_DARK_RATIO)));
|
||||
float is_dark = step(bright_rows, row_pos);
|
||||
float scan = mix(1.0f, SCAN_DARK_FLOOR, is_dark);
|
||||
float ps = max(u.pixel_scale, 1.0f);
|
||||
float sub = fract(uv.y * u.screen_height);
|
||||
float dark_center = 1.0f - u.scan_dark_ratio * 0.5f;
|
||||
float d = abs(sub - dark_center);
|
||||
d = min(d, 1.0f - d);
|
||||
float half_width = u.scan_dark_ratio * 0.5f;
|
||||
float softness = u.scan_edge_soft * 0.5f / ps;
|
||||
float band = 1.0f - smoothstep(half_width - softness, half_width + softness, d);
|
||||
float scan = mix(1.0f, u.scan_dark_floor, band);
|
||||
colour *= mix(1.0f, scan, u.scanline_strength);
|
||||
}
|
||||
|
||||
|
||||
@@ -204,6 +204,12 @@ namespace Rendering {
|
||||
const SDL_GPUViewport VP = computeViewport(scaling_mode_, sw, sh, game_width_, game_height_);
|
||||
SDL_SetGPUViewport(pass, &VP);
|
||||
|
||||
// pixel_scale = píxels físics per fila lògica al viewport. El shader l'usa
|
||||
// per ajustar l'ample del smoothstep de scanlines a 1 píxel físic (estil crtpi).
|
||||
uniforms_.pixel_scale = (game_height_ > 0)
|
||||
? VP.h / static_cast<float>(game_height_)
|
||||
: 1.0F;
|
||||
|
||||
SDL_BindGPUGraphicsPipeline(pass, pipeline_);
|
||||
|
||||
SDL_GPUTextureSamplerBinding binding{};
|
||||
@@ -234,6 +240,9 @@ namespace Rendering {
|
||||
uniforms_.curvature = params.curvature;
|
||||
uniforms_.bleeding = params.bleeding;
|
||||
uniforms_.flicker = params.flicker;
|
||||
uniforms_.scan_dark_ratio = params.scan_dark_ratio;
|
||||
uniforms_.scan_dark_floor = params.scan_dark_floor;
|
||||
uniforms_.scan_edge_soft = params.scan_edge_soft;
|
||||
}
|
||||
|
||||
void SDL3GPUShader::setVSync(bool vsync) {
|
||||
|
||||
@@ -11,20 +11,28 @@
|
||||
#include "core/rendering/shader_backend.hpp"
|
||||
|
||||
// Uniforms enviats al fragment stage cada frame.
|
||||
// Han de coincidir amb l'estructura MSL/GLSL (48 bytes, alineats a 16).
|
||||
// Han de coincidir amb l'estructura MSL/GLSL (64 bytes = 4 × vec4, alineats a 16).
|
||||
struct PostFXUniforms {
|
||||
// vec4 #0
|
||||
float vignette_strength;
|
||||
float chroma_strength;
|
||||
float scanline_strength;
|
||||
float screen_height;
|
||||
// vec4 #1
|
||||
float mask_strength;
|
||||
float gamma_strength;
|
||||
float curvature;
|
||||
float bleeding;
|
||||
// vec4 #2
|
||||
float pixel_scale;
|
||||
float time;
|
||||
float oversample;
|
||||
float flicker;
|
||||
// vec4 #3 — paràmetres de scanlines exposats al preset YAML
|
||||
float scan_dark_ratio;
|
||||
float scan_dark_floor;
|
||||
float scan_edge_soft;
|
||||
float pad3;
|
||||
};
|
||||
|
||||
namespace Rendering {
|
||||
@@ -96,6 +104,11 @@ namespace Rendering {
|
||||
.time = 0.0F,
|
||||
.oversample = 1.0F,
|
||||
.flicker = 0.0F,
|
||||
// Defaults canònics: 2/3 brillant + 1/3 fosca, brillantor 42%, suavitzat complet (1 px físic).
|
||||
.scan_dark_ratio = 0.333F,
|
||||
.scan_dark_floor = 0.42F,
|
||||
.scan_edge_soft = 1.0F,
|
||||
.pad3 = 0.0F,
|
||||
};
|
||||
|
||||
int game_width_{0};
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -25,6 +25,10 @@ namespace Rendering {
|
||||
float curvature{0.0F};
|
||||
float bleeding{0.0F};
|
||||
float flicker{0.0F};
|
||||
// Forma de les scanlines — 3 subpíxels per fila lògica per defecte.
|
||||
float scan_dark_ratio{0.333F}; // fracció obscura (1/3)
|
||||
float scan_dark_floor{0.42F}; // brillantor subfila fosca
|
||||
float scan_edge_soft{1.0F}; // 0 = step dur; 1 = suavitzat 1 px físic
|
||||
};
|
||||
|
||||
// Paràmetres del shader CRT-Pi (algoritme de scanlines amb pesos gaussians).
|
||||
|
||||
Reference in new issue
Block a user