diff --git a/data/effects/blur.effect b/data/effects/blur.effect index a8cf157..7b7e7d3 100644 --- a/data/effects/blur.effect +++ b/data/effects/blur.effect @@ -78,7 +78,7 @@ technique Box /// Blur: Box (Linear Optimized) // By abusing Linear sampling we can reduce the necessary samples, halving the total samples. -float4 PSBoxBlurLinear(VertDataOut vtx) : TARGET { +float4 PSBoxBlurLinear(VertDataOut vtx) : TARGET { // Radius 4 (Even): // [-4, -3, -2, -1, 0, +1, +2, +3, +4] // ^-S-^ ^-S-^ S ^-S-^ ^-S-^ @@ -155,6 +155,66 @@ technique Gaussian } } +/// Blur: Gaussian Linear +float4 PSGaussianLinearBlur(VertDataOut vtx) : TARGET { + // Origin sample must always be sampled. + // Even, Odd must decide differently than Box Blur + + // Radius 5 (Odd): + // [-5, -4, -3, -2, -1, 0, +1, +2, +3, +4, +5] + // S ^-S-^ ^-S-^ S ^-S-^ ^-S-^ S + // S ^-S-^ ^-S-^ S ^-S-^ ^-S-^ S + // Total Samples: 7 (n+2) + + // Radius 4 (Even): + // [-4, -3, -2, -1, 0, +1, +2, +3, +4] + // ^-S-^ ^-S-^ S ^-S-^ ^-S-^ + // Total Samples: 5 (n+1) + + // Radius 3 (Odd): + // [-3, -2, -1, 0, +1, +2, +3] + // S ^-S-^ S ^-S-^ S + // Total Samples: 5 (n+2) + + // Radius 2 (Even): + // [-2, -1, 0, +1, +2] + // ^-S-^ S ^-S-^ + // Total Samples: 3 (n+1) + + float4 origin = u_image.SampleLevel(pointSampler, vtx.uv, 0); + float4 final = origin * kernel.SampleLevel(pointSampler, (float2(0, u_radius - 1) * kernelTexel), 0).r; + float2 halfTexelDelta = u_texelDelta / 2.0; + + for (int k = 1; k < u_radius; k+=2) { + float2 offset = k * u_texelDelta + halfTexelDelta; + float l_g0 = kernel.SampleLevel(pointSampler, (float2(k, u_radius - 1) * kernelTexel), 0).r; + float l_g1 = kernel.SampleLevel(pointSampler, (float2(k + 1, u_radius - 1) * kernelTexel), 0).r; + float4 l_p = u_image.SampleLevel(linearSampler, vtx.uv + offset, 0); + float4 l_n = u_image.SampleLevel(linearSampler, vtx.uv - offset, 0); + final += (l_p + l_n) * l_g0; + final += (l_p + l_n) * l_g1; + } + + if (u_radius % 2 == 1) { + // Odd numbers require treatment of ends. + float4 left = u_image.SampleLevel(pointSampler, vtx.uv + u_texelDelta * u_radius, 0); + float4 right = u_image.SampleLevel(pointSampler, vtx.uv - u_texelDelta * u_radius, 0); + float krn = kernel.SampleLevel(pointSampler, (float2(u_radius, u_radius - 1) * kernelTexel), 0).r; + final += (left + right) * krn; + } + + return final; +} + +technique GaussianLinear +{ + pass + { + vertex_shader = VSDefault(vtx); + pixel_shader = PSGaussianLinearBlur(vtx); + } +} + /// Blur: Bilateral float Bilateral(float x, float sigma) { return 0.39894 * exp(-0.5 * (x*x) / (sigma*sigma)) / sigma; diff --git a/data/locale/en-US.ini b/data/locale/en-US.ini index b0672ad..02c9ef5 100644 --- a/data/locale/en-US.ini +++ b/data/locale/en-US.ini @@ -28,10 +28,11 @@ CustomShader.Texture.Type.Source="Source" # Filter - Blur Filter.Blur="Blur" Filter.Blur.Type="Type" -Filter.Blur.Type.Description="The type of blur to apply:\n- 'Box' smoothes pixels equally.\n- 'Box Linear' uses linear sampling to reduce the GPU usage, sacrificing minimal quality.\n- 'Gaussian' applies a gaussian curve to the smoothed pixels.\n- 'Bilateral' is an edge detection variant of 'Gaussian'." +Filter.Blur.Type.Description="The type of blur to apply:\n- 'Box' smoothes pixels equally.\n- 'Box Linear' uses linear sampling to reduce the GPU usage, sacrificing minimal quality.\n- 'Gaussian' applies a gaussian curve to the smoothed pixels.\n- 'Gaussian Linear' again uses linear sampling to reduce the total samples, sacrificing more quality this time.\n- 'Bilateral' is an edge detection variant of 'Gaussian'." Filter.Blur.Type.Box="Box" Filter.Blur.Type.BoxLinear="Box Linear" Filter.Blur.Type.Gaussian="Gaussian" +Filter.Blur.Type.GaussianLinear="Gaussian Linear" Filter.Blur.Type.Bilateral="Bilateral" Filter.Blur.Size="Size (Pixel)" Filter.Blur.Size.Description="Area size of the blur, large sizes may cause:\n- Skipped frames\n- Frame loss or drops\n- Input lag\n- GPU overheating\n- or other issues." diff --git a/source/filter-blur.cpp b/source/filter-blur.cpp index e9b4e96..70b6f8a 100644 --- a/source/filter-blur.cpp +++ b/source/filter-blur.cpp @@ -41,6 +41,7 @@ extern "C" { #define P_TYPE_BOX "Filter.Blur.Type.Box" #define P_TYPE_BOXLINEAR "Filter.Blur.Type.BoxLinear" #define P_TYPE_GAUSSIAN "Filter.Blur.Type.Gaussian" +#define P_TYPE_GAUSSIANLINEAR "Filter.Blur.Type.GaussianLinear" #define P_TYPE_BILATERAL "Filter.Blur.Type.Bilateral" #define P_SIZE "Filter.Blur.Size" #define P_BILATERAL_SMOOTHING "Filter.Blur.Bilateral.Smoothing" @@ -125,8 +126,6 @@ bool filter::blur::blur_instance::apply_gaussian_param() if (blur_effect->has_parameter("kernel")) { blur_effect->get_parameter("kernel").set_texture(kernel); - } else { - return false; } if (blur_effect->has_parameter("kernelTexel")) { @@ -300,6 +299,7 @@ obs_properties_t* filter::blur::blur_instance::get_properties() obs_property_list_add_int(p, P_TRANSLATE(P_TYPE_BOX), filter::blur::type::Box); obs_property_list_add_int(p, P_TRANSLATE(P_TYPE_BOXLINEAR), filter::blur::type::BoxLinear); obs_property_list_add_int(p, P_TRANSLATE(P_TYPE_GAUSSIAN), filter::blur::type::Gaussian); + obs_property_list_add_int(p, P_TRANSLATE(P_TYPE_GAUSSIANLINEAR), filter::blur::type::GaussianLinear); obs_property_list_add_int(p, P_TRANSLATE(P_TYPE_BILATERAL), filter::blur::type::Bilateral); p = obs_properties_add_int_slider(pr, P_SIZE, P_TRANSLATE(P_SIZE), 1, 25, 1); @@ -630,14 +630,8 @@ void filter::blur::blur_instance::video_render(gs_effect_t* effect) if (!apply_shared_param(intermediate, xpel, ypel)) break; - switch (type) { - case Gaussian: - apply_gaussian_param(); - break; - case Bilateral: - apply_bilateral_param(); - break; - } + apply_gaussian_param(); + apply_bilateral_param(); gs_texrender_reset(rt); if (!gs_texrender_begin(rt, baseW, baseH)) { @@ -1025,12 +1019,14 @@ std::string filter::blur::blur_factory::get_technique(filter::blur::type type) switch (type) { case type::Box: return "Box"; - case type::BoxLinear: - return "BoxLinear"; case type::Gaussian: return "Gaussian"; case type::Bilateral: return "Bilateral"; + case type::BoxLinear: + return "BoxLinear"; + case type::GaussianLinear: + return "GaussianLinear"; } return ""; } diff --git a/source/filter-blur.h b/source/filter-blur.h index 28a36da..0143582 100644 --- a/source/filter-blur.h +++ b/source/filter-blur.h @@ -42,9 +42,10 @@ namespace filter { namespace blur { enum type : int64_t { Box, - BoxLinear, Gaussian, Bilateral, + BoxLinear, + GaussianLinear, }; enum mask_type : int64_t {