Add bloom based on dual filter blur (#367)

* Update CRT-1tap to v1.2

* update default param

* Update default param

* Add bloom based on dual filter blur

Previously squashed commits:
WIP:Dual filtering bloom effect
Add scale level weighting; Comment out debug code; Simplify tonemap
Debug:Show bloom contrib
Tweak defaults; Small bugfixes
Organize shaders into subfolder
Refactor tonemap into separate file
Tweak parameters
Greatly simplify exposure to intensity mapping; Clean up
Fix faster preset
Change luma pass size to 1 pixel
Lots of polishing
Add combined presets
Add docs; Refactor params a bit; Cleanup
Update combined presets
Rename presets for better ordering
This commit is contained in:
fishcu 2023-02-12 00:19:43 +01:00 committed by GitHub
parent 356678ec53
commit a6e11453ad
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 1592 additions and 126 deletions

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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);
}
}
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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

View file

@ -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

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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

View file

@ -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);
}

292
crt/crt-1tap-bloom.slangp Normal file
View file

@ -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"

View file

@ -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"

View file

@ -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"

View file

@ -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);
}