#version 450 layout(location = 0) in vec2 v_uv; layout(location = 0) out vec4 out_color; layout(set = 2, binding = 0) uniform sampler2D source; layout(set = 3, binding = 0) uniform DownscaleUniforms { int algorithm; // 0 = Lanczos2 (ventana 2, ±2 taps), 1 = Lanczos3 (ventana 3, ±3 taps) float pad0; float pad1; float pad2; } u; // Kernel Lanczos normalizado: sinc(t) * sinc(t/a) para |t| < a, 0 fuera. float lanczos(float t, float a) { t = abs(t); if (t < 0.0001) { return 1.0; } if (t >= a) { return 0.0; } const float PI = 3.14159265358979; float pt = PI * t; return (a * sin(pt) * sin(pt / a)) / (pt * pt); } void main() { vec2 src_size = vec2(textureSize(source, 0)); // Posición en coordenadas de texel (centros de texel en N+0.5) vec2 p = v_uv * src_size; vec2 p_floor = floor(p); float a = (u.algorithm == 0) ? 2.0 : 3.0; int win = int(a); vec4 color = vec4(0.0); float weight_sum = 0.0; for (int j = -win; j <= win; j++) { for (int i = -win; i <= win; i++) { // Centro del texel (i,j) relativo a p_floor vec2 tap_center = p_floor + vec2(float(i), float(j)) + 0.5; vec2 offset = tap_center - p; float w = lanczos(offset.x, a) * lanczos(offset.y, a); color += texture(source, tap_center / src_size) * w; weight_sum += w; } } out_color = (weight_sum > 0.0) ? (color / weight_sum) : vec4(0.0, 0.0, 0.0, 1.0); }