From 8a59989df4a6b3e7a3d8eaf3d2b6c105a76b3449 Mon Sep 17 00:00:00 2001 From: Tatsuya79 Date: Sat, 22 May 2021 15:16:23 +0200 Subject: [PATCH] ntsc-adaptive-tate, smart-morph additions --- ntsc/ntsc-adaptive-tate.slangp | 14 ++ .../ntsc-adaptive-tate/ntsc-tate-pass1.slang | 87 +++++++ .../ntsc-adaptive-tate/ntsc-tate-pass2.slang | 220 ++++++++++++++++++ .../crt-geom-ntsc-composite-sharp-tate.slangp | 78 +++++++ presets/crt-geom-ntsc-composite-sharp.slangp | 77 ++++++ warp/shaders/smart-morph.slang | 40 +++- 6 files changed, 506 insertions(+), 10 deletions(-) create mode 100644 ntsc/ntsc-adaptive-tate.slangp create mode 100644 ntsc/shaders/ntsc-adaptive-tate/ntsc-tate-pass1.slang create mode 100644 ntsc/shaders/ntsc-adaptive-tate/ntsc-tate-pass2.slang create mode 100644 presets/crt-geom-ntsc-composite-sharp-tate.slangp create mode 100644 presets/crt-geom-ntsc-composite-sharp.slangp diff --git a/ntsc/ntsc-adaptive-tate.slangp b/ntsc/ntsc-adaptive-tate.slangp new file mode 100644 index 0000000..47462ae --- /dev/null +++ b/ntsc/ntsc-adaptive-tate.slangp @@ -0,0 +1,14 @@ +shaders = 2 + +shader0 = shaders/ntsc-adaptive-tate/ntsc-tate-pass1.slang +scale_type0 = source +scale_x0 = 1.0 +filter_linear0 = false +scale_y0 = 4.0 +float_framebuffer0 = true + +shader1 = shaders/ntsc-adaptive-tate/ntsc-tate-pass2.slang +scale_type1 = source +scale_x1 = 1.0 +scale_y1 = 0.5 +filter_linear1 = false diff --git a/ntsc/shaders/ntsc-adaptive-tate/ntsc-tate-pass1.slang b/ntsc/shaders/ntsc-adaptive-tate/ntsc-tate-pass1.slang new file mode 100644 index 0000000..3549f7e --- /dev/null +++ b/ntsc/shaders/ntsc-adaptive-tate/ntsc-tate-pass1.slang @@ -0,0 +1,87 @@ +#version 450 + +// NTSC-Adaptive +// based on Themaister's NTSC shader + +layout(std140, set = 0, binding = 0) uniform UBO +{ + mat4 MVP; + vec4 OutputSize; + vec4 OriginalSize; + vec4 SourceSize; + uint FrameCount; + float quality, bw; +} global; + +#pragma parameter quality "Quality (Composite = 0, Svideo = 1)" 0.0 0.0 1.0 1.0 +#pragma parameter bw "Black and White" 0.0 0.0 1.0 1.0 + +#pragma stage vertex +layout(location = 0) in vec4 Position; +layout(location = 1) in vec2 TexCoord; +layout(location = 0) out vec2 vTexCoord; +layout(location = 1) out vec2 pix_no; + +void main() +{ + gl_Position = global.MVP * Position; + vTexCoord = TexCoord; + pix_no = TexCoord * global.SourceSize.xy * (global.OutputSize.xy / global.SourceSize.xy); +} + +#pragma stage fragment +layout(location = 0) in vec2 vTexCoord; +layout(location = 1) in vec2 pix_no; +layout(location = 0) out vec4 FragColor; +layout(set = 0, binding = 2) uniform sampler2D Source; + +#define PI 3.14159265 +float phase = (global.OriginalSize.y > 300.0) ? 2.0 : 3.0; + + +#define mix_mat mat3(BRIGHTNESS, FRINGING, FRINGING, ARTIFACTING, 2.0 * SATURATION, 0.0, ARTIFACTING, 0.0, 2.0 * SATURATION) + +const mat3 yiq2rgb_mat = mat3( + 1.0, 0.956, 0.6210, + 1.0, -0.2720, -0.6474, + 1.0, -1.1060, 1.7046); + +vec3 yiq2rgb(vec3 yiq) +{ + return yiq * yiq2rgb_mat; +} + +const mat3 yiq_mat = mat3( + 0.2989, 0.5870, 0.1140, + 0.5959, -0.2744, -0.3216, + 0.2115, -0.5229, 0.3114 +); + +vec3 rgb2yiq(vec3 col) +{ + return col * yiq_mat; +} + +void main() +{ + float CHROMA_MOD_FREQ = (phase < 2.5) ? (4.0 * PI / 15.0) : (PI / 3.0); + float ARTIFACTING = 1.0 - global.quality; + float FRINGING = 1.0 - global.quality; + float SATURATION = 1.0 - global.bw; + // prevent some very slight clipping that happens at 1.0 + const float BRIGHTNESS = 0.95; + vec3 col = texture(Source, vTexCoord).rgb; + vec3 yiq = rgb2yiq(col); + + float chroma_phase = (phase < 2.5) ? PI * (mod(pix_no.x, 2.0) + mod(global.FrameCount, 2.)) : 0.6667 * PI * (mod(pix_no.x, 3.0) + mod(global.FrameCount, 2.)); + + float mod_phase = chroma_phase + pix_no.y * CHROMA_MOD_FREQ; + + float i_mod = cos(mod_phase); + float q_mod = sin(mod_phase); + + yiq.yz *= vec2(i_mod, q_mod); // Modulate. + yiq *= mix_mat; // Cross-talk. + yiq.yz *= vec2(i_mod, q_mod); // Demodulate. + FragColor = vec4(yiq, 1.0); +} diff --git a/ntsc/shaders/ntsc-adaptive-tate/ntsc-tate-pass2.slang b/ntsc/shaders/ntsc-adaptive-tate/ntsc-tate-pass2.slang new file mode 100644 index 0000000..c20ffa4 --- /dev/null +++ b/ntsc/shaders/ntsc-adaptive-tate/ntsc-tate-pass2.slang @@ -0,0 +1,220 @@ +#version 450 + +// NTSC-Adaptive +// based on Themaister's NTSC shader + +layout(std140, set = 0, binding = 0) uniform UBO +{ + mat4 MVP; + vec4 OutputSize; + vec4 OriginalSize; + vec4 SourceSize; + float linearize; +} global; + +#pragma parameter linearize "Linearize Output Gamma" 0.0 0.0 1.0 1.0 + +#define fetch_offset(offset, one_y) \ + texture(Source, vTexCoord + vec2(0.0, (offset) * (one_y))).xyz + +#pragma stage vertex +layout(location = 0) in vec4 Position; +layout(location = 1) in vec2 TexCoord; +layout(location = 0) out vec2 vTexCoord; + +void main() +{ + gl_Position = global.MVP * Position; + vTexCoord = TexCoord - vec2(0.0, 0.5 / global.SourceSize.y); // Compensate for decimate-by-2. +} + +#pragma stage fragment +layout(location = 0) in vec2 vTexCoord; +layout(location = 0) out vec4 FragColor; +layout(set = 0, binding = 2) uniform sampler2D Source; + +const mat3 yiq2rgb_mat = mat3( + 1.0, 0.956, 0.6210, + 1.0, -0.2720, -0.6474, + 1.0, -1.1060, 1.7046); + +vec3 yiq2rgb(vec3 yiq) +{ + return yiq * yiq2rgb_mat; +} + +const mat3 yiq_mat = mat3( + 0.2989, 0.5870, 0.1140, + 0.5959, -0.2744, -0.3216, + 0.2115, -0.5229, 0.3114 +); + +vec3 rgb2yiq(vec3 col) +{ + return col * yiq_mat; +} + +const int TAPS_2_phase = 32; +const float luma_filter_2_phase[33] = float[33]( + -0.000174844, + -0.000205844, + -0.000149453, + -0.000051693, + 0.000000000, + -0.000066171, + -0.000245058, + -0.000432928, + -0.000472644, + -0.000252236, + 0.000198929, + 0.000687058, + 0.000944112, + 0.000803467, + 0.000363199, + 0.000013422, + 0.000253402, + 0.001339461, + 0.002932972, + 0.003983485, + 0.003026683, + -0.001102056, + -0.008373026, + -0.016897700, + -0.022914480, + -0.021642347, + -0.008863273, + 0.017271957, + 0.054921920, + 0.098342579, + 0.139044281, + 0.168055832, + 0.178571429); + +const float chroma_filter_2_phase[33] = float[33]( + 0.001384762, + 0.001678312, + 0.002021715, + 0.002420562, + 0.002880460, + 0.003406879, + 0.004004985, + 0.004679445, + 0.005434218, + 0.006272332, + 0.007195654, + 0.008204665, + 0.009298238, + 0.010473450, + 0.011725413, + 0.013047155, + 0.014429548, + 0.015861306, + 0.017329037, + 0.018817382, + 0.020309220, + 0.021785952, + 0.023227857, + 0.024614500, + 0.025925203, + 0.027139546, + 0.028237893, + 0.029201910, + 0.030015081, + 0.030663170, + 0.031134640, + 0.031420995, + 0.031517031); + +const int TAPS_3_phase = 24; +const float luma_filter_3_phase[25] = float[25]( + -0.000012020, + -0.000022146, + -0.000013155, + -0.000012020, + -0.000049979, + -0.000113940, + -0.000122150, + -0.000005612, + 0.000170516, + 0.000237199, + 0.000169640, + 0.000285688, + 0.000984574, + 0.002018683, + 0.002002275, + -0.000909882, + -0.007049081, + -0.013222860, + -0.012606931, + 0.002460860, + 0.035868225, + 0.084016453, + 0.135563500, + 0.175261268, + 0.190176552); + +const float chroma_filter_3_phase[25] = float[25]( + -0.000118847, + -0.000271306, + -0.000502642, + -0.000930833, + -0.001451013, + -0.002064744, + -0.002700432, + -0.003241276, + -0.003524948, + -0.003350284, + -0.002491729, + -0.000721149, + 0.002164659, + 0.006313635, + 0.011789103, + 0.018545660, + 0.026414396, + 0.035100710, + 0.044196567, + 0.053207202, + 0.061590275, + 0.068803602, + 0.074356193, + 0.077856564, + 0.079052396); + +void main() +{ + float phase = (global.OriginalSize.y > 300.0) ? 2.0 : 3.0; + float one_y = global.SourceSize.w; + vec3 signal = vec3(0.0); + + if(phase < 2.5) + { + for (int i = 0; i < TAPS_2_phase; i++) + { + float offset = float(i); + + vec3 sums = fetch_offset(offset - float(TAPS_2_phase), one_y) + + fetch_offset(float(TAPS_2_phase) - offset, one_y); + signal += sums * vec3(luma_filter_2_phase[i], chroma_filter_2_phase[i], chroma_filter_2_phase[i]); + } + signal += texture(Source, vTexCoord).xyz * + vec3(luma_filter_2_phase[TAPS_2_phase], chroma_filter_2_phase[TAPS_2_phase], chroma_filter_2_phase[TAPS_2_phase]); + } + else if(phase > 2.5) + { + for (int i = 0; i < TAPS_3_phase; i++) + { + float offset = float(i); + + vec3 sums = fetch_offset(offset - float(TAPS_3_phase), one_y) + + fetch_offset(float(TAPS_3_phase) - offset, one_y); + signal += sums * vec3(luma_filter_3_phase[i], chroma_filter_3_phase[i], chroma_filter_3_phase[i]); + } + signal += texture(Source, vTexCoord).xyz * + vec3(luma_filter_3_phase[TAPS_3_phase], chroma_filter_3_phase[TAPS_3_phase], chroma_filter_3_phase[TAPS_3_phase]); + } + + vec3 rgb = yiq2rgb(signal); + FragColor = vec4(rgb, 1.0); + if(global.linearize < 0.5) return; + else FragColor = pow(FragColor, vec4(2.2)); +} diff --git a/presets/crt-geom-ntsc-composite-sharp-tate.slangp b/presets/crt-geom-ntsc-composite-sharp-tate.slangp new file mode 100644 index 0000000..ce07e5c --- /dev/null +++ b/presets/crt-geom-ntsc-composite-sharp-tate.slangp @@ -0,0 +1,78 @@ +shaders = "6" +shader0 = "../misc/ntsc-colors.slang" +filter_linear0 = "false" +wrap_mode0 = "clamp_to_border" +mipmap_input0 = "false" +alias0 = "" +float_framebuffer0 = "false" +srgb_framebuffer0 = "false" +scale_type_x0 = "source" +scale_x0 = "1.000000" +scale_type_y0 = "source" +scale_y0 = "1.000000" +shader1 = "../ntsc/shaders/ntsc-adaptive-tate/ntsc-tate-pass1.slang" +filter_linear1 = "false" +wrap_mode1 = "clamp_to_border" +mipmap_input1 = "false" +alias1 = "" +float_framebuffer1 = "true" +srgb_framebuffer1 = "false" +scale_type_x1 = "source" +scale_x1 = "1.000000" +scale_type_y1 = "source" +scale_y1 = "4.000000" +shader2 = "../ntsc/shaders/ntsc-adaptive-tate/ntsc-tate-pass2.slang" +filter_linear2 = "false" +wrap_mode2 = "clamp_to_border" +mipmap_input2 = "false" +alias2 = "" +float_framebuffer2 = "false" +srgb_framebuffer2 = "false" +scale_type_x2 = "source" +scale_x2 = "1.000000" +scale_type_y2 = "source" +scale_y2 = "0.500000" +shader3 = "../warp/shaders/smart-morph.slang" +wrap_mode3 = "clamp_to_border" +mipmap_input3 = "false" +alias3 = "" +float_framebuffer3 = "false" +srgb_framebuffer3 = "false" +scale_type_x3 = "source" +scale_x3 = "1.000000" +scale_type_y3 = "source" +scale_y3 = "1.000000" +shader4 = "../sharpen/shaders/fast-sharpen.slang" +wrap_mode4 = "clamp_to_border" +mipmap_input4 = "false" +alias4 = "" +float_framebuffer4 = "false" +srgb_framebuffer4 = "false" +scale_type_x4 = "source" +scale_x4 = "1.000000" +scale_type_y4 = "source" +scale_y4 = "1.000000" +shader5 = "../crt/shaders/crt-geom.slang" +wrap_mode5 = "clamp_to_border" +mipmap_input5 = "false" +alias5 = "" +float_framebuffer5 = "false" +srgb_framebuffer5 = "false" + +intensity = "0.0" +quality = "0.0" +SM_RANGE = "2.0" +SM_PWR = "0.7" +CONTR = "0.15" + +CRTgamma = "2.2" +CURVATURE = "1.0" +d = "1.5" +R = "1.8" +cornersize = "0.0155" +y_tilt = "-0.05" +scanline_weight = "0.25" +DOTMASK = "0.0" +lum = "0.15" +interlace_detect = "0.0" +vertical_scanlines = "1.0" diff --git a/presets/crt-geom-ntsc-composite-sharp.slangp b/presets/crt-geom-ntsc-composite-sharp.slangp new file mode 100644 index 0000000..b7d0cd5 --- /dev/null +++ b/presets/crt-geom-ntsc-composite-sharp.slangp @@ -0,0 +1,77 @@ +shaders = "6" +shader0 = "../misc/ntsc-colors.slang" +filter_linear0 = "false" +wrap_mode0 = "clamp_to_border" +mipmap_input0 = "false" +alias0 = "" +float_framebuffer0 = "false" +srgb_framebuffer0 = "false" +scale_type_x0 = "source" +scale_x0 = "1.000000" +scale_type_y0 = "source" +scale_y0 = "1.000000" +shader1 = "../ntsc/shaders/ntsc-adaptive/ntsc-pass1.slang" +filter_linear1 = "false" +wrap_mode1 = "clamp_to_border" +mipmap_input1 = "false" +alias1 = "" +float_framebuffer1 = "true" +srgb_framebuffer1 = "false" +scale_type_x1 = "source" +scale_x1 = "4.000000" +scale_type_y1 = "source" +scale_y1 = "1.000000" +shader2 = "../ntsc/shaders/ntsc-adaptive/ntsc-pass2.slang" +filter_linear2 = "false" +wrap_mode2 = "clamp_to_border" +mipmap_input2 = "false" +alias2 = "" +float_framebuffer2 = "false" +srgb_framebuffer2 = "false" +scale_type_x2 = "source" +scale_x2 = "0.500000" +scale_type_y2 = "source" +scale_y2 = "1.000000" +shader3 = "../warp/shaders/smart-morph.slang" +wrap_mode3 = "clamp_to_border" +mipmap_input3 = "false" +alias3 = "" +float_framebuffer3 = "false" +srgb_framebuffer3 = "false" +scale_type_x3 = "source" +scale_x3 = "1.000000" +scale_type_y3 = "source" +scale_y3 = "1.000000" +shader4 = "../sharpen/shaders/fast-sharpen.slang" +wrap_mode4 = "clamp_to_border" +mipmap_input4 = "false" +alias4 = "" +float_framebuffer4 = "false" +srgb_framebuffer4 = "false" +scale_type_x4 = "source" +scale_x4 = "1.000000" +scale_type_y4 = "source" +scale_y4 = "1.000000" +shader5 = "../crt/shaders/crt-geom.slang" +wrap_mode5 = "clamp_to_border" +mipmap_input5 = "false" +alias5 = "" +float_framebuffer5 = "false" +srgb_framebuffer5 = "false" + +intensity = "0.0" +quality = "0.0" +SM_RANGE = "1.0" +SM_PWR = "0.7" +CONTR = "0.15" + +CRTgamma = "2.2" +CURVATURE = "1.0" +d = "1.5" +R = "1.8" +cornersize = "0.0155" +y_tilt = "-0.05" +scanline_weight = "0.25" +DOTMASK = "0.0" +lum = "0.15" +interlace_detect = "0.0" diff --git a/warp/shaders/smart-morph.slang b/warp/shaders/smart-morph.slang index 9ebd244..a298a3f 100644 --- a/warp/shaders/smart-morph.slang +++ b/warp/shaders/smart-morph.slang @@ -22,10 +22,11 @@ layout(push_constant) uniform Push vec4 OriginalSize; vec4 OutputSize; uint FrameCount; - float SM_MODE, SM_PWR, SM_STRMIN, SM_STRMAX, SM_CUTLO, SM_CUTHI, SM_DEBUG; + float SM_MODE, SM_RANGE, SM_PWR, SM_STRMIN, SM_STRMAX, SM_CUTLO, SM_CUTHI, SM_DEBUG; } params; #pragma parameter SM_MODE "SmartMorph Dilation / Erosion" 0.0 0.0 1.0 1.0 // Switches between dilation and erosion (line thinning or thickening). +#pragma parameter SM_RANGE "SmartMorph Range 0-multi 1-hor 2-vert" 0.0 0.0 2.0 1.0 // Switches between all directions / horizontal only / vertical only. #pragma parameter SM_PWR "SmartMorph Luma Exponent" 0.5 0.0 10.0 0.1 // range: [0.0, +inf) - Raises d by the exponent of PWR. Smaller values for stronger morphing. #pragma parameter SM_STRMIN "SmartMorph MIN Strength" 0.0 0.0 1.0 0.01 // range: [0.0, STRMAX] - Minimal strength to apply #pragma parameter SM_STRMAX "SmartMorph MAX Strength" 1.0 0.0 1.0 0.01 // range: [STRMIN, 1.0] - Maximal strength to apply. @@ -68,20 +69,39 @@ void main() vec3 E = TEX( 0., 0.).rgb; vec3 F = TEX( 1., 0.).rgb; vec3 H = TEX( 0., 1.).rgb; + vec3 res; - vec4 b = mul( mat4x3(B, D, H, F), y_weights ); float e = dot(E, y_weights); - float di = 0.0; - if(params.SM_MODE > 0.5){ - di = min(min(b.x, b.y), min(b.z, min(b.w, e))); - } - else{ - di = max(max(b.x, b.y), max(b.z, max(b.w, e))); - } + if (params.SM_RANGE == 2.0){ + vec2 b = mul( mat2x3(B, H), y_weights ); + if(params.SM_MODE > 0.5) + di = max(b.x, b.y); + else + di = min(b.x, b.y); + + res = (di==b.y) ? B : H; + } + else if (params.SM_RANGE == 1.0){ + vec2 b = mul( mat2x3(D,F), y_weights ); + if(params.SM_MODE > 0.5) + di = max(b.x, b.y); + else + di = min(b.x, b.y); + + res = (di==b.y) ? D : F; + } + else{ + vec4 b = mul( mat4x3(B, D, H, F), y_weights ); + if(params.SM_MODE > 0.5) + di = min(min(b.x, b.y), min(b.z, min(b.w, e))); + else + di = max(max(b.x, b.y), max(b.z, max(b.w, e))); + + res = (di==b.x) ? B : (di==b.y) ? D : (di==b.z) ? H : F; + } - vec3 res = (di==b.x) ? B : (di==b.y) ? D : (di==b.z) ? H : F; di = abs(e-di); float str = (di<=params.SM_CUTLO) ? params.SM_STRMIN : (di>=params.SM_CUTHI) ? params.SM_STRMAX : smoothstep( 0.0, 1.0, pow((di-params.SM_CUTLO)/(params.SM_CUTHI-params.SM_CUTLO), params.SM_PWR) ) * (params.SM_STRMAX-params.SM_STRMIN) + params.SM_STRMIN;