From 3952c33c60fa7b8f317018d7ef6f591520922bd4 Mon Sep 17 00:00:00 2001 From: Michael Fabian 'Xaymar' Dirks Date: Sun, 23 Dec 2018 19:54:57 +0100 Subject: [PATCH] filter-blur: Add Directional Blur (Motion Blur) and Step Scaling Directional Blur (also known as Motion Blur in some art software) enables full control over the direction the passes are applied in, which can further be combined with the scaling option. With this very simple blur effects can have a massively bigger influence. Step Scaling allows for improved control over individual Blur passes and can be combined with Directional Blur to imitate certain effects. It also allows smaller Blur sizes to cover a larger area, although with a drastic loss in final quality. For example, if someone is streaming at 720p and wants to have their dynamic 2160p background blurry to a very high degree, this option would allow that at next to no quality loss in the final stream. The actual values that need to be used vary for each source and encoder however, so they will have to be chosen carefully. --- data/locale/en-US.ini | 10 +++- source/filter-blur.cpp | 122 +++++++++++++++++++++++++++++++++++------ source/filter-blur.h | 8 +++ 3 files changed, 122 insertions(+), 18 deletions(-) diff --git a/data/locale/en-US.ini b/data/locale/en-US.ini index 02c9ef5a..fbd6dfa3 100644 --- a/data/locale/en-US.ini +++ b/data/locale/en-US.ini @@ -38,6 +38,14 @@ 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." Filter.Blur.Bilateral.Smoothing="Smoothing" Filter.Blur.Bilateral.Sharpness="Sharpness" +Filter.Blur.Directional="Directional Blur" +Filter.Blur.Directional.Description="Change the Blur into a Directional Blur. May not work with all Blur Types." +Filter.Blur.Directional.Angle="Angle" +Filter.Blur.Directional.Angle.Description="The angle in degrees for the Directional Blur." +Filter.Blur.StepScale="Step Scaling" +Filter.Blur.StepScale.Description="Scale the texel step used in the Blur shader, which allows for smaller Blur sizes to cover more space, at the cost of some quality.\nCan be combined with Directional Blur to change the behavior drastically." +Filter.Blur.StepScale.X="Step Scale X" +Filter.Blur.StepScale.Y="Step Scale Y" Filter.Blur.Region="Apply to Region only" Filter.Blur.Region.Description="Only apply the blur to a region inside the source." Filter.Blur.Region.Left="Left Edge" @@ -54,7 +62,6 @@ Filter.Blur.Region.Feather.Shift="Feather Shift" Filter.Blur.Region.Feather.Shift.Description="Shift of the Feather area, positive is inwards, negative is outwards." Filter.Blur.Region.Invert="Invert Region" Filter.Blur.Region.Invert.Description="Invert the region so that everything but this area is blurred." -Filter.Blur.ColorFormat="Color Format" Filter.Blur.Mask="Apply a Mask" Filter.Blur.Mask.Description="Apply a mask to the area that needs to be blurred, which allows for more control over the blurred area." Filter.Blur.Mask.Type="Mask Type" @@ -86,6 +93,7 @@ Filter.Blur.Mask.Alpha="Mask Alpha Filter" Filter.Blur.Mask.Alpha.Description="Filter the mask by this alpha value before applying it." Filter.Blur.Mask.Multiplier="Mask Multiplier" Filter.Blur.Mask.Multiplier.Description="Multiply the final mask value by this value." +Filter.Blur.ColorFormat="Color Format" # Filter - Custom Shader Filter.CustomShader="Custom Shader" diff --git a/source/filter-blur.cpp b/source/filter-blur.cpp index 5e0ef8b7..07422b63 100644 --- a/source/filter-blur.cpp +++ b/source/filter-blur.cpp @@ -18,9 +18,9 @@ */ #include "filter-blur.h" +#include #include #include -#include #include "strings.h" #include "util-math.h" @@ -46,7 +46,11 @@ extern "C" { #define P_SIZE "Filter.Blur.Size" #define P_BILATERAL_SMOOTHING "Filter.Blur.Bilateral.Smoothing" #define P_BILATERAL_SHARPNESS "Filter.Blur.Bilateral.Sharpness" -#define P_COLORFORMAT "Filter.Blur.ColorFormat" +#define P_DIRECTIONAL "Filter.Blur.Directional" +#define P_DIRECTIONAL_ANGLE "Filter.Blur.Directional.Angle" +#define P_STEPSCALE "Filter.Blur.StepScale" +#define P_STEPSCALE_X "Filter.Blur.StepScale.X" +#define P_STEPSCALE_Y "Filter.Blur.StepScale.Y" #define P_MASK "Filter.Blur.Mask" #define P_MASK_TYPE "Filter.Blur.Mask.Type" #define P_MASK_TYPE_REGION "Filter.Blur.Mask.Type.Region" @@ -64,6 +68,7 @@ extern "C" { #define P_MASK_COLOR "Filter.Blur.Mask.Color" #define P_MASK_ALPHA "Filter.Blur.Mask.Alpha" #define P_MASK_MULTIPLIER "Filter.Blur.Mask.Multiplier" +#define P_COLORFORMAT "Filter.Blur.ColorFormat" // Initializer & Finalizer INITIALIZER(filterBlurFactoryInitializer) @@ -199,14 +204,13 @@ bool filter::blur::blur_instance::apply_mask_parameters(std::shared_ptrdirectional = obs_data_get_bool(settings, P_DIRECTIONAL); + this->angle = obs_data_get_double(settings, P_DIRECTIONAL_ANGLE); + + // Scaling + this->scaling = obs_data_get_bool(settings, P_STEPSCALE); + this->scale.first = obs_data_get_double(settings, P_STEPSCALE_X) / 100.0; + this->scale.second = obs_data_get_double(settings, P_STEPSCALE_Y) / 100.0; + // advanced if (obs_data_get_bool(settings, S_ADVANCED)) { color_format = obs_data_get_int(settings, P_COLORFORMAT); @@ -624,10 +658,55 @@ void filter::blur::blur_instance::video_render(gs_effect_t* effect) std::pair kvs[] = {{1.0f / baseW, 0.0f}, {0.0f, 1.0f / baseH}}; tex_intermediate = tex_source; // We need the original to work. + // Directional Blur + if (this->directional) { + // Directional Blur changes how + + kvs[0].first = (1.0f / baseW); + kvs[0].second = (1.0f / baseH); + kvs[1].first = kvs[0].first; + kvs[1].second = kvs[0].second; + + double_t rad = this->angle * PI / 180.0; + double_t c0 = cos(rad); + double_t s0 = sin(rad); + + kvs[0].first *= c0; + kvs[0].second *= s0; + + if (!this->scaling) { + kvs[1].first *= 0.0; + kvs[1].second *= 0.0; + } else { + kvs[1].first *= s0; + kvs[1].second *= c0; + } + } + + // Apply scaling + if (this->scaling) { + if (!this->directional) { + kvs[0].first *= float_t(this->scale.first); + kvs[0].second *= float_t(this->scale.second); + kvs[1].first *= float_t(this->scale.first); + kvs[1].second *= float_t(this->scale.second); + } else { + // Directional Blur changes how scaling works as it rotates and needs to be relative to the axis of rotation. + kvs[0].first *= float_t(this->scale.first); + kvs[0].second *= float_t(this->scale.first); + kvs[1].first *= float_t(this->scale.second); + kvs[1].second *= float_t(this->scale.second); + } + } + try { for (auto v : kvs) { float xpel = std::get<0>(v); float ypel = std::get<1>(v); + if ((abs(xpel) <= FLT_EPSILON) && (abs(ypel) <= FLT_EPSILON)) { + // Ignore passes that have a 0 texel modifier. + continue; + } { auto op = this->rt_primary->render(baseW, baseH); @@ -944,19 +1023,19 @@ void filter::blur::blur_factory::get_defaults(obs_data_t* data) obs_data_set_default_int(data, P_TYPE, filter::blur::type::Box); obs_data_set_default_int(data, P_SIZE, 5); - // bilateral Only + // Bilateral Only obs_data_set_default_double(data, P_BILATERAL_SMOOTHING, 50.0); obs_data_set_default_double(data, P_BILATERAL_SHARPNESS, 90.0); - // region + // Masking obs_data_set_default_bool(data, P_MASK, false); obs_data_set_default_int(data, P_MASK_TYPE, mask_type::Region); - obs_data_set_default_double(data, P_MASK_REGION_LEFT, 0.0f); - obs_data_set_default_double(data, P_MASK_REGION_RIGHT, 0.0f); - obs_data_set_default_double(data, P_MASK_REGION_TOP, 0.0f); - obs_data_set_default_double(data, P_MASK_REGION_BOTTOM, 0.0f); - obs_data_set_default_double(data, P_MASK_REGION_FEATHER, 0.0f); - obs_data_set_default_double(data, P_MASK_REGION_FEATHER_SHIFT, 0.0f); + obs_data_set_default_double(data, P_MASK_REGION_LEFT, 0.0); + obs_data_set_default_double(data, P_MASK_REGION_RIGHT, 0.0); + obs_data_set_default_double(data, P_MASK_REGION_TOP, 0.0); + obs_data_set_default_double(data, P_MASK_REGION_BOTTOM, 0.0); + obs_data_set_default_double(data, P_MASK_REGION_FEATHER, 0.0); + obs_data_set_default_double(data, P_MASK_REGION_FEATHER_SHIFT, 0.0); obs_data_set_default_bool(data, P_MASK_REGION_INVERT, false); char* default_file = obs_module_file("white.png"); obs_data_set_default_string(data, P_MASK_IMAGE, default_file); @@ -965,7 +1044,16 @@ void filter::blur::blur_factory::get_defaults(obs_data_t* data) obs_data_set_default_int(data, P_MASK_COLOR, 0xFFFFFFFFull); obs_data_set_default_double(data, P_MASK_MULTIPLIER, 1.0); - // advanced + // Directional Blur + obs_data_set_default_bool(data, P_DIRECTIONAL, false); + obs_data_set_default_double(data, P_DIRECTIONAL_ANGLE, 0.0); + + // Scaling + obs_data_set_default_bool(data, P_STEPSCALE, false); + obs_data_set_default_double(data, P_STEPSCALE_X, 100.0); + obs_data_set_default_double(data, P_STEPSCALE_Y, 100.0); + + // Advanced obs_data_set_default_bool(data, S_ADVANCED, false); obs_data_set_default_int(data, P_COLORFORMAT, ColorFormat::RGB); } diff --git a/source/filter-blur.h b/source/filter-blur.h index f755c514..a8da7ce2 100644 --- a/source/filter-blur.h +++ b/source/filter-blur.h @@ -106,6 +106,14 @@ namespace filter { float_t multiplier; } mask; + // Directional + bool directional; + double_t angle; + + // Scale + bool scaling; + std::pair scale; + // advanced uint64_t color_format;