filter-blur: Allow applying Blur to a sub-region of the source only

The Blur Filter can now be applied to a region inside the source itself, the inverse of that region, and/or a feathered version of that region. This allows for easier scene setups where only some parts need to be blurred, but the rest can be left as is.

Fixes #12
This commit is contained in:
Michael Fabian 'Xaymar' Dirks 2018-04-29 00:14:29 +02:00
parent 1ba9145fbd
commit af71a7cc1d
6 changed files with 484 additions and 37 deletions

View file

@ -9,6 +9,14 @@ uniform int u_radius;
uniform int u_diameter;
uniform float2 u_texelDelta;
/// Region
uniform float regionLeft;
uniform float regionTop;
uniform float regionRight;
uniform float regionBottom;
uniform float regionFeather;
uniform float regionFeatherShift;
// Settings (Private)
uniform float bilateralSmoothing;
uniform float bilateralSharpness;
@ -17,6 +25,8 @@ sampler_state textureSampler {
Filter = Point;
AddressU = Clamp;
AddressV = Clamp;
MinLOD = 0;
MaxLOD = 0;
};
struct VertDataIn {
@ -38,33 +48,23 @@ VertDataOut VSDefault(VertDataIn v_in)
}
// Bilateral Blur
float Bilateral(float x, float sigma)
{
float Bilateral(float x, float sigma) {
return 0.39894 * exp(-0.5 * (x*x) / (sigma*sigma)) / sigma;
}
float Bilateral3(float3 v, float sigma)
{
// First part is Gaussian function (1.0 / (o * sqrt(2.0 * pivalue))) with o = 1
float Bilateral3(float3 v, float sigma) {
// First part is Bilateral function (1.0 / (o * sqrt(2.0 * pivalue))) with o = 1
return 0.39894 * exp(-0.5 * dot(v,v) / (sigma*sigma)) / sigma;
}
float4 BilateralBlur(float2 p_uv, float2 p_radius,
texture2d p_image, float2 p_imageTexel) {
float2 l_uvoffset = float2(0, 0);
}
float4 PSBilateral(VertDataOut v_in) : TARGET
{
float2 l_uv = float2(0, 0);
float4 BlurFunc(float2 uv, float4 rgba) {
float2 uvOffset = float2(0, 0);
float Z = 0.0;
float bZ = 1.0 / Bilateral(0.0, bilateralSharpness);
float4 source = u_image.Sample(textureSampler, v_in.uv);
float3 color = float3(0, 0, 0);
for (int k = 1; k <= u_radius; k++) {
// Advance UV by one texel.
l_uv += u_texelDelta;
uvOffset += u_texelDelta;
// Bilateral Kernel
float bKernel = Bilateral(abs(k), bilateralSmoothing);
@ -72,12 +72,12 @@ float4 PSBilateral(VertDataOut v_in) : TARGET
float bZKernel = bZ * bKernel;
// Sample Color
float3 l_p = u_image.Sample(textureSampler, v_in.uv + l_uv).rgb;
float3 l_n = u_image.Sample(textureSampler, v_in.uv - l_uv).rgb;
float3 l_p = u_image.SampleLevel(textureSampler, uv + uvOffset, 0).rgb;
float3 l_n = u_image.SampleLevel(textureSampler, uv - uvOffset, 0).rgb;
// Bilateral Stuff
float l_factor_p = Bilateral3(l_p - source.rgb, bilateralSharpness) * bZKernel;
float l_factor_n = Bilateral3(l_n - source.rgb, bilateralSharpness) * bZKernel;
float l_factor_p = Bilateral3(l_p - rgba.rgb, bilateralSharpness) * bZKernel;
float l_factor_n = Bilateral3(l_n - rgba.rgb, bilateralSharpness) * bZKernel;
Z = Z + l_factor_p + l_factor_n;
// Store Color
@ -85,7 +85,74 @@ float4 PSBilateral(VertDataOut v_in) : TARGET
color += l_n * l_factor_n;
}
return float4(color.rgb / Z, source.a);
return float4(color.rgb / Z, rgba.a);
}
float4 PSBilateral(VertDataOut v_in) : TARGET {
float4 rgba = u_image.SampleLevel(textureSampler, v_in.uv, 0);
return BlurFunc(v_in.uv, rgba);
}
float4 PSBilateralRegion(VertDataOut v_in) : TARGET {
float4 rgba = u_image.SampleLevel(textureSampler, v_in.uv, 0);
if ((v_in.uv.x < regionLeft)
|| (v_in.uv.x > regionRight)
|| (v_in.uv.y < regionTop)
|| (v_in.uv.y > regionBottom)) {
return rgba;
}
return BlurFunc(v_in.uv, rgba);
}
float4 PSBilateralRegionInvert(VertDataOut v_in) : TARGET {
float4 rgba = u_image.SampleLevel(textureSampler, v_in.uv, 0);
if ((v_in.uv.x > regionLeft)
&& (v_in.uv.x < regionRight)
&& (v_in.uv.y > regionTop)
&& (v_in.uv.y < regionBottom)) {
return rgba;
}
return BlurFunc(v_in.uv, rgba);
}
float4 PSBilateralRegionFeather(VertDataOut v_in) : TARGET {
float halfFeather = (regionFeather / 2.0);
float feather = max(regionFeather, 0.00000001);
float leftFeather = clamp(((v_in.uv.x - regionLeft + halfFeather) / feather) + regionFeatherShift, 0.0, 1.0);
float rightFeather = clamp(((-(v_in.uv.x - regionRight) + halfFeather) / feather) + regionFeatherShift, 0.0, 1.0);
float topFeather = clamp(((v_in.uv.y - regionTop + halfFeather) / feather) + regionFeatherShift, 0.0, 1.0);
float bottomFeather = clamp(((-(v_in.uv.y - regionBottom) + halfFeather) / feather) + regionFeatherShift, 0.0, 1.0);
float finalFeather = min(min(leftFeather, rightFeather), min(topFeather, bottomFeather));
float4 rgba = u_image.SampleLevel(textureSampler, v_in.uv, 0);
if (finalFeather <= 0.00001) {
return rgba;
} else if (finalFeather >= 0.99999) {
return BlurFunc(v_in.uv, rgba);
}
return lerp(rgba, BlurFunc(v_in.uv, rgba), finalFeather);
}
float4 PSBilateralRegionFeatherInvert(VertDataOut v_in) : TARGET {
float halfFeather = (regionFeather / 2.0);
float feather = max(regionFeather, 0.00000001);
float leftFeather = clamp(((v_in.uv.x - regionLeft + halfFeather) / feather) + regionFeatherShift, 0.0, 1.0);
float rightFeather = clamp(((-(v_in.uv.x - regionRight) + halfFeather) / feather) + regionFeatherShift, 0.0, 1.0);
float topFeather = clamp(((v_in.uv.y - regionTop + halfFeather) / feather) + regionFeatherShift, 0.0, 1.0);
float bottomFeather = clamp(((-(v_in.uv.y - regionBottom) + halfFeather) / feather) + regionFeatherShift, 0.0, 1.0);
float finalFeather = 1.0 - min(min(leftFeather, rightFeather), min(topFeather, bottomFeather));
float4 rgba = u_image.SampleLevel(textureSampler, v_in.uv, 0);
if (finalFeather <= 0.00001) {
return rgba;
} else if (finalFeather >= 0.99999) {
return BlurFunc(v_in.uv, rgba);
}
return lerp(rgba, BlurFunc(v_in.uv, rgba), finalFeather);
}
technique Draw
@ -96,3 +163,37 @@ technique Draw
pixel_shader = PSBilateral(v_in);
}
}
technique DrawRegion
{
pass
{
vertex_shader = VSDefault(v_in);
pixel_shader = PSBilateralRegion(v_in);
}
}
technique DrawRegionInvert
{
pass
{
vertex_shader = VSDefault(v_in);
pixel_shader = PSBilateralRegionInvert(v_in);
}
}
technique DrawRegionFeather
{
pass
{
vertex_shader = VSDefault(v_in);
pixel_shader = PSBilateralRegionFeather(v_in);
}
}
technique DrawRegionFeatherInvert
{
pass
{
vertex_shader = VSDefault(v_in);
pixel_shader = PSBilateralRegionFeatherInvert(v_in);
}
}

View file

@ -9,10 +9,21 @@ uniform int u_radius;
uniform int u_diameter;
uniform float2 u_texelDelta;
/// Region
uniform float regionLeft;
uniform float regionTop;
uniform float regionRight;
uniform float regionBottom;
uniform float regionFeather;
uniform float regionFeatherShift;
// Data
sampler_state textureSampler {
Filter = Point;
AddressU = Clamp;
AddressV = Clamp;
MinLOD = 0;
MaxLOD = 0;
};
struct VertDataIn {
@ -34,17 +45,82 @@ VertDataOut VSDefault(VertDataIn v_in)
}
// Box Blur
float4 PSBox(VertDataOut v_in) : TARGET
{
float4 rgba = u_image.Sample(textureSampler, v_in.uv);
float4 BlurFunc(float2 uv, float4 rgba) {
float4 final = rgba;
for (int k = 1; k <= u_radius; k++) {
rgba += u_image.Sample(textureSampler, v_in.uv + (u_texelDelta * k));
rgba += u_image.Sample(textureSampler, v_in.uv - (u_texelDelta * k));
final += u_image.SampleLevel(textureSampler, uv + (u_texelDelta * k), 0);
final += u_image.SampleLevel(textureSampler, uv - (u_texelDelta * k), 0);
}
rgba = rgba / u_diameter;
return final / u_diameter;
}
float4 PSBox(VertDataOut v_in) : TARGET {
float4 rgba = u_image.SampleLevel(textureSampler, v_in.uv, 0);
return BlurFunc(v_in.uv, rgba);
}
float4 PSBoxRegion(VertDataOut v_in) : TARGET {
float4 rgba = u_image.SampleLevel(textureSampler, v_in.uv, 0);
if ((v_in.uv.x < regionLeft)
|| (v_in.uv.x > regionRight)
|| (v_in.uv.y < regionTop)
|| (v_in.uv.y > regionBottom)) {
return rgba;
}
return BlurFunc(v_in.uv, rgba);
}
float4 PSBoxRegionInvert(VertDataOut v_in) : TARGET {
float4 rgba = u_image.SampleLevel(textureSampler, v_in.uv, 0);
if ((v_in.uv.x > regionLeft)
&& (v_in.uv.x < regionRight)
&& (v_in.uv.y > regionTop)
&& (v_in.uv.y < regionBottom)) {
return rgba;
}
return BlurFunc(v_in.uv, rgba);
}
float4 PSBoxRegionFeather(VertDataOut v_in) : TARGET {
float halfFeather = (regionFeather / 2.0);
float feather = max(regionFeather, 0.00000001);
float leftFeather = clamp(((v_in.uv.x - regionLeft + halfFeather) / feather) + regionFeatherShift, 0.0, 1.0);
float rightFeather = clamp(((-(v_in.uv.x - regionRight) + halfFeather) / feather) + regionFeatherShift, 0.0, 1.0);
float topFeather = clamp(((v_in.uv.y - regionTop + halfFeather) / feather) + regionFeatherShift, 0.0, 1.0);
float bottomFeather = clamp(((-(v_in.uv.y - regionBottom) + halfFeather) / feather) + regionFeatherShift, 0.0, 1.0);
float finalFeather = min(min(leftFeather, rightFeather), min(topFeather, bottomFeather));
float4 rgba = u_image.SampleLevel(textureSampler, v_in.uv, 0);
if (finalFeather <= 0.00001) {
return rgba;
} else if (finalFeather >= 0.99999) {
return BlurFunc(v_in.uv, rgba);
}
return lerp(rgba, BlurFunc(v_in.uv, rgba), finalFeather);
}
float4 PSBoxRegionFeatherInvert(VertDataOut v_in) : TARGET {
float halfFeather = (regionFeather / 2.0);
float feather = max(regionFeather, 0.00000001);
float leftFeather = clamp(((v_in.uv.x - regionLeft + halfFeather) / feather) + regionFeatherShift, 0.0, 1.0);
float rightFeather = clamp(((-(v_in.uv.x - regionRight) + halfFeather) / feather) + regionFeatherShift, 0.0, 1.0);
float topFeather = clamp(((v_in.uv.y - regionTop + halfFeather) / feather) + regionFeatherShift, 0.0, 1.0);
float bottomFeather = clamp(((-(v_in.uv.y - regionBottom) + halfFeather) / feather) + regionFeatherShift, 0.0, 1.0);
float finalFeather = 1.0 - min(min(leftFeather, rightFeather), min(topFeather, bottomFeather));
float4 rgba = u_image.SampleLevel(textureSampler, v_in.uv, 0);
if (finalFeather <= 0.00001) {
return rgba;
} else if (finalFeather >= 0.99999) {
return BlurFunc(v_in.uv, rgba);
}
return lerp(rgba, BlurFunc(v_in.uv, rgba), finalFeather);
}
technique Draw
{
pass
@ -53,3 +129,39 @@ technique Draw
pixel_shader = PSBox(v_in);
}
}
technique DrawRegion
{
pass
{
vertex_shader = VSDefault(v_in);
pixel_shader = PSBoxRegion(v_in);
}
}
technique DrawRegionInvert
{
pass
{
vertex_shader = VSDefault(v_in);
pixel_shader = PSBoxRegionInvert(v_in);
}
}
technique DrawRegionFeather
{
pass
{
vertex_shader = VSDefault(v_in);
pixel_shader = PSBoxRegionFeather(v_in);
}
}
technique DrawRegionFeatherInvert
{
pass
{
vertex_shader = VSDefault(v_in);
pixel_shader = PSBoxRegionFeatherInvert(v_in);
}
}

View file

@ -9,6 +9,14 @@ uniform int u_radius;
uniform int u_diameter;
uniform float2 u_texelDelta;
/// Region
uniform float regionLeft;
uniform float regionTop;
uniform float regionRight;
uniform float regionBottom;
uniform float regionFeather;
uniform float regionFeatherShift;
// Settings (Private)
//uniform float registerkernel[25];
uniform texture2d kernel;
@ -40,20 +48,86 @@ VertDataOut VSDefault(VertDataIn v_in)
return vert_out;
}
float4 PSGaussian(VertDataOut v_in) : TARGET {
float4 BlurFunc(float2 uv, float4 rgba) {
float2 uvOffset = float2(0, 0);
float4 rgba = u_image.SampleLevel(textureSampler, v_in.uv, 0)
* kernel.SampleLevel(textureSampler, (float2(0, u_radius - 1) * kernelTexel), 0).r;
float4 final = rgba * kernel.SampleLevel(textureSampler, (float2(0, u_radius - 1) * kernelTexel), 0).r;
for (int k = 1; k <= u_radius; k++) {
uvOffset += u_texelDelta;
float l_g = kernel.SampleLevel(textureSampler, (float2(k, u_radius - 1) * kernelTexel), 0).r;
float4 l_p = u_image.SampleLevel(textureSampler, v_in.uv + uvOffset, 0) * l_g;
float4 l_n = u_image.SampleLevel(textureSampler, v_in.uv - uvOffset, 0) * l_g;
rgba += l_p + l_n;
float4 l_p = u_image.SampleLevel(textureSampler, uv + uvOffset, 0);
float4 l_n = u_image.SampleLevel(textureSampler, uv - uvOffset, 0);
final += (l_p + l_n) * l_g;
}
return final;
}
float4 PSGaussian(VertDataOut v_in) : TARGET {
float4 rgba = u_image.SampleLevel(textureSampler, v_in.uv, 0);
return BlurFunc(v_in.uv, rgba);
}
float4 PSGaussianRegion(VertDataOut v_in) : TARGET {
float4 rgba = u_image.SampleLevel(textureSampler, v_in.uv, 0);
if ((v_in.uv.x < regionLeft)
|| (v_in.uv.x > regionRight)
|| (v_in.uv.y < regionTop)
|| (v_in.uv.y > regionBottom)) {
return rgba;
}
return BlurFunc(v_in.uv, rgba);
}
float4 PSGaussianRegionInvert(VertDataOut v_in) : TARGET {
float4 rgba = u_image.SampleLevel(textureSampler, v_in.uv, 0);
if ((v_in.uv.x > regionLeft)
&& (v_in.uv.x < regionRight)
&& (v_in.uv.y > regionTop)
&& (v_in.uv.y < regionBottom)) {
return rgba;
}
return BlurFunc(v_in.uv, rgba);
}
float4 PSGaussianRegionFeather(VertDataOut v_in) : TARGET {
float halfFeather = (regionFeather / 2.0);
float feather = max(regionFeather, 0.00000001);
float leftFeather = clamp(((v_in.uv.x - regionLeft + halfFeather) / feather) + regionFeatherShift, 0.0, 1.0);
float rightFeather = clamp(((-(v_in.uv.x - regionRight) + halfFeather) / feather) + regionFeatherShift, 0.0, 1.0);
float topFeather = clamp(((v_in.uv.y - regionTop + halfFeather) / feather) + regionFeatherShift, 0.0, 1.0);
float bottomFeather = clamp(((-(v_in.uv.y - regionBottom) + halfFeather) / feather) + regionFeatherShift, 0.0, 1.0);
float finalFeather = min(min(leftFeather, rightFeather), min(topFeather, bottomFeather));
float4 rgba = u_image.SampleLevel(textureSampler, v_in.uv, 0);
if (finalFeather <= 0.00001) {
return rgba;
} else if (finalFeather >= 0.99999) {
return BlurFunc(v_in.uv, rgba);
}
return lerp(rgba, BlurFunc(v_in.uv, rgba), finalFeather);
}
float4 PSGaussianRegionFeatherInvert(VertDataOut v_in) : TARGET {
float halfFeather = (regionFeather / 2.0);
float feather = max(regionFeather, 0.00000001);
float leftFeather = clamp(((v_in.uv.x - regionLeft + halfFeather) / feather) + regionFeatherShift, 0.0, 1.0);
float rightFeather = clamp(((-(v_in.uv.x - regionRight) + halfFeather) / feather) + regionFeatherShift, 0.0, 1.0);
float topFeather = clamp(((v_in.uv.y - regionTop + halfFeather) / feather) + regionFeatherShift, 0.0, 1.0);
float bottomFeather = clamp(((-(v_in.uv.y - regionBottom) + halfFeather) / feather) + regionFeatherShift, 0.0, 1.0);
float finalFeather = 1.0 - min(min(leftFeather, rightFeather), min(topFeather, bottomFeather));
float4 rgba = u_image.SampleLevel(textureSampler, v_in.uv, 0);
if (finalFeather <= 0.00001) {
return rgba;
} else if (finalFeather >= 0.99999) {
return BlurFunc(v_in.uv, rgba);
}
return lerp(rgba, BlurFunc(v_in.uv, rgba), finalFeather);
}
technique Draw
{
pass
@ -62,3 +136,37 @@ technique Draw
pixel_shader = PSGaussian(v_in);
}
}
technique DrawRegion
{
pass
{
vertex_shader = VSDefault(v_in);
pixel_shader = PSGaussianRegion(v_in);
}
}
technique DrawRegionInvert
{
pass
{
vertex_shader = VSDefault(v_in);
pixel_shader = PSGaussianRegionInvert(v_in);
}
}
technique DrawRegionFeather
{
pass
{
vertex_shader = VSDefault(v_in);
pixel_shader = PSGaussianRegionFeather(v_in);
}
}
technique DrawRegionFeatherInvert
{
pass
{
vertex_shader = VSDefault(v_in);
pixel_shader = PSGaussianRegionFeatherInvert(v_in);
}
}

View file

@ -12,6 +12,22 @@ 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.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"
Filter.Blur.Region.Left.Description="Distance to left edge of the source in percent."
Filter.Blur.Region.Top="Top Edge"
Filter.Blur.Region.Top.Description="Distance to top edge of the source in percent."
Filter.Blur.Region.Right="Right Edge"
Filter.Blur.Region.Right.Description="Distance to right edge of the source in percent."
Filter.Blur.Region.Bottom="Bottom Edge"
Filter.Blur.Region.Bottom.Description="Distance to bottom edge of the source in percent."
Filter.Blur.Region.Feather="Feather Area"
Filter.Blur.Region.Feather.Description="Size of the smoothing area in percent, or 0 to turn off feather."
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 - Custom Shader

View file

@ -44,6 +44,16 @@ extern "C" {
#define S_BILATERAL_SMOOTHING "Filter.Blur.Bilateral.Smoothing"
#define S_BILATERAL_SHARPNESS "Filter.Blur.Bilateral.Sharpness"
// Region
#define S_REGION "Filter.Blur.Region"
#define S_REGION_LEFT "Filter.Blur.Region.Left"
#define S_REGION_TOP "Filter.Blur.Region.Top"
#define S_REGION_RIGHT "Filter.Blur.Region.Right"
#define S_REGION_BOTTOM "Filter.Blur.Region.Bottom"
#define S_REGION_FEATHER "Filter.Blur.Region.Feather"
#define S_REGION_FEATHER_SHIFT "Filter.Blur.Region.Feather.Shift"
#define S_REGION_INVERT "Filter.Blur.Region.Invert"
// Advanced
#define S_FILTER_BLUR_COLORFORMAT "Filter.Blur.ColorFormat"
@ -96,6 +106,7 @@ Filter::Blur::Blur() {
} catch (std::runtime_error ex) {
P_LOG_ERROR("<filter-blur> Loading effect '%s' (path: '%s') failed with error(s): %s",
kv.first.c_str(), kv.second.c_str(), ex.what());
obs_leave_graphics();
return;
}
}
@ -160,6 +171,16 @@ void Filter::Blur::get_defaults(obs_data_t *data) {
obs_data_set_default_double(data, S_BILATERAL_SMOOTHING, 50.0);
obs_data_set_default_double(data, S_BILATERAL_SHARPNESS, 90.0);
// Region
obs_data_set_default_bool(data, S_REGION, false);
obs_data_set_default_double(data, S_REGION_LEFT, 0.0f);
obs_data_set_default_double(data, S_REGION_TOP, 0.0f);
obs_data_set_default_double(data, S_REGION_RIGHT, 0.0f);
obs_data_set_default_double(data, S_REGION_BOTTOM, 0.0f);
obs_data_set_default_double(data, S_REGION_FEATHER, 0.0f);
obs_data_set_default_double(data, S_REGION_FEATHER_SHIFT, 0.0f);
obs_data_set_default_bool(data, S_REGION_INVERT, false);
// Advanced
obs_data_set_default_bool(data, S_ADVANCED, false);
obs_data_set_default_int(data, S_FILTER_BLUR_COLORFORMAT, ColorFormat::RGB);
@ -186,6 +207,25 @@ obs_properties_t * Filter::Blur::get_properties(void *) {
p = obs_properties_add_float_slider(pr, S_BILATERAL_SHARPNESS, P_TRANSLATE(S_BILATERAL_SHARPNESS), 0, 99.99, 0.01);
obs_property_set_long_description(p, P_TRANSLATE(P_DESC(S_BILATERAL_SHARPNESS)));
// Region
p = obs_properties_add_bool(pr, S_REGION, P_TRANSLATE(S_REGION));
obs_property_set_long_description(p, P_TRANSLATE(P_DESC(S_REGION)));
obs_property_set_modified_callback(p, modified_properties);
p = obs_properties_add_float_slider(pr, S_REGION_LEFT, P_TRANSLATE(S_REGION_LEFT), 0.0, 100.0, 0.01);
obs_property_set_long_description(p, P_TRANSLATE(P_DESC(S_REGION_LEFT)));
p = obs_properties_add_float_slider(pr, S_REGION_TOP, P_TRANSLATE(S_REGION_TOP), 0.0, 100.0, 0.01);
obs_property_set_long_description(p, P_TRANSLATE(P_DESC(S_REGION_TOP)));
p = obs_properties_add_float_slider(pr, S_REGION_RIGHT, P_TRANSLATE(S_REGION_RIGHT), 0.0, 100.0, 0.01);
obs_property_set_long_description(p, P_TRANSLATE(P_DESC(S_REGION_RIGHT)));
p = obs_properties_add_float_slider(pr, S_REGION_BOTTOM, P_TRANSLATE(S_REGION_BOTTOM), 0.0, 100.0, 0.01);
obs_property_set_long_description(p, P_TRANSLATE(P_DESC(S_REGION_BOTTOM)));
p = obs_properties_add_float_slider(pr, S_REGION_FEATHER, P_TRANSLATE(S_REGION_FEATHER), 0.0, 50.0, 0.01);
obs_property_set_long_description(p, P_TRANSLATE(P_DESC(S_REGION_FEATHER)));
p = obs_properties_add_float_slider(pr, S_REGION_FEATHER_SHIFT, P_TRANSLATE(S_REGION_FEATHER_SHIFT), -100.0, 100.0, 0.01);
obs_property_set_long_description(p, P_TRANSLATE(P_DESC(S_REGION_FEATHER_SHIFT)));
p = obs_properties_add_bool(pr, S_REGION_INVERT, P_TRANSLATE(S_REGION_INVERT));
obs_property_set_long_description(p, P_TRANSLATE(P_DESC(S_REGION_INVERT)));
// Advanced
p = obs_properties_add_bool(pr, S_ADVANCED, P_TRANSLATE(S_ADVANCED));
obs_property_set_long_description(p, P_TRANSLATE(P_DESC(S_ADVANCED)));
@ -216,6 +256,16 @@ bool Filter::Blur::modified_properties(obs_properties_t *pr, obs_property_t *, o
obs_property_set_visible(obs_properties_get(pr, S_BILATERAL_SMOOTHING), showBilateral);
obs_property_set_visible(obs_properties_get(pr, S_BILATERAL_SHARPNESS), showBilateral);
// Region
bool showRegion = obs_data_get_bool(d, S_REGION);
obs_property_set_visible(obs_properties_get(pr, S_REGION_LEFT), showRegion);
obs_property_set_visible(obs_properties_get(pr, S_REGION_TOP), showRegion);
obs_property_set_visible(obs_properties_get(pr, S_REGION_RIGHT), showRegion);
obs_property_set_visible(obs_properties_get(pr, S_REGION_BOTTOM), showRegion);
obs_property_set_visible(obs_properties_get(pr, S_REGION_FEATHER), showRegion);
obs_property_set_visible(obs_properties_get(pr, S_REGION_FEATHER_SHIFT), showRegion);
obs_property_set_visible(obs_properties_get(pr, S_REGION_INVERT), showRegion);
// Advanced
bool showAdvanced = false;
if (obs_data_get_bool(d, S_ADVANCED))
@ -312,8 +362,24 @@ void Filter::Blur::Instance::update(obs_data_t *data) {
m_bilateralSmoothing = obs_data_get_double(data, S_BILATERAL_SMOOTHING) / 100.0;
m_bilateralSharpness = obs_data_get_double(data, S_BILATERAL_SHARPNESS) / 100.0;
// Region
m_region.enabled = obs_data_get_bool(data, S_REGION);
if (m_region.enabled) {
m_region.left = float_t(obs_data_get_double(data, S_REGION_LEFT) / 100.0);
m_region.top = float_t(obs_data_get_double(data, S_REGION_TOP) / 100.0);
m_region.right = 1.0 - float_t(obs_data_get_double(data, S_REGION_RIGHT) / 100.0);
m_region.bottom = 1.0 - float_t(obs_data_get_double(data, S_REGION_BOTTOM) / 100.0);
m_region.feather = float_t(obs_data_get_double(data, S_REGION_FEATHER) / 100.0);
m_region.feather_shift = float_t(obs_data_get_double(data, S_REGION_FEATHER_SHIFT) / 100.0);
m_region.invert = obs_data_get_bool(data, S_REGION_INVERT);
}
// Advanced
if (obs_data_get_bool(data, S_ADVANCED)) {
m_colorFormat = obs_data_get_int(data, S_FILTER_BLUR_COLORFORMAT);
} else {
m_colorFormat = obs_data_get_default_int(data, S_FILTER_BLUR_COLORFORMAT);
}
}
uint32_t Filter::Blur::Instance::get_width() {
@ -469,6 +535,17 @@ void Filter::Blur::Instance::video_render(gs_effect_t *effect) {
std::make_tuple("Horizontal", m_rtHorizontal, 1.0f / baseW, 0.0f),
std::make_tuple("Vertical", m_rtVertical, 0.0f, 1.0f / baseH),
};
std::string pass = "Draw";
if (m_region.enabled) {
if (m_region.feather > 0) {
pass = "DrawRegionFeather";
} else {
pass = "DrawRegion";
}
if (m_region.invert) {
pass += "Invert";
}
}
for (auto v : kvs) {
const char* name = std::get<0>(v);
gs_texrender_t* rt = std::get<1>(v);
@ -497,7 +574,7 @@ void Filter::Blur::Instance::video_render(gs_effect_t *effect) {
gs_clear(GS_CLEAR_COLOR | GS_CLEAR_DEPTH, &black, 0, 0);
// Render
while (gs_effect_loop(m_effect->get_object(), "Draw")) {
while (gs_effect_loop(m_effect->get_object(), pass.c_str())) {
gs_draw_sprite(intermediate, 0, baseW, baseH);
}
@ -578,6 +655,27 @@ bool Filter::Blur::Instance::apply_shared_param(gs_texture_t* input, float texel
result = result && gs_set_param_int(m_effect->get_object(), "u_radius", (int)m_size);
result = result && gs_set_param_int(m_effect->get_object(), "u_diameter", (int)(1 + (m_size * 2)));
if (m_region.enabled) {
if (m_effect->has_parameter("regionLeft")) {
m_effect->get_parameter("regionLeft").set_float(m_region.left);
}
if (m_effect->has_parameter("regionTop")) {
m_effect->get_parameter("regionTop").set_float(m_region.top);
}
if (m_effect->has_parameter("regionRight")) {
m_effect->get_parameter("regionRight").set_float(m_region.right);
}
if (m_effect->has_parameter("regionBottom")) {
m_effect->get_parameter("regionBottom").set_float(m_region.bottom);
}
if (m_effect->has_parameter("regionFeather")) {
m_effect->get_parameter("regionFeather").set_float(m_region.feather);
}
if (m_effect->has_parameter("regionFeatherShift")) {
m_effect->get_parameter("regionFeatherShift").set_float(m_region.feather_shift);
}
}
return result;
}

View file

@ -98,6 +98,18 @@ namespace Filter {
double_t m_bilateralSmoothing;
double_t m_bilateralSharpness;
// Regional
struct Region {
bool enabled;
float_t left;
float_t top;
float_t right;
float_t bottom;
float_t feather;
float_t feather_shift;
bool invert;
} m_region;
// Advanced
bool m_errorLogged = false;
uint64_t m_colorFormat;