diff --git a/blurs/dual_filter_2_pass.slangp b/blurs/dual_filter_2_pass.slangp index 3dad1b1..621e1c7 100644 --- a/blurs/dual_filter_2_pass.slangp +++ b/blurs/dual_filter_2_pass.slangp @@ -7,7 +7,7 @@ scale_x0 = 1.0 scale_y0 = 1.0 float_framebuffer0 = true -shader1 = shaders/dual_filter_downsample.slang +shader1 = shaders/dual_filter/downsample.slang filter_linear1 = true scale_type1 = source scale_x1 = 0.5 @@ -15,7 +15,7 @@ scale_y1 = 0.5 float_framebuffer1 = true wrap_mode1 = mirrored_repeat -shader2 = shaders/dual_filter_upsample.slang +shader2 = shaders/dual_filter/upsample.slang filter_linear2 = true scale_type2 = source scale_x2 = 2.0 diff --git a/blurs/dual_filter_4_pass.slangp b/blurs/dual_filter_4_pass.slangp index e655cd7..a352a95 100644 --- a/blurs/dual_filter_4_pass.slangp +++ b/blurs/dual_filter_4_pass.slangp @@ -7,7 +7,7 @@ scale_x0 = 1.0 scale_y0 = 1.0 float_framebuffer0 = true -shader1 = shaders/dual_filter_downsample.slang +shader1 = shaders/dual_filter/downsample.slang filter_linear1 = true scale_type1 = source scale_x1 = 0.5 @@ -15,7 +15,7 @@ scale_y1 = 0.5 float_framebuffer1 = true wrap_mode1 = mirrored_repeat -shader2 = shaders/dual_filter_downsample.slang +shader2 = shaders/dual_filter/downsample.slang filter_linear2 = true scale_type2 = source scale_x2 = 0.5 @@ -23,7 +23,7 @@ scale_y2 = 0.5 float_framebuffer2 = true wrap_mode2 = mirrored_repeat -shader3 = shaders/dual_filter_upsample.slang +shader3 = shaders/dual_filter/upsample.slang filter_linear3 = true scale_type3 = source scale_x3 = 2.0 @@ -31,7 +31,7 @@ scale_y3 = 2.0 float_framebuffer3 = true wrap_mode3 = mirrored_repeat -shader4 = shaders/dual_filter_upsample.slang +shader4 = shaders/dual_filter/upsample.slang filter_linear4 = true scale_type4 = source scale_x4 = 2.0 diff --git a/blurs/dual_filter_6_pass.slangp b/blurs/dual_filter_6_pass.slangp index 181b8bf..873e487 100644 --- a/blurs/dual_filter_6_pass.slangp +++ b/blurs/dual_filter_6_pass.slangp @@ -7,7 +7,7 @@ scale_x0 = 1.0 scale_y0 = 1.0 float_framebuffer0 = true -shader1 = shaders/dual_filter_downsample.slang +shader1 = shaders/dual_filter/downsample.slang filter_linear1 = true scale_type1 = source scale_x1 = 0.5 @@ -15,7 +15,7 @@ scale_y1 = 0.5 float_framebuffer1 = true wrap_mode1 = mirrored_repeat -shader2 = shaders/dual_filter_downsample.slang +shader2 = shaders/dual_filter/downsample.slang filter_linear2 = true scale_type2 = source scale_x2 = 0.5 @@ -23,7 +23,7 @@ scale_y2 = 0.5 float_framebuffer2 = true wrap_mode2 = mirrored_repeat -shader3 = shaders/dual_filter_downsample.slang +shader3 = shaders/dual_filter/downsample.slang filter_linear3 = true scale_type3 = source scale_x3 = 0.5 @@ -31,7 +31,7 @@ scale_y3 = 0.5 float_framebuffer3 = true wrap_mode3 = mirrored_repeat -shader4 = shaders/dual_filter_upsample.slang +shader4 = shaders/dual_filter/upsample.slang filter_linear4 = true scale_type4 = source scale_x4 = 2.0 @@ -39,7 +39,7 @@ scale_y4 = 2.0 float_framebuffer4 = true wrap_mode4 = mirrored_repeat -shader5 = shaders/dual_filter_upsample.slang +shader5 = shaders/dual_filter/upsample.slang filter_linear5 = true scale_type5 = source scale_x5 = 2.0 @@ -47,7 +47,7 @@ scale_y5 = 2.0 float_framebuffer5 = true wrap_mode5 = mirrored_repeat -shader6 = shaders/dual_filter_upsample.slang +shader6 = shaders/dual_filter/upsample.slang filter_linear6 = true scale_type6 = source scale_x6 = 2.0 diff --git a/blurs/dual_filter_bloom.slangp b/blurs/dual_filter_bloom.slangp new file mode 100644 index 0000000..32bd54f --- /dev/null +++ b/blurs/dual_filter_bloom.slangp @@ -0,0 +1,187 @@ +shaders = 24 + +parameters = "BLUR_RADIUS" +BLUR_RADIUS = 2.0 + +shader0 = shaders/kawase/linearize.slang +scale_type0 = source +scale0 = 1.0 +float_framebuffer0 = true +alias0 = "Input" + + +shader1 = shaders/dual_filter/downsample_bloom.slang +filter_linear1 = true +scale_type1 = viewport +scale1 = 0.7 +float_framebuffer1 = true +wrap_mode1 = mirrored_repeat + +shader2 = shaders/dual_filter/upsample.slang +filter_linear2 = true +scale_type2 = source +scale2 = 1.0 +float_framebuffer2 = true +wrap_mode2 = mirrored_repeat + +shader3 = shaders/dual_filter/downsample.slang +filter_linear3 = true +scale_type3 = source +scale3 = 0.5 +float_framebuffer3 = true +wrap_mode3 = mirrored_repeat + +shader4 = shaders/dual_filter/upsample.slang +filter_linear4 = true +scale_type4 = source +scale4 = 2.0 +float_framebuffer4 = true +wrap_mode4 = mirrored_repeat +alias4 = "Scale1" + + +shader5 = shaders/dual_filter/downsample.slang +filter_linear5 = true +scale_type5 = source +scale5 = 0.5 +float_framebuffer5 = true +wrap_mode5 = mirrored_repeat + +shader6 = shaders/dual_filter/downsample.slang +filter_linear6 = true +scale_type6 = source +scale6 = 0.5 +float_framebuffer6 = true +wrap_mode6 = mirrored_repeat + +shader7 = shaders/dual_filter/upsample.slang +filter_linear7 = true +scale_type7 = source +scale7 = 2.0 +float_framebuffer7 = true +wrap_mode7 = mirrored_repeat +alias7 = "Scale2" + + +shader8 = shaders/dual_filter/downsample.slang +filter_linear8 = true +scale_type8 = source +scale8 = 0.5 +float_framebuffer8 = true +wrap_mode8 = mirrored_repeat + +shader9 = shaders/dual_filter/downsample.slang +filter_linear9 = true +scale_type9 = source +scale9 = 0.5 +float_framebuffer9 = true +wrap_mode9 = mirrored_repeat + +shader10 = shaders/dual_filter/upsample.slang +filter_linear10 = true +scale_type10 = source +scale10 = 2.0 +float_framebuffer10 = true +wrap_mode10 = mirrored_repeat +alias10 = "Scale3" + + +shader11 = shaders/dual_filter/downsample.slang +filter_linear11 = true +scale_type11 = source +scale11 = 0.5 +float_framebuffer11 = true +wrap_mode11 = mirrored_repeat + +shader12 = shaders/dual_filter/downsample.slang +filter_linear12 = true +scale_type12 = source +scale12 = 0.5 +float_framebuffer12 = true +wrap_mode12 = mirrored_repeat + +shader13 = shaders/dual_filter/upsample.slang +filter_linear13 = true +scale_type13 = source +scale13 = 2.0 +float_framebuffer13 = true +wrap_mode13 = mirrored_repeat +alias13 = "Scale4" + + +shader14 = shaders/dual_filter/downsample.slang +filter_linear14 = true +scale_type14 = source +scale14 = 0.5 +float_framebuffer14 = true +wrap_mode14 = mirrored_repeat + +shader15 = shaders/dual_filter/downsample.slang +filter_linear15 = true +scale_type15 = source +scale15 = 0.5 +float_framebuffer15 = true +wrap_mode15 = mirrored_repeat + +shader16 = shaders/dual_filter/upsample.slang +filter_linear16 = true +scale_type16 = source +scale16 = 2.0 +float_framebuffer16 = true +wrap_mode16 = mirrored_repeat +alias16 = "Scale5" + + +shader17 = shaders/dual_filter/downsample.slang +filter_linear17 = true +scale_type17 = source +scale17 = 0.5 +float_framebuffer17 = true +wrap_mode17 = mirrored_repeat + +shader18 = shaders/dual_filter/downsample.slang +filter_linear18 = true +scale_type18 = source +scale18 = 0.5 +float_framebuffer18 = true +wrap_mode18 = mirrored_repeat + +shader19 = shaders/dual_filter/upsample.slang +filter_linear19 = true +scale_type19 = source +scale19 = 2.0 +float_framebuffer19 = true +wrap_mode19 = mirrored_repeat +alias19 = "Scale6" + + +shader20 = shaders/dual_filter/naive_resample.slang +filter_linear20 = true +scale_type20 = absolute +scale_x20 = 128 +scale_y20 = 128 +float_framebuffer20 = true +wrap_mode20 = mirrored_repeat + +shader21 = shaders/dual_filter/moving_avg.slang +filter_linear21 = true +scale_type21 = absolute +scale_x21 = 2 +scale_y21 = 2 +float_framebuffer21 = true +mipmap_input21 = true +alias21 = "MovingAverage" + + +shader22 = shaders/dual_filter/bloom_blend.slang +filter_linear22 = true +scale_type22 = viewport +scale22 = 1.0 +float_framebuffer22 = true + + +shader23 = shaders/kawase/delinearize.slang +filter_linear23 = true +scale_type23 = viewport +scal23 = 1.0 +float_framebuffer23 = true diff --git a/blurs/dual_filter_bloom_fast.slangp b/blurs/dual_filter_bloom_fast.slangp new file mode 100644 index 0000000..4a3c08b --- /dev/null +++ b/blurs/dual_filter_bloom_fast.slangp @@ -0,0 +1,138 @@ +shaders = 18 + +shader0 = shaders/kawase/linearize.slang +scale_type0 = source +scale0 = 1.0 +float_framebuffer0 = true +alias0 = "Input" + + +shader1 = shaders/dual_filter/downsample_bloom.slang +filter_linear1 = true +scale_type1 = viewport +scale1 = 0.4 +float_framebuffer1 = true +wrap_mode1 = mirrored_repeat + +shader2 = shaders/dual_filter/upsample.slang +filter_linear2 = true +scale_type2 = source +scale2 = 1.0 +float_framebuffer2 = true +wrap_mode2 = mirrored_repeat + +shader3 = shaders/dual_filter/downsample.slang +filter_linear3 = true +scale_type3 = source +scale3 = 0.5 +float_framebuffer3 = true +wrap_mode3 = mirrored_repeat + +shader4 = shaders/dual_filter/upsample.slang +filter_linear4 = true +scale_type4 = source +scale4 = 2.0 +float_framebuffer4 = true +wrap_mode4 = mirrored_repeat +alias4 = "Scale1" + + +shader5 = shaders/dual_filter/downsample.slang +filter_linear5 = true +scale_type5 = source +scale5 = 0.5 +float_framebuffer5 = true +wrap_mode5 = mirrored_repeat + +shader6 = shaders/dual_filter/downsample.slang +filter_linear6 = true +scale_type6 = source +scale6 = 0.5 +float_framebuffer6 = true +wrap_mode6 = mirrored_repeat + +shader7 = shaders/dual_filter/upsample.slang +filter_linear7 = true +scale_type7 = source +scale7 = 2.0 +float_framebuffer7 = true +wrap_mode7 = mirrored_repeat +alias7 = "Scale2" + + +shader8 = shaders/dual_filter/downsample.slang +filter_linear8 = true +scale_type8 = source +scale8 = 0.5 +float_framebuffer8 = true +wrap_mode8 = mirrored_repeat + +shader9 = shaders/dual_filter/downsample.slang +filter_linear9 = true +scale_type9 = source +scale9 = 0.5 +float_framebuffer9 = true +wrap_mode9 = mirrored_repeat + +shader10 = shaders/dual_filter/upsample.slang +filter_linear10 = true +scale_type10 = source +scale10 = 2.0 +float_framebuffer10 = true +wrap_mode10 = mirrored_repeat +alias10 = "Scale3" + + +shader11 = shaders/dual_filter/downsample.slang +filter_linear11 = true +scale_type11 = source +scale11 = 0.5 +float_framebuffer11 = true +wrap_mode11 = mirrored_repeat + +shader12 = shaders/dual_filter/downsample.slang +filter_linear12 = true +scale_type12 = source +scale12 = 0.5 +float_framebuffer12 = true +wrap_mode12 = mirrored_repeat + +shader13 = shaders/dual_filter/upsample.slang +filter_linear13 = true +scale_type13 = source +scale13 = 2.0 +float_framebuffer13 = true +wrap_mode13 = mirrored_repeat +alias13 = "Scale4" + + +shader14 = shaders/dual_filter/naive_resample.slang +filter_linear14 = true +scale_type14 = absolute +scale_x14 = 64 +scale_y14 = 64 +float_framebuffer14 = true +wrap_mode14 = mirrored_repeat + +shader15 = shaders/dual_filter/moving_avg.slang +filter_linear15 = true +scale_type15 = absolute +scale_x15 = 2 +scale_y15 = 2 +float_framebuffer15 = true +mipmap_input15 = true +alias15 = "MovingAverage" + + +shader16 = shaders/dual_filter/bloom_blend_fast.slang +filter_linear16 = true +scale_type16 = viewport +scale16 = 1.0 +float_framebuffer16 = true + + +shader17 = shaders/kawase/delinearize.slang +filter_linear17 = true +scale_type17 = viewport +scal17 = 1.0 +float_framebuffer17 = true diff --git a/blurs/dual_filter_bloom_fastest.slangp b/blurs/dual_filter_bloom_fastest.slangp new file mode 100644 index 0000000..3c97ea2 --- /dev/null +++ b/blurs/dual_filter_bloom_fastest.slangp @@ -0,0 +1,65 @@ +shaders = 8 + +parameters = "MIN_EXP_INTENSITY" +MIN_EXP_INTENSITY = 0.45 + +shader0 = shaders/kawase/linearize.slang +scale_type0 = source +scale0 = 1.0 +float_framebuffer0 = true +alias0 = "Input" + +shader1 = shaders/dual_filter/downsample_bloom.slang +filter_linear1 = false +scale_type1 = source +scale1 = 0.5 +float_framebuffer1 = true +wrap_mode1 = mirrored_repeat +alias1 = "Downsample1" + +shader2 = shaders/dual_filter/downsample.slang +filter_linear2 = true +scale_type2 = source +scale2 = 0.5 +float_framebuffer2 = true +wrap_mode2 = mirrored_repeat +alias2 = "Downsample2" + +shader3 = shaders/dual_filter/upsample.slang +filter_linear3 = true +scale_type3 = source +scale3 = 2.0 +float_framebuffer3 = true +wrap_mode3 = mirrored_repeat +alias3 = "Upsample" + +shader4 = shaders/dual_filter/naive_resample.slang +filter_linear4 = true +scale_type4 = absolute +scale_x4 = 64 +scale_y4 = 64 +float_framebuffer4 = true + +shader5 = shaders/dual_filter/moving_avg.slang +filter_linear5 = true +scale_type5 = absolute +scale_x5 = 2 +scale_y5 = 2 +float_framebuffer5 = true +wrap_mode5 = mirrored_repeat +mipmap_input5 = true +alias5 = "MovingAverage" + +shader6 = shaders/dual_filter/bloom_blend_fastest.slang +filter_linear6 = true +scale_type6 = viewport +scale6 = 1.0 +wrap_mode6 = mirrored_repeat +float_framebuffer6 = true + +shader7 = shaders/kawase/delinearize.slang +filter_linear7 = false +scale_type7 = viewport +scale7 = 1.0 +float_framebuffer7 = true + diff --git a/blurs/shaders/dual_filter/bloom_blend.slang b/blurs/shaders/dual_filter/bloom_blend.slang new file mode 100644 index 0000000..17ae0a0 --- /dev/null +++ b/blurs/shaders/dual_filter/bloom_blend.slang @@ -0,0 +1,108 @@ +#version 450 + +// See dual_filter.slang for copyright and other information. + +#include "dual_filter.slang" +#include "parameters.slang" +#include "parameters_bloom.slang" +#include "tonemapping.slang" + +#pragma parameter SCALE_EMPH "Bloom scale emphasis" 1.0 0.0 5.0 0.1 +#pragma parameter SCALE_SPREAD "Bloom scale spread" 5.0 0.5 15.0 0.5 +#pragma parameter DEBUG_EXPOSURE_GRAPH "Debug overlay: Exposure graph" 0.0 0.0 1.0 1.0 + +layout(push_constant) uniform Push { + vec4 SourceSize; + vec4 OriginalSize; + vec4 OutputSize; + vec4 InputSize; + uint FrameCount; + float MIN_EXP_INTENSITY; + float EYE_ADAPTION; + float MIN_EXP; + float MAX_EXP; + float SCALE_EMPH; + float SCALE_SPREAD; + float DEBUG_EXPOSURE_GRAPH; +} +param; + +layout(std140, set = 0, binding = 0) uniform UBO { + mat4 MVP; +} +global; + +#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; +} + +#pragma stage fragment +layout(location = 0) in vec2 vTexCoord; +layout(location = 0) out vec4 FragColor; +layout(set = 0, binding = 2) uniform sampler2D Source; +layout(set = 0, binding = 3) uniform sampler2D Input; +layout(set = 0, binding = 4) uniform sampler2D MovingAverage; +layout(set = 0, binding = 5) uniform sampler2D Scale1; +layout(set = 0, binding = 6) uniform sampler2D Scale2; +layout(set = 0, binding = 7) uniform sampler2D Scale3; +layout(set = 0, binding = 8) uniform sampler2D Scale4; +layout(set = 0, binding = 9) uniform sampler2D Scale5; +layout(set = 0, binding = 10) uniform sampler2D Scale6; + +float scale_gauss(float x) { + const float dx = x - param.SCALE_EMPH; + return exp(-dx * dx / (2.0 * param.SCALE_SPREAD * param.SCALE_SPREAD)); +} + +void main() { + // Weigh the different scale levels. + const float w1 = scale_gauss(0.0); + const float w2 = scale_gauss(1.0); + const float w3 = scale_gauss(2.0); + const float w4 = scale_gauss(3.0); + const float w5 = scale_gauss(4.0); + const float w6 = scale_gauss(5.0); + vec3 bloom = w1 * texture(Scale1, vTexCoord).rgb + // + w2 * texture(Scale2, vTexCoord).rgb + // + w3 * texture(Scale3, vTexCoord).rgb + // + w4 * texture(Scale4, vTexCoord).rgb + // + w5 * texture(Scale5, vTexCoord).rgb + // + w6 * texture(Scale6, vTexCoord).rgb / (w1 + w2 + w3 + w4 + w5 + w6); + + // Moving average luminance sampled from respective pass. + const vec3 ambient = texture(MovingAverage, vec2(0.5)).rgb; + bloom = + tonemap(bloom * ambient_to_intensity(ambient, param.MIN_EXP_INTENSITY, + param.MIN_EXP_INTENSITY * (1.0 - param.EYE_ADAPTION), + param.MIN_EXP, param.MAX_EXP)); + + const vec2 sharp_coord = (floor(vTexCoord * param.InputSize.xy) + 0.5) * param.InputSize.zw; + FragColor = vec4(blend_screen(bloom, texture(Input, sharp_coord).rgb), 1.0); + + if (param.DEBUG_EXPOSURE_GRAPH > 0.5) { + // Debug output. + // This is manually copied from tonemapping code, need to maintain here if things change. + float exposure = sqrt(dot(vec3(0.30, 0.59, 0.11), ambient)); + float mapped_exp = ambient_to_intensity( + ambient, param.MIN_EXP_INTENSITY, param.MIN_EXP_INTENSITY * (1.0 - param.EYE_ADAPTION), + param.MIN_EXP, param.MAX_EXP); + const float graph_x = vTexCoord.x * vTexCoord.x; + float graph_y = + mix(param.MIN_EXP_INTENSITY, param.MIN_EXP_INTENSITY * (1.0 - param.EYE_ADAPTION), + smoothstep(param.MIN_EXP, param.MAX_EXP, sqrt(graph_x))); + if (abs(1.0 - vTexCoord.y - graph_y) < 0.01) { + FragColor = vec4(0.0, 0.0, 1.0, 1.0); + } + const float dx = vTexCoord.x - exposure; + const float dy = 1.0 - vTexCoord.y - mapped_exp; + if (sqrt(dx * dx + dy * dy) < 0.02) { + FragColor = vec4(0.2, 0.2, 1.0, 1.0); + } + } +} diff --git a/blurs/shaders/dual_filter/bloom_blend_fast.slang b/blurs/shaders/dual_filter/bloom_blend_fast.slang new file mode 100644 index 0000000..ebb1a6c --- /dev/null +++ b/blurs/shaders/dual_filter/bloom_blend_fast.slang @@ -0,0 +1,79 @@ +#version 450 + +// See dual_filter.slang for copyright and other information. + +#include "dual_filter.slang" +#include "parameters.slang" +#include "parameters_bloom.slang" +#include "tonemapping.slang" + +#pragma parameter SCALE_EMPH "Bloom scale emphasis" 0.0 0.0 3.0 0.1 +#pragma parameter SCALE_SPREAD "Bloom scale spread" 4.0 0.5 10.0 0.5 + +layout(push_constant) uniform Push { + vec4 SourceSize; + vec4 OriginalSize; + vec4 OutputSize; + vec4 InputSize; + uint FrameCount; + float MIN_EXP_INTENSITY; + float EYE_ADAPTION; + float MIN_EXP; + float MAX_EXP; + float SCALE_EMPH; + float SCALE_SPREAD; +} +param; + +layout(std140, set = 0, binding = 0) uniform UBO { + mat4 MVP; +} +global; + +#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; +} + +#pragma stage fragment +layout(location = 0) in vec2 vTexCoord; +layout(location = 0) out vec4 FragColor; +layout(set = 0, binding = 2) uniform sampler2D Source; +layout(set = 0, binding = 3) uniform sampler2D Input; +layout(set = 0, binding = 4) uniform sampler2D MovingAverage; +layout(set = 0, binding = 5) uniform sampler2D Scale1; +layout(set = 0, binding = 6) uniform sampler2D Scale2; +layout(set = 0, binding = 7) uniform sampler2D Scale3; +layout(set = 0, binding = 8) uniform sampler2D Scale4; + +float scale_gauss(float x) { + const float dx = x - param.SCALE_EMPH; + return exp(-dx * dx / (2.0 * param.SCALE_SPREAD * param.SCALE_SPREAD)); +} + +void main() { + // Weigh the different scale levels. + const float w1 = scale_gauss(0.0); + const float w2 = scale_gauss(1.0); + const float w3 = scale_gauss(2.0); + const float w4 = scale_gauss(3.0); + vec3 bloom = w1 * texture(Scale1, vTexCoord).rgb + // + w2 * texture(Scale2, vTexCoord).rgb + // + w3 * texture(Scale3, vTexCoord).rgb + // + w4 * texture(Scale4, vTexCoord).rgb / (w1 + w2 + w3 + w4); + + // Moving average luminance sampled from respective pass. + const vec3 ambient = texture(MovingAverage, vec2(0.5)).rgb; + bloom = + tonemap(bloom * ambient_to_intensity(ambient, param.MIN_EXP_INTENSITY, + param.MIN_EXP_INTENSITY * (1.0 - param.EYE_ADAPTION), + param.MIN_EXP, param.MAX_EXP)); + + const vec2 sharp_coord = (floor(vTexCoord * param.InputSize.xy) + 0.5) * param.InputSize.zw; + FragColor = vec4(blend_screen(bloom, texture(Input, sharp_coord).rgb), 1.0); +} diff --git a/blurs/shaders/dual_filter/bloom_blend_fastest.slang b/blurs/shaders/dual_filter/bloom_blend_fastest.slang new file mode 100644 index 0000000..15d3397 --- /dev/null +++ b/blurs/shaders/dual_filter/bloom_blend_fastest.slang @@ -0,0 +1,63 @@ +#version 450 + +// See dual_filter.slang for copyright and other information. + +#include "dual_filter.slang" +#include "parameters.slang" +#include "parameters_bloom.slang" +#include "tonemapping.slang" + +layout(push_constant) uniform Push { + vec4 InputSize; + vec4 Downsample1Size; + vec4 Downsample2Size; + vec4 UpsampleSize; + float BLUR_RADIUS; + float MIN_EXP_INTENSITY; + float EYE_ADAPTION; + float MIN_EXP; + float MAX_EXP; +} +param; + +layout(std140, set = 0, binding = 0) uniform UBO { + mat4 MVP; +} +global; + +#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; +} + +#pragma stage fragment +layout(location = 0) in vec2 vTexCoord; +layout(location = 0) out vec4 FragColor; +layout(set = 0, binding = 2) uniform sampler2D Source; +layout(set = 0, binding = 3) uniform sampler2D Input; +layout(set = 0, binding = 4) uniform sampler2D Downsample1; +layout(set = 0, binding = 5) uniform sampler2D Downsample2; +layout(set = 0, binding = 6) uniform sampler2D Upsample; +layout(set = 0, binding = 7) uniform sampler2D MovingAverage; + +void main() { + const vec3 ambient = texture(MovingAverage, vec2(0.5)).rgb; + // Hack: "Fastest" bloom appears relatively less intense compared to the regular preset. + // Using an unnormalized value achieves about equal intensity. + vec3 bloom = + 3.0 * upsample(Downsample1, vTexCoord, 0.5 * param.Downsample1Size.zw * param.BLUR_RADIUS) + + 1.0 * upsample(Downsample2, vTexCoord, 0.5 * param.Downsample2Size.zw * param.BLUR_RADIUS) + + 3.0 * upsample(Upsample, vTexCoord, 0.5 * param.UpsampleSize.zw * param.BLUR_RADIUS); + bloom = + tonemap(bloom * ambient_to_intensity(ambient, param.MIN_EXP_INTENSITY, + param.MIN_EXP_INTENSITY * (1.0 - param.EYE_ADAPTION), + param.MIN_EXP, param.MAX_EXP)); + + const vec2 sharp_coord = (floor(vTexCoord * param.InputSize.xy) + 0.5) * param.InputSize.zw; + FragColor = vec4(blend_screen(bloom, texture(Input, sharp_coord).rgb), 1.0); +} diff --git a/blurs/shaders/dual_filter_downsample.slang b/blurs/shaders/dual_filter/downsample.slang similarity index 52% rename from blurs/shaders/dual_filter_downsample.slang rename to blurs/shaders/dual_filter/downsample.slang index f775432..2f6365a 100644 --- a/blurs/shaders/dual_filter_downsample.slang +++ b/blurs/shaders/dual_filter/downsample.slang @@ -1,15 +1,16 @@ #version 450 -// See dual_filter_parameters.slang for copyright and other information. +// See dual_filter.slang for copyright and other information. -#include "dual_filter_parameters.slang" +#include "dual_filter.slang" +#include "parameters.slang" layout(push_constant) uniform Push { vec4 SourceSize; vec4 OriginalSize; vec4 OutputSize; uint FrameCount; - float BLUR_STRENGTH; + float BLUR_RADIUS; } param; @@ -34,11 +35,6 @@ layout(location = 0) out vec4 FragColor; layout(set = 0, binding = 2) uniform sampler2D Source; void main() { - const vec2 halfpixel = 0.5 * param.SourceSize.zw * param.BLUR_STRENGTH; - vec3 sum = texture(Source, vTexCoord).rgb * 4.0; - sum += texture(Source, vTexCoord - halfpixel).rgb; - sum += texture(Source, vTexCoord + halfpixel).rgb; - sum += texture(Source, vTexCoord + vec2(halfpixel.x, -halfpixel.y)).rgb; - sum += texture(Source, vTexCoord - vec2(halfpixel.x, -halfpixel.y)).rgb; - FragColor = vec4(sum * 0.125, 1.0); + const vec2 offset = param.SourceSize.zw * param.BLUR_RADIUS; + FragColor = vec4(downsample(Source, vTexCoord, offset), 1.0); } diff --git a/blurs/shaders/dual_filter/downsample_bloom.slang b/blurs/shaders/dual_filter/downsample_bloom.slang new file mode 100644 index 0000000..759041b --- /dev/null +++ b/blurs/shaders/dual_filter/downsample_bloom.slang @@ -0,0 +1,44 @@ +#version 450 + +// See dual_filter.slang for copyright and other information. + +#include "dual_filter.slang" +#include "parameters.slang" +#include "parameters_bloom.slang" + +layout(push_constant) uniform Push { + vec4 SourceSize; + vec4 OriginalSize; + vec4 OutputSize; + uint FrameCount; + float BLUR_RADIUS; + float BLOOM_THRESHOLD; +} +param; + +layout(std140, set = 0, binding = 0) uniform UBO { + mat4 MVP; +} +global; + +#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; +} + +#pragma stage fragment +layout(location = 0) in vec2 vTexCoord; +layout(location = 0) out vec4 FragColor; +layout(set = 0, binding = 2) uniform sampler2D Source; + +void main() { + // Use the output pixel size as reference here to be more robust against different bloom + // configurations. + const vec2 offset = 0.5 * param.OutputSize.zw * param.BLUR_RADIUS; + FragColor = vec4(pow(downsample(Source, vTexCoord, offset), vec3(param.BLOOM_THRESHOLD)), 1.0); +} diff --git a/blurs/shaders/dual_filter/dual_filter.slang b/blurs/shaders/dual_filter/dual_filter.slang new file mode 100644 index 0000000..650ecbe --- /dev/null +++ b/blurs/shaders/dual_filter/dual_filter.slang @@ -0,0 +1,57 @@ +/* + Dual Filter Blur & Bloom v1.1 by fishku + Copyright (C) 2023 + Public domain license (CC0) + + The dual filter blur implementation follows the notes of the SIGGRAPH 2015 talk here: + https://community.arm.com/cfs-file/__key/communityserver-blogs-components-weblogfiles/00-00-00-20-66/siggraph2015_2D00_mmg_2D00_marius_2D00_notes.pdf + Dual filtering is a fast large-radius blur that approximates a Gaussian blur. It is closely + related to the popular blur filter by Kawase, but runs faster at equal quality. + + How it works: Any number of downsampling passes are chained with the same number of upsampling + passes in an hourglass configuration. Both types of resampling passes exploit bilinear + interpolation with carefully chosen coordinates and weights to produce a smooth output. + There are just 5 + 8 = 13 texture samples per combined down- and upsampling pass. + The effective blur radius increases with the number of passes. + + This implementation adds a configurable blur strength which can diminish or accentuate the + effect compared to the reference implementation, equivalent to strength 1.0. + A blur strength above 3.0 may lead to artifacts, especially on presets with fewer passes. + + The bloom filter applies a thresholding operation, then blurs the input to varying degrees. + The scene luminance is estimated using a feedback pass with variable update speed. + The final pass screen blends a tonemapped bloom value with the original input, with the bloom + intensity controlled by the scene luminance (a.k.a. eye adaption). + + Changelog: + v1.1: Added bloom functionality. + v1.0: Initial release. +*/ + +vec3 downsample(sampler2D tex, vec2 coord, vec2 offset) { + // The offset should be 1 source pixel size which equals 0.5 output pixel sizes in the default + // configuration. + return (texture(tex, coord - offset).rgb + // + texture(tex, coord + vec2(offset.x, -offset.y)).rgb + // + texture(tex, coord).rgb * 4.0 + // + texture(tex, coord + offset).rgb + // + texture(tex, coord - vec2(offset.x, -offset.y)).rgb) * + 0.125; +} + +vec3 upsample(sampler2D tex, vec2 coord, vec2 offset) { + // The offset should be 0.5 source pixel sizes which equals 1 output pixel size in the default + // configuration. + return (texture(tex, coord + vec2(0.0, -offset.y * 2.0)).rgb + + (texture(tex, coord + vec2(-offset.x, -offset.y)).rgb + + texture(tex, coord + vec2(offset.x, -offset.y)).rgb) * + 2.0 + + texture(tex, coord + vec2(-offset.x * 2.0, 0.0)).rgb + + texture(tex, coord + vec2(offset.x * 2.0, 0.0)).rgb + + (texture(tex, coord + vec2(-offset.x, offset.y)).rgb + + texture(tex, coord + vec2(offset.x, offset.y)).rgb) * + 2.0 + + texture(tex, coord + vec2(0.0, offset.y * 2.0)).rgb) / + 12.0; +} + diff --git a/blurs/shaders/dual_filter/moving_avg.slang b/blurs/shaders/dual_filter/moving_avg.slang new file mode 100644 index 0000000..7d1c4ac --- /dev/null +++ b/blurs/shaders/dual_filter/moving_avg.slang @@ -0,0 +1,42 @@ +#version 450 + +// See dual_filter.slang for copyright and other information. + +#include "parameters.slang" +#include "parameters_bloom.slang" + +layout(push_constant) uniform Push { + vec4 SourceSize; + vec4 OriginalSize; + vec4 OutputSize; + uint FrameCount; + float ADAPT_SPEED; +} +param; + +layout(std140, set = 0, binding = 0) uniform UBO { + mat4 MVP; +} +global; + +#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; +} + +#pragma stage fragment +layout(location = 0) in vec2 vTexCoord; +layout(location = 0) out vec4 FragColor; +layout(set = 0, binding = 2) uniform sampler2D Source; +layout(set = 0, binding = 3) uniform sampler2D MovingAverageFeedback; + +void main() { + FragColor = vec4(mix(texture(MovingAverageFeedback, vTexCoord).rgb, + textureLod(Source, vTexCoord, 9000.1).rgb, param.ADAPT_SPEED), + 1.0); +} diff --git a/blurs/shaders/dual_filter/naive_resample.slang b/blurs/shaders/dual_filter/naive_resample.slang new file mode 100644 index 0000000..6f2c89f --- /dev/null +++ b/blurs/shaders/dual_filter/naive_resample.slang @@ -0,0 +1,35 @@ +#version 450 + +// This is simply stock.slang with a custom input sampler. + +layout(push_constant) uniform Push { + vec4 SourceSize; + vec4 OriginalSize; + vec4 OutputSize; + uint FrameCount; +} +params; + +layout(std140, set = 0, binding = 0) uniform UBO { + mat4 MVP; +} +global; + +#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; +} + +#pragma stage fragment +layout(location = 0) in vec2 vTexCoord; +layout(location = 0) out vec4 FragColor; +layout(set = 0, binding = 2) uniform sampler2D Input; + +void main() { + FragColor = vec4(texture(Input, vTexCoord).rgb, 1.0); +} diff --git a/blurs/shaders/dual_filter/parameters.slang b/blurs/shaders/dual_filter/parameters.slang new file mode 100644 index 0000000..ccc3b19 --- /dev/null +++ b/blurs/shaders/dual_filter/parameters.slang @@ -0,0 +1,6 @@ +// See dual_filter.slang for copyright and other information. + +// clang-format off +#pragma parameter DUAL_FILTER_SETTINGS "=== Dual Filter Blur & Bloom v1.1 settings ===" 0.0 0.0 1.0 1.0 +#pragma parameter BLUR_RADIUS "Blur radius" 1.0 0.1 7.5 0.1 +// clang-format on diff --git a/blurs/shaders/dual_filter/parameters_bloom.slang b/blurs/shaders/dual_filter/parameters_bloom.slang new file mode 100644 index 0000000..e9b7b17 --- /dev/null +++ b/blurs/shaders/dual_filter/parameters_bloom.slang @@ -0,0 +1,8 @@ +// clang-format off +#pragma parameter MIN_EXP_INTENSITY "Bloom intensity" 0.6 0.0 2.0 0.05 +#pragma parameter BLOOM_THRESHOLD "Bloom threshold" 3.5 1.0 10.0 0.1 +#pragma parameter ADAPT_SPEED "Eye adaptation speed" 0.1 0.0 1.0 0.01 +#pragma parameter EYE_ADAPTION "Eye adaptation strength: Reduce bloom on bright screens" 0.8 0.0 1.0 0.05 +#pragma parameter MIN_EXP "Minimum exposure value (where bloom is strongest)" 0.1 0.0 0.95 0.01 +#pragma parameter MAX_EXP "Maximum exposure value (where bloom is weakest)" 0.55 0.05 1.0 0.01 +// clang-format on \ No newline at end of file diff --git a/blurs/shaders/dual_filter/tonemapping.slang b/blurs/shaders/dual_filter/tonemapping.slang new file mode 100644 index 0000000..fd2e3e6 --- /dev/null +++ b/blurs/shaders/dual_filter/tonemapping.slang @@ -0,0 +1,46 @@ +// See dual_filter.slang for copyright and other information. + +// Tonemapping following +// http://filmicworlds.com/blog/filmic-tonemapping-with-piecewise-power-curves/ +// Parameters: +// toeStrength = 0.5 +// toeLength = 0.5 +// shoulderStrength = 2.0 +// shoulderLength = 0.5 +// shoulderAngle = 1.0 +float tonemap(float x) { + x = clamp(x, 0.0, 16.0); + x *= 0.246645; + if (x < 0.026840) { + // Toe + const float y0 = exp(4.324533 + 2.0 * log(x + 1.e-8)); + return y0 * 0.529110; + } else if (x < 0.143452) { + // Linear + const float x0 = x - 0.013420; + const float y0 = 4.054409 * x0; + return y0 * 0.529110; + } else { + // Shoulder + const float x0 = 5.0 - x; + const float y0 = exp(-20.740919 + 13.369429 * log(x0 + 1.e-8)); + return y0 * -0.529110 + 1.058221; + } +} +vec3 tonemap(vec3 x) { + return vec3(tonemap(x.r), tonemap(x.g), tonemap(x.b)); +} + +float ambient_to_intensity(vec3 ambient, float min_exp_intensity, float max_exp_intensity, + float min_exp, float max_exp) { + // Moving average luminance sampled from respective pass. + float exposure = dot(vec3(0.30, 0.59, 0.11), ambient); + // Lift up exposure value for better control. + exposure = sqrt(exposure); + // Map from exposure value to bloom intensity, and then to final value + return mix(min_exp_intensity, max_exp_intensity, smoothstep(min_exp, max_exp, exposure)); +} + +vec3 blend_screen(vec3 a, vec3 b) { + return 1.0 - (1.0 - a) * (1.0 - b); +} diff --git a/blurs/shaders/dual_filter/upsample.slang b/blurs/shaders/dual_filter/upsample.slang new file mode 100644 index 0000000..98b87ee --- /dev/null +++ b/blurs/shaders/dual_filter/upsample.slang @@ -0,0 +1,40 @@ +#version 450 + +// See dual_filter.slang for copyright and other information. + +#include "dual_filter.slang" +#include "parameters.slang" + +layout(push_constant) uniform Push { + vec4 SourceSize; + vec4 OriginalSize; + vec4 OutputSize; + uint FrameCount; + float BLUR_RADIUS; +} +param; + +layout(std140, set = 0, binding = 0) uniform UBO { + mat4 MVP; +} +global; + +#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; +} + +#pragma stage fragment +layout(location = 0) in vec2 vTexCoord; +layout(location = 0) out vec4 FragColor; +layout(set = 0, binding = 2) uniform sampler2D Source; + +void main() { + const vec2 offset = 0.5 * param.SourceSize.zw * param.BLUR_RADIUS; + FragColor = vec4(upsample(Source, vTexCoord, offset), 1.0); +} diff --git a/blurs/shaders/dual_filter_parameters.slang b/blurs/shaders/dual_filter_parameters.slang deleted file mode 100644 index c05cf33..0000000 --- a/blurs/shaders/dual_filter_parameters.slang +++ /dev/null @@ -1,28 +0,0 @@ -/* - Dual filter v1.0, ported to Slang by fishku - Copyright (C) 2023 - Public domain license (CC0) - - Follows the notes of the SIGGRAPH 2015 talk here: - https://community.arm.com/cfs-file/__key/communityserver-blogs-components-weblogfiles/00-00-00-20-66/siggraph2015_2D00_mmg_2D00_marius_2D00_notes.pdf - Dual filtering is a fast large-radius blur that approximates a Gaussian blur. It is closely - related to the popular blur filter by Kawase, but runs faster at equal quality. - - How it works: Any number of downsampling passes are chained with the same number of upsampling - passes in an hourglass configuration. Both types of resampling passes exploit bilinear - interpolation with carefully chosen coordinates and weights to produce a smooth output. - There are just 5 + 8 = 13 texture samples per combined down- and upsampling pass. - The effective blur radius increases with the number of passes. - - This implementation adds a configurable blur strength which can diminish or accentuate the - effect compared to the reference implementation, equivalent to strength 1.0. - A blur strength above 3.0 may lead to artifacts, especially on presets with fewer passes. - - Changelog: - v1.0: Initial release. -*/ - -// clang-format off -#pragma parameter DUAL_FILTER_SETTINGS "=== Dual filter v1.0 settings ===" 0.0 0.0 1.0 1.0 -#pragma parameter BLUR_STRENGTH "Blur strength" 1.0 0.6 7.5 0.1 -// clang-format on diff --git a/blurs/shaders/dual_filter_upsample.slang b/blurs/shaders/dual_filter_upsample.slang deleted file mode 100644 index 5ce2f92..0000000 --- a/blurs/shaders/dual_filter_upsample.slang +++ /dev/null @@ -1,47 +0,0 @@ -#version 450 - -// See dual_filter_parameters.slang for copyright and other information. - -#include "dual_filter_parameters.slang" - -layout(push_constant) uniform Push { - vec4 SourceSize; - vec4 OriginalSize; - vec4 OutputSize; - uint FrameCount; - float BLUR_STRENGTH; -} -param; - -layout(std140, set = 0, binding = 0) uniform UBO { - mat4 MVP; -} -global; - -#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; -} - -#pragma stage fragment -layout(location = 0) in vec2 vTexCoord; -layout(location = 0) out vec4 FragColor; -layout(set = 0, binding = 2) uniform sampler2D Source; - -void main() { - const vec2 halfpixel = 0.5 * param.SourceSize.zw * param.BLUR_STRENGTH; - vec3 sum = texture(Source, vTexCoord + vec2(-halfpixel.x * 2.0, 0.0)).rgb; - sum += texture(Source, vTexCoord + vec2(-halfpixel.x, halfpixel.y)).rgb * 2.0; - sum += texture(Source, vTexCoord + vec2(0.0, halfpixel.y * 2.0)).rgb; - sum += texture(Source, vTexCoord + vec2(halfpixel.x, halfpixel.y)).rgb * 2.0; - sum += texture(Source, vTexCoord + vec2(halfpixel.x * 2.0, 0.0)).rgb; - sum += texture(Source, vTexCoord + vec2(halfpixel.x, -halfpixel.y)).rgb * 2.0; - sum += texture(Source, vTexCoord + vec2(0.0, -halfpixel.y * 2.0)).rgb; - sum += texture(Source, vTexCoord + vec2(-halfpixel.x, -halfpixel.y)).rgb * 2.0; - FragColor = vec4(sum / 12.0, 1.0); -} diff --git a/crt/crt-1tap-bloom.slangp b/crt/crt-1tap-bloom.slangp new file mode 100644 index 0000000..2a5f35a --- /dev/null +++ b/crt/crt-1tap-bloom.slangp @@ -0,0 +1,292 @@ +shaders = "26" +feedback_pass = "0" +shader0 = "shaders/crt-1tap.slang" +filter_linear0 = "true" +wrap_mode0 = "clamp_to_border" +mipmap_input0 = "false" +alias0 = "" +float_framebuffer0 = "true" +srgb_framebuffer0 = "false" +scale_type_x0 = "viewport" +scale_x0 = "1.000000" +scale_type_y0 = "viewport" +scale_y0 = "1.000000" +shader1 = "../blurs/shaders/kawase/linearize.slang" +wrap_mode1 = "clamp_to_border" +mipmap_input1 = "false" +alias1 = "Input" +float_framebuffer1 = "true" +srgb_framebuffer1 = "false" +scale_type_x1 = "source" +scale_x1 = "1.000000" +scale_type_y1 = "source" +scale_y1 = "1.000000" +shader2 = "../blurs/shaders/dual_filter/downsample_bloom.slang" +filter_linear2 = "true" +wrap_mode2 = "mirrored_repeat" +mipmap_input2 = "false" +alias2 = "" +float_framebuffer2 = "true" +srgb_framebuffer2 = "false" +scale_type_x2 = "viewport" +scale_x2 = "0.700000" +scale_type_y2 = "viewport" +scale_y2 = "0.700000" +shader3 = "../blurs/shaders/dual_filter/upsample.slang" +filter_linear3 = "true" +wrap_mode3 = "mirrored_repeat" +mipmap_input3 = "false" +alias3 = "" +float_framebuffer3 = "true" +srgb_framebuffer3 = "false" +scale_type_x3 = "source" +scale_x3 = "1.000000" +scale_type_y3 = "source" +scale_y3 = "1.000000" +shader4 = "../blurs/shaders/dual_filter/downsample.slang" +filter_linear4 = "true" +wrap_mode4 = "mirrored_repeat" +mipmap_input4 = "false" +alias4 = "" +float_framebuffer4 = "true" +srgb_framebuffer4 = "false" +scale_type_x4 = "source" +scale_x4 = "0.500000" +scale_type_y4 = "source" +scale_y4 = "0.500000" +shader5 = "../blurs/shaders/dual_filter/upsample.slang" +filter_linear5 = "true" +wrap_mode5 = "mirrored_repeat" +mipmap_input5 = "false" +alias5 = "Scale1" +float_framebuffer5 = "true" +srgb_framebuffer5 = "false" +scale_type_x5 = "source" +scale_x5 = "2.000000" +scale_type_y5 = "source" +scale_y5 = "2.000000" +shader6 = "../blurs/shaders/dual_filter/downsample.slang" +filter_linear6 = "true" +wrap_mode6 = "mirrored_repeat" +mipmap_input6 = "false" +alias6 = "" +float_framebuffer6 = "true" +srgb_framebuffer6 = "false" +scale_type_x6 = "source" +scale_x6 = "0.500000" +scale_type_y6 = "source" +scale_y6 = "0.500000" +shader7 = "../blurs/shaders/dual_filter/downsample.slang" +filter_linear7 = "true" +wrap_mode7 = "mirrored_repeat" +mipmap_input7 = "false" +alias7 = "" +float_framebuffer7 = "true" +srgb_framebuffer7 = "false" +scale_type_x7 = "source" +scale_x7 = "0.500000" +scale_type_y7 = "source" +scale_y7 = "0.500000" +shader8 = "../blurs/shaders/dual_filter/upsample.slang" +filter_linear8 = "true" +wrap_mode8 = "mirrored_repeat" +mipmap_input8 = "false" +alias8 = "Scale2" +float_framebuffer8 = "true" +srgb_framebuffer8 = "false" +scale_type_x8 = "source" +scale_x8 = "2.000000" +scale_type_y8 = "source" +scale_y8 = "2.000000" +shader9 = "../blurs/shaders/dual_filter/downsample.slang" +filter_linear9 = "true" +wrap_mode9 = "mirrored_repeat" +mipmap_input9 = "false" +alias9 = "" +float_framebuffer9 = "true" +srgb_framebuffer9 = "false" +scale_type_x9 = "source" +scale_x9 = "0.500000" +scale_type_y9 = "source" +scale_y9 = "0.500000" +shader10 = "../blurs/shaders/dual_filter/downsample.slang" +filter_linear10 = "true" +wrap_mode10 = "mirrored_repeat" +mipmap_input10 = "false" +alias10 = "" +float_framebuffer10 = "true" +srgb_framebuffer10 = "false" +scale_type_x10 = "source" +scale_x10 = "0.500000" +scale_type_y10 = "source" +scale_y10 = "0.500000" +shader11 = "../blurs/shaders/dual_filter/upsample.slang" +filter_linear11 = "true" +wrap_mode11 = "mirrored_repeat" +mipmap_input11 = "false" +alias11 = "Scale3" +float_framebuffer11 = "true" +srgb_framebuffer11 = "false" +scale_type_x11 = "source" +scale_x11 = "2.000000" +scale_type_y11 = "source" +scale_y11 = "2.000000" +shader12 = "../blurs/shaders/dual_filter/downsample.slang" +filter_linear12 = "true" +wrap_mode12 = "mirrored_repeat" +mipmap_input12 = "false" +alias12 = "" +float_framebuffer12 = "true" +srgb_framebuffer12 = "false" +scale_type_x12 = "source" +scale_x12 = "0.500000" +scale_type_y12 = "source" +scale_y12 = "0.500000" +shader13 = "../blurs/shaders/dual_filter/downsample.slang" +filter_linear13 = "true" +wrap_mode13 = "mirrored_repeat" +mipmap_input13 = "false" +alias13 = "" +float_framebuffer13 = "true" +srgb_framebuffer13 = "false" +scale_type_x13 = "source" +scale_x13 = "0.500000" +scale_type_y13 = "source" +scale_y13 = "0.500000" +shader14 = "../blurs/shaders/dual_filter/upsample.slang" +filter_linear14 = "true" +wrap_mode14 = "mirrored_repeat" +mipmap_input14 = "false" +alias14 = "Scale4" +float_framebuffer14 = "true" +srgb_framebuffer14 = "false" +scale_type_x14 = "source" +scale_x14 = "2.000000" +scale_type_y14 = "source" +scale_y14 = "2.000000" +shader15 = "../blurs/shaders/dual_filter/downsample.slang" +filter_linear15 = "true" +wrap_mode15 = "mirrored_repeat" +mipmap_input15 = "false" +alias15 = "" +float_framebuffer15 = "true" +srgb_framebuffer15 = "false" +scale_type_x15 = "source" +scale_x15 = "0.500000" +scale_type_y15 = "source" +scale_y15 = "0.500000" +shader16 = "../blurs/shaders/dual_filter/downsample.slang" +filter_linear16 = "true" +wrap_mode16 = "mirrored_repeat" +mipmap_input16 = "false" +alias16 = "" +float_framebuffer16 = "true" +srgb_framebuffer16 = "false" +scale_type_x16 = "source" +scale_x16 = "0.500000" +scale_type_y16 = "source" +scale_y16 = "0.500000" +shader17 = "../blurs/shaders/dual_filter/upsample.slang" +filter_linear17 = "true" +wrap_mode17 = "mirrored_repeat" +mipmap_input17 = "false" +alias17 = "Scale5" +float_framebuffer17 = "true" +srgb_framebuffer17 = "false" +scale_type_x17 = "source" +scale_x17 = "2.000000" +scale_type_y17 = "source" +scale_y17 = "2.000000" +shader18 = "../blurs/shaders/dual_filter/downsample.slang" +filter_linear18 = "true" +wrap_mode18 = "mirrored_repeat" +mipmap_input18 = "false" +alias18 = "" +float_framebuffer18 = "true" +srgb_framebuffer18 = "false" +scale_type_x18 = "source" +scale_x18 = "0.500000" +scale_type_y18 = "source" +scale_y18 = "0.500000" +shader19 = "../blurs/shaders/dual_filter/downsample.slang" +filter_linear19 = "true" +wrap_mode19 = "mirrored_repeat" +mipmap_input19 = "false" +alias19 = "" +float_framebuffer19 = "true" +srgb_framebuffer19 = "false" +scale_type_x19 = "source" +scale_x19 = "0.500000" +scale_type_y19 = "source" +scale_y19 = "0.500000" +shader20 = "../blurs/shaders/dual_filter/upsample.slang" +filter_linear20 = "true" +wrap_mode20 = "mirrored_repeat" +mipmap_input20 = "false" +alias20 = "Scale6" +float_framebuffer20 = "true" +srgb_framebuffer20 = "false" +scale_type_x20 = "source" +scale_x20 = "2.000000" +scale_type_y20 = "source" +scale_y20 = "2.000000" +shader21 = "../blurs/shaders/dual_filter/naive_resample.slang" +filter_linear21 = "true" +wrap_mode21 = "mirrored_repeat" +mipmap_input21 = "false" +alias21 = "" +float_framebuffer21 = "true" +srgb_framebuffer21 = "false" +scale_type_x21 = "absolute" +scale_x21 = "128" +scale_type_y21 = "absolute" +scale_y21 = "128" +shader22 = "../blurs/shaders/dual_filter/moving_avg.slang" +filter_linear22 = "true" +wrap_mode22 = "clamp_to_border" +mipmap_input22 = "true" +alias22 = "MovingAverage" +float_framebuffer22 = "true" +srgb_framebuffer22 = "false" +scale_type_x22 = "absolute" +scale_x22 = "2" +scale_type_y22 = "absolute" +scale_y22 = "2" +shader23 = "../blurs/shaders/dual_filter/bloom_blend.slang" +filter_linear23 = "true" +wrap_mode23 = "clamp_to_border" +mipmap_input23 = "false" +alias23 = "" +float_framebuffer23 = "true" +srgb_framebuffer23 = "false" +scale_type_x23 = "viewport" +scale_x23 = "1.000000" +scale_type_y23 = "viewport" +scale_y23 = "1.000000" +shader24 = "../blurs/shaders/kawase/delinearize.slang" +filter_linear24 = "true" +wrap_mode24 = "clamp_to_border" +mipmap_input24 = "false" +alias24 = "" +float_framebuffer24 = "true" +srgb_framebuffer24 = "false" +scale_type_x24 = "viewport" +scale_x24 = "1.000000" +scale_type_y24 = "viewport" +scale_y24 = "1.000000" +shader25 = "../sharpen/shaders/rcas.slang" +filter_linear25 = "false" +wrap_mode25 = "clamp_to_border" +mipmap_input25 = "false" +alias25 = "" +float_framebuffer25 = "false" +srgb_framebuffer25 = "false" +scale_type_x25 = "source" +scale_x25 = "1.000000" +scale_type_y25 = "source" +scale_y25 = "1.000000" +BLUR_RADIUS = "2.000000" +MIN_EXP_INTENSITY = "0.500000" +BLOOM_THRESHOLD = "2.500000" +EYE_ADAPTION = "0.850000" +RCAS_STRENGTH = "1.000000" diff --git a/crt/crt-1tap-bloom_fast.slangp b/crt/crt-1tap-bloom_fast.slangp new file mode 100644 index 0000000..7d977ec --- /dev/null +++ b/crt/crt-1tap-bloom_fast.slangp @@ -0,0 +1,224 @@ +shaders = "20" +feedback_pass = "0" +shader0 = "shaders/crt-1tap.slang" +filter_linear0 = "true" +wrap_mode0 = "clamp_to_border" +mipmap_input0 = "false" +alias0 = "" +float_framebuffer0 = "true" +srgb_framebuffer0 = "false" +scale_type_x0 = "viewport" +scale_x0 = "1.000000" +scale_type_y0 = "viewport" +scale_y0 = "1.000000" +shader1 = "../blurs/shaders/kawase/linearize.slang" +wrap_mode1 = "clamp_to_border" +mipmap_input1 = "false" +alias1 = "Input" +float_framebuffer1 = "true" +srgb_framebuffer1 = "false" +scale_type_x1 = "source" +scale_x1 = "1.000000" +scale_type_y1 = "source" +scale_y1 = "1.000000" +shader2 = "../blurs/shaders/dual_filter/downsample_bloom.slang" +filter_linear2 = "true" +wrap_mode2 = "mirrored_repeat" +mipmap_input2 = "false" +alias2 = "" +float_framebuffer2 = "true" +srgb_framebuffer2 = "false" +scale_type_x2 = "viewport" +scale_x2 = "0.400000" +scale_type_y2 = "viewport" +scale_y2 = "0.400000" +shader3 = "../blurs/shaders/dual_filter/upsample.slang" +filter_linear3 = "true" +wrap_mode3 = "mirrored_repeat" +mipmap_input3 = "false" +alias3 = "" +float_framebuffer3 = "true" +srgb_framebuffer3 = "false" +scale_type_x3 = "source" +scale_x3 = "1.000000" +scale_type_y3 = "source" +scale_y3 = "1.000000" +shader4 = "../blurs/shaders/dual_filter/downsample.slang" +filter_linear4 = "true" +wrap_mode4 = "mirrored_repeat" +mipmap_input4 = "false" +alias4 = "" +float_framebuffer4 = "true" +srgb_framebuffer4 = "false" +scale_type_x4 = "source" +scale_x4 = "0.500000" +scale_type_y4 = "source" +scale_y4 = "0.500000" +shader5 = "../blurs/shaders/dual_filter/upsample.slang" +filter_linear5 = "true" +wrap_mode5 = "mirrored_repeat" +mipmap_input5 = "false" +alias5 = "Scale1" +float_framebuffer5 = "true" +srgb_framebuffer5 = "false" +scale_type_x5 = "source" +scale_x5 = "2.000000" +scale_type_y5 = "source" +scale_y5 = "2.000000" +shader6 = "../blurs/shaders/dual_filter/downsample.slang" +filter_linear6 = "true" +wrap_mode6 = "mirrored_repeat" +mipmap_input6 = "false" +alias6 = "" +float_framebuffer6 = "true" +srgb_framebuffer6 = "false" +scale_type_x6 = "source" +scale_x6 = "0.500000" +scale_type_y6 = "source" +scale_y6 = "0.500000" +shader7 = "../blurs/shaders/dual_filter/downsample.slang" +filter_linear7 = "true" +wrap_mode7 = "mirrored_repeat" +mipmap_input7 = "false" +alias7 = "" +float_framebuffer7 = "true" +srgb_framebuffer7 = "false" +scale_type_x7 = "source" +scale_x7 = "0.500000" +scale_type_y7 = "source" +scale_y7 = "0.500000" +shader8 = "../blurs/shaders/dual_filter/upsample.slang" +filter_linear8 = "true" +wrap_mode8 = "mirrored_repeat" +mipmap_input8 = "false" +alias8 = "Scale2" +float_framebuffer8 = "true" +srgb_framebuffer8 = "false" +scale_type_x8 = "source" +scale_x8 = "2.000000" +scale_type_y8 = "source" +scale_y8 = "2.000000" +shader9 = "../blurs/shaders/dual_filter/downsample.slang" +filter_linear9 = "true" +wrap_mode9 = "mirrored_repeat" +mipmap_input9 = "false" +alias9 = "" +float_framebuffer9 = "true" +srgb_framebuffer9 = "false" +scale_type_x9 = "source" +scale_x9 = "0.500000" +scale_type_y9 = "source" +scale_y9 = "0.500000" +shader10 = "../blurs/shaders/dual_filter/downsample.slang" +filter_linear10 = "true" +wrap_mode10 = "mirrored_repeat" +mipmap_input10 = "false" +alias10 = "" +float_framebuffer10 = "true" +srgb_framebuffer10 = "false" +scale_type_x10 = "source" +scale_x10 = "0.500000" +scale_type_y10 = "source" +scale_y10 = "0.500000" +shader11 = "../blurs/shaders/dual_filter/upsample.slang" +filter_linear11 = "true" +wrap_mode11 = "mirrored_repeat" +mipmap_input11 = "false" +alias11 = "Scale3" +float_framebuffer11 = "true" +srgb_framebuffer11 = "false" +scale_type_x11 = "source" +scale_x11 = "2.000000" +scale_type_y11 = "source" +scale_y11 = "2.000000" +shader12 = "../blurs/shaders/dual_filter/downsample.slang" +filter_linear12 = "true" +wrap_mode12 = "mirrored_repeat" +mipmap_input12 = "false" +alias12 = "" +float_framebuffer12 = "true" +srgb_framebuffer12 = "false" +scale_type_x12 = "source" +scale_x12 = "0.500000" +scale_type_y12 = "source" +scale_y12 = "0.500000" +shader13 = "../blurs/shaders/dual_filter/downsample.slang" +filter_linear13 = "true" +wrap_mode13 = "mirrored_repeat" +mipmap_input13 = "false" +alias13 = "" +float_framebuffer13 = "true" +srgb_framebuffer13 = "false" +scale_type_x13 = "source" +scale_x13 = "0.500000" +scale_type_y13 = "source" +scale_y13 = "0.500000" +shader14 = "../blurs/shaders/dual_filter/upsample.slang" +filter_linear14 = "true" +wrap_mode14 = "mirrored_repeat" +mipmap_input14 = "false" +alias14 = "Scale4" +float_framebuffer14 = "true" +srgb_framebuffer14 = "false" +scale_type_x14 = "source" +scale_x14 = "2.000000" +scale_type_y14 = "source" +scale_y14 = "2.000000" +shader15 = "../blurs/shaders/dual_filter/naive_resample.slang" +filter_linear15 = "true" +wrap_mode15 = "mirrored_repeat" +mipmap_input15 = "false" +alias15 = "" +float_framebuffer15 = "true" +srgb_framebuffer15 = "false" +scale_type_x15 = "absolute" +scale_x15 = "64" +scale_type_y15 = "absolute" +scale_y15 = "64" +shader16 = "../blurs/shaders/dual_filter/moving_avg.slang" +filter_linear16 = "true" +wrap_mode16 = "clamp_to_border" +mipmap_input16 = "true" +alias16 = "MovingAverage" +float_framebuffer16 = "true" +srgb_framebuffer16 = "false" +scale_type_x16 = "absolute" +scale_x16 = "2" +scale_type_y16 = "absolute" +scale_y16 = "2" +shader17 = "../blurs/shaders/dual_filter/bloom_blend_fast.slang" +filter_linear17 = "true" +wrap_mode17 = "clamp_to_border" +mipmap_input17 = "false" +alias17 = "" +float_framebuffer17 = "true" +srgb_framebuffer17 = "false" +scale_type_x17 = "viewport" +scale_x17 = "1.000000" +scale_type_y17 = "viewport" +scale_y17 = "1.000000" +shader18 = "../blurs/shaders/kawase/delinearize.slang" +filter_linear18 = "true" +wrap_mode18 = "clamp_to_border" +mipmap_input18 = "false" +alias18 = "" +float_framebuffer18 = "true" +srgb_framebuffer18 = "false" +scale_type_x18 = "viewport" +scale_x18 = "1.000000" +scale_type_y18 = "viewport" +scale_y18 = "1.000000" +shader19 = "../sharpen/shaders/rcas.slang" +filter_linear19 = "false" +wrap_mode19 = "clamp_to_border" +mipmap_input19 = "false" +alias19 = "" +float_framebuffer19 = "false" +srgb_framebuffer19 = "false" +scale_type_x19 = "source" +scale_x19 = "1.000000" +scale_type_y19 = "source" +scale_y19 = "1.000000" +MIN_EXP_INTENSITY = "0.650000" +BLOOM_THRESHOLD = "2.500001" +RCAS_STRENGTH = "1.000000" diff --git a/crt/crt-1tap-bloom_fastest.slangp b/crt/crt-1tap-bloom_fastest.slangp new file mode 100644 index 0000000..dc353de --- /dev/null +++ b/crt/crt-1tap-bloom_fastest.slangp @@ -0,0 +1,115 @@ +shaders = "10" +feedback_pass = "0" +shader0 = "shaders/crt-1tap.slang" +filter_linear0 = "true" +wrap_mode0 = "clamp_to_border" +mipmap_input0 = "false" +alias0 = "" +float_framebuffer0 = "true" +srgb_framebuffer0 = "false" +scale_type_x0 = "viewport" +scale_x0 = "1.000000" +scale_type_y0 = "viewport" +scale_y0 = "1.000000" +shader1 = "../blurs/shaders/kawase/linearize.slang" +wrap_mode1 = "clamp_to_border" +mipmap_input1 = "false" +alias1 = "Input" +float_framebuffer1 = "true" +srgb_framebuffer1 = "false" +scale_type_x1 = "source" +scale_x1 = "1.000000" +scale_type_y1 = "source" +scale_y1 = "1.000000" +shader2 = "../blurs/shaders/dual_filter/downsample_bloom.slang" +filter_linear2 = "false" +wrap_mode2 = "mirrored_repeat" +mipmap_input2 = "false" +alias2 = "Downsample1" +float_framebuffer2 = "true" +srgb_framebuffer2 = "false" +scale_type_x2 = "source" +scale_x2 = "0.500000" +scale_type_y2 = "source" +scale_y2 = "0.500000" +shader3 = "../blurs/shaders/dual_filter/downsample.slang" +filter_linear3 = "true" +wrap_mode3 = "mirrored_repeat" +mipmap_input3 = "false" +alias3 = "Downsample2" +float_framebuffer3 = "true" +srgb_framebuffer3 = "false" +scale_type_x3 = "source" +scale_x3 = "0.500000" +scale_type_y3 = "source" +scale_y3 = "0.500000" +shader4 = "../blurs/shaders/dual_filter/upsample.slang" +filter_linear4 = "true" +wrap_mode4 = "mirrored_repeat" +mipmap_input4 = "false" +alias4 = "Upsample" +float_framebuffer4 = "true" +srgb_framebuffer4 = "false" +scale_type_x4 = "source" +scale_x4 = "2.000000" +scale_type_y4 = "source" +scale_y4 = "2.000000" +shader5 = "../blurs/shaders/dual_filter/naive_resample.slang" +filter_linear5 = "true" +wrap_mode5 = "clamp_to_border" +mipmap_input5 = "false" +alias5 = "" +float_framebuffer5 = "true" +srgb_framebuffer5 = "false" +scale_type_x5 = "absolute" +scale_x5 = "64" +scale_type_y5 = "absolute" +scale_y5 = "64" +shader6 = "../blurs/shaders/dual_filter/moving_avg.slang" +filter_linear6 = "true" +wrap_mode6 = "mirrored_repeat" +mipmap_input6 = "true" +alias6 = "MovingAverage" +float_framebuffer6 = "true" +srgb_framebuffer6 = "false" +scale_type_x6 = "absolute" +scale_x6 = "2" +scale_type_y6 = "absolute" +scale_y6 = "2" +shader7 = "../blurs/shaders/dual_filter/bloom_blend_fastest.slang" +filter_linear7 = "true" +wrap_mode7 = "mirrored_repeat" +mipmap_input7 = "false" +alias7 = "" +float_framebuffer7 = "true" +srgb_framebuffer7 = "false" +scale_type_x7 = "viewport" +scale_x7 = "1.000000" +scale_type_y7 = "viewport" +scale_y7 = "1.000000" +shader8 = "../blurs/shaders/kawase/delinearize.slang" +filter_linear8 = "false" +wrap_mode8 = "clamp_to_border" +mipmap_input8 = "false" +alias8 = "" +float_framebuffer8 = "true" +srgb_framebuffer8 = "false" +scale_type_x8 = "viewport" +scale_x8 = "1.000000" +scale_type_y8 = "viewport" +scale_y8 = "1.000000" +shader9 = "../sharpen/shaders/rcas.slang" +filter_linear9 = "false" +wrap_mode9 = "clamp_to_border" +mipmap_input9 = "false" +alias9 = "" +float_framebuffer9 = "false" +srgb_framebuffer9 = "false" +scale_type_x9 = "source" +scale_x9 = "1.000000" +scale_type_y9 = "source" +scale_y9 = "1.000000" +BLUR_RADIUS = "2.000000" +MIN_EXP_INTENSITY = "0.450000" +BLOOM_THRESHOLD = "3.000000" +RCAS_STRENGTH = "1.000000" diff --git a/crt/shaders/crt-1tap.slang b/crt/shaders/crt-1tap.slang index 8826308..7445a87 100644 --- a/crt/shaders/crt-1tap.slang +++ b/crt/shaders/crt-1tap.slang @@ -1,7 +1,7 @@ #version 450 /* - crt-1tap v1.1 by fishku + crt-1tap v1.2 by fishku Copyright (C) 2023 Public domain license (CC0) @@ -21,18 +21,19 @@ for even and odd integer scaling. Changelog: + v1.2: Better scanline sharpness; Minor cleanups. v1.1: Update license; Better defaults; Don't compute alpha. v1.0: Initial release. */ // clang-format off -#pragma parameter CRT1TAP_SETTINGS "=== CRT-1tap settings ===" 0.0 0.0 1.0 1.0 -#pragma parameter MIN_THICK "MIN_THICK: Scanline thickness of dark pixels." 0.3 0.0 1.4 0.05 -#pragma parameter MAX_THICK "MAX_THICK: Scanline thickness of bright pixels." 1.05 0.0 1.4 0.05 -#pragma parameter V_SHARP "V_SHARP: Vertical sharpness of the scanline" 0.2 0.0 1.0 0.05 -#pragma parameter H_SHARP "H_SHARP: Horizontal sharpness of pixel transitions." 0.15 0.0 1.0 0.05 -#pragma parameter SUBPX_POS "SUBPX_POS: Scanline subpixel position." 0.15 -0.5 0.5 0.01 -#pragma parameter THICK_FALLOFF "THICK_FALLOFF: Reduction of thinner scanlines." 0.65 0.2 2.0 0.05 +#pragma parameter CRT1TAP_SETTINGS "=== CRT-1tap v1.2 settings ===" 0.0 0.0 1.0 1.0 +#pragma parameter MIN_THICK "Scanline thickness of dark pixels" 0.3 0.0 1.4 0.05 +#pragma parameter MAX_THICK "Scanline thickness of bright pixels" 0.9 0.0 1.4 0.05 +#pragma parameter V_SHARP "Vertical sharpness of the scanline" 0.5 0.0 1.0 0.05 +#pragma parameter H_SHARP "Horizontal sharpness of pixel transitions" 0.15 0.0 1.0 0.05 +#pragma parameter SUBPX_POS "Scanline subpixel position" 0.3 -0.5 0.5 0.01 +#pragma parameter THICK_FALLOFF "Reduction / increase of thinner scanlines" 0.65 0.2 2.0 0.05 // clang-format on layout(push_constant) uniform Push { @@ -47,7 +48,9 @@ layout(push_constant) uniform Push { } param; -layout(std140, set = 0, binding = 0) uniform UBO { mat4 MVP; } +layout(std140, set = 0, binding = 0) uniform UBO { + mat4 MVP; +} global; #pragma stage vertex @@ -68,34 +71,27 @@ layout(set = 0, binding = 2) uniform sampler2D Original; void main() { float src_x_int; - const float src_x_fract = - modf(vTexCoord.x * param.SourceSize.x - 0.5f, src_x_int); + const float src_x_fract = modf(vTexCoord.x * param.SourceSize.x - 0.5, src_x_int); float src_y_int; const float src_y_fract = - modf(vTexCoord.y * param.SourceSize.y - param.SUBPX_POS, src_y_int); + modf(vTexCoord.y * param.SourceSize.y - param.SUBPX_POS, src_y_int) - 0.5; // Function similar to smoothstep and sigmoid. - const float s = sign(src_x_fract - 0.5f); - const float o = (1.0f + s) * 0.5f; + const float s = sign(src_x_fract - 0.5); + const float o = (1.0 + s) * 0.5; const float src_x = - src_x_int + o - - 0.5f * s * - pow(2.0f * (o - s * src_x_fract), mix(1.0f, 6.0f, param.H_SHARP)); + src_x_int + o - 0.5 * s * pow(2.0 * (o - s * src_x_fract), mix(1.0, 6.0, param.H_SHARP)); - const vec3 signal = - texture(Source, vec2((src_x + 0.5f) * param.SourceSize.z, - (src_y_int + 0.5f) * param.SourceSize.w)) - .rgb; + const vec3 signal = texture(Source, vec2((src_x + 0.5) * param.SourceSize.z, + (src_y_int + 0.5) * param.SourceSize.w)) + .rgb; // Vectorize operations for speed. - const float eff_v_sharp = 3.0f + 50.0f * param.V_SHARP * param.V_SHARP; + const float eff_v_sharp = 3.0 + 50.0 * param.V_SHARP * param.V_SHARP; + const vec3 radius = + pow(mix(param.MIN_THICK.xxx, param.MAX_THICK.xxx, signal), param.THICK_FALLOFF.xxx) * 0.5; FragColor.rgb = - signal * - clamp(eff_v_sharp * - ((pow(mix(param.MIN_THICK.xxx, param.MAX_THICK.xxx, signal), - param.THICK_FALLOFF.xxx) * - 0.5f) - - abs(src_y_fract - 0.5f)), - 0.0f, 1.0f); + signal * clamp(0.25 - eff_v_sharp * (src_y_fract * src_y_fract - radius * radius), + 0.0, 1.0); }