From 7cf3e17b9b0d2143be2a40b508d6d834d492f0c7 Mon Sep 17 00:00:00 2001 From: Michael Fabian 'Xaymar' Dirks Date: Tue, 29 Jan 2019 09:15:40 +0100 Subject: [PATCH] filter-sdf-effects: Fix black border and add inverse gradient shadow Sources were rendering with a black border around them if they had a soft fade, which is due to how the shadow calculated the image sample. With the new shader code this is now fixed and the source looks like it should be. Additionally this removes the bug where enabling any shadow would cause only the texels to draw that were above the threshold. Additionally this adds support for inverse gradients (min > max) and negative gradients for outer shadows instead of only positive gradients. This technically allows for cleaner shadows. --- data/effects/sdf-generator.effect | 116 +++++++++++++++++- data/effects/sdf-shadow.effect | 92 +++++++++++++- source/filter-sdf-effects.cpp | 192 ++++++++++++++---------------- source/filter-sdf-effects.hpp | 4 +- 4 files changed, 290 insertions(+), 114 deletions(-) diff --git a/data/effects/sdf-generator.effect b/data/effects/sdf-generator.effect index 5579203e..8c2e47e4 100644 --- a/data/effects/sdf-generator.effect +++ b/data/effects/sdf-generator.effect @@ -1,3 +1,31 @@ +// 2D Signed Distance Field Generator +// +// This will produce an approximated Signed Distance Field on the fly. + +// Version 1.0: +// - Inputs: +// - _image: Source Image +// - _size: Size of SDF Frame +// - _sdf: Last SDF Frame +// - _threshold: Alpha Threshold +// - Output: +// - float4 +// - R: If outside, distance to nearest wall, otherwise 0. +// - G: If inside, distance to nearest wall, otherwise 0. +// - BA: UV coordinates of nearest wall. +// +// Version 1.1: +// - See Version 1.0 +// - Adjusted R, G to be 0..1 range, multiply by 65536.0 to get proper results. + +// -------------------------------------------------------------------------------- // +// Defines +#define MAX_DISTANCE 65536.0 +#define NEAR_INFINITE 18446744073709551616.0 +#define RANGE 4 + +// -------------------------------------------------------------------------------- // + // OBS Default uniform float4x4 ViewProj; @@ -7,14 +35,19 @@ uniform float2 _size; uniform texture2d _sdf; // in, out - swap rendering uniform float _threshold; -#define NEAR_INFINITE 18446744073709551616.0 -#define RANGE 4 - sampler_state sdfSampler { Filter = Point; AddressU = Clamp; AddressV = Clamp; }; + +sampler_state sdfSampler1_1 { + Filter = Linear; + AddressU = Border; + AddressV = Border; + BorderColor = FFFFFFFF; +}; + sampler_state imageSampler { Filter = Point; AddressU = Clamp; @@ -108,12 +141,87 @@ float4 PS_SDFGenerator_v1(VertDataOut v_in) : TARGET return outval; } +float4 PS_SDFGenerator_v1_1(VertDataOut v_in) : TARGET +{ + const float step = 1.0 / MAX_DISTANCE; + + float4 outval = float4(0.0, 0.0, v_in.uv.x, v_in.uv.y); + + // utility values + float2 uv_step = 1.0 / _size; + float lowest = NEAR_INFINITE; + float2 lowest_source = float2(NEAR_INFINITE, NEAR_INFINITE); + float2 lowest_origin = float2(NEAR_INFINITE, NEAR_INFINITE); + + // inputs + float imageA = _image.Sample(imageSampler, v_in.uv).a; + float4 self = _sdf.Sample(sdfSampler1_1, v_in.uv); + + if (imageA > _threshold) { + // Inside + // TODO: Optimize to be O(n*n) instead of (2n*2n) + for (int x = -RANGE; x < RANGE; x++) { + for (int y = -RANGE; y < RANGE; y++) { + if ((x == 0) && (y == 0)) { + continue; + } + + float2 dtr = float2(x, y); + float2 dt = uv_step * dtr; + float4 here = _sdf.Sample(sdfSampler1_1, v_in.uv + dt); + float dst = abs(distance(float2(0., 0.), dtr)) * step; + + if (lowest > (here.g + dst)) { + lowest = here.g + dst; + lowest_source = v_in.uv + dt; + lowest_origin = here.ba; + } + } + } + if (lowest < NEAR_INFINITE) { + outval.g = lowest; + outval.ba = lowest_origin; + } else { + outval.g = self.g + step; + } + } else { + // Outside + // TODO: Optimize to be O(n*n) instead of (2n*2n) + for (int x = -RANGE; x < RANGE; x++) { + for (int y = -RANGE; y < RANGE; y++) { + if ((x == 0) && (y == 0)) { + continue; + } + + float2 dtr = float2(x, y); + float2 dt = uv_step * dtr; + float4 here = _sdf.Sample(sdfSampler1_1, v_in.uv + dt); + float dst = abs(distance(float2(0., 0.), dtr)) * step; + + if (lowest > (here.r + dst)) { + lowest = here.r + dst; + lowest_source = v_in.uv + dt; + lowest_origin = here.ba; + } + } + } + if (lowest < NEAR_INFINITE) { + outval.r = lowest; + outval.ba = lowest_origin; + } else { + outval.r = self.r + step; + } + } + + return outval; +} + technique Draw { pass { vertex_shader = VSDefault(v_in); - pixel_shader = PS_SDFGenerator_v1(v_in); + pixel_shader = PS_SDFGenerator_v1_1(v_in); } } diff --git a/data/effects/sdf-shadow.effect b/data/effects/sdf-shadow.effect index bb868a56..a3e1c856 100644 --- a/data/effects/sdf-shadow.effect +++ b/data/effects/sdf-shadow.effect @@ -1,3 +1,11 @@ +// -------------------------------------------------------------------------------- // +// Defines +#define MAX_DISTANCE 65536.0 +#define NEAR_INFINITE 18446744073709551616.0 +#define FLT_SMALL 0.001 + +// -------------------------------------------------------------------------------- // + // OBS Default uniform float4x4 ViewProj; @@ -14,15 +22,21 @@ uniform float2 _outer_offset; uniform float4 _outer_color; uniform float _threshold; -#define NEAR_INFINITE 18446744073709551616.0 - sampler_state sdfSampler { - Filter = Trilinear; + Filter = Linear; AddressU = Clamp; AddressV = Clamp; }; + +sampler_state sdfSampler1_1 { + Filter = Linear; + AddressU = Border; + AddressV = Border; + BorderColor = FFFF0000; +}; + sampler_state imageSampler { - Filter = Trilinear; + Filter = Linear; AddressU = Clamp; AddressV = Clamp; }; @@ -48,7 +62,7 @@ VertDataOut VSDefault(VertDataIn v_in) float4 PS_SDFShadow_v1(VertDataOut v_in) : TARGET { float4 final = _image.Sample(imageSampler, v_in.uv); - + if (_inner_max > 0 && final.a >= _threshold) { float inner_dist = _sdf.Sample(sdfSampler, v_in.uv + _inner_offset).g; float range = (_inner_max - _inner_min); @@ -65,11 +79,77 @@ float4 PS_SDFShadow_v1(VertDataOut v_in) : TARGET return final; } +float4 PS_SDFShadow_v1_1(VertDataOut v_in) : TARGET +{ + // V1.1: + // - No longer clipping off image using _threshold. + // - Inverse Gradient supported (max < min) + // - Negative Gradient support (min/max < 0) + + // Support for inverse Gradient (Outer Shadow): Maximum < Minimum + // + // Min=4.00, Max=0.00: + // Expected: Max is fully visible, Min and higher is fully shadowed. + // d=0.5 + // d = d - 4.00 (= -3.5) + // d = d / 4.00 (= -0.875, 87.5%) + // d is 87.5% visible + // Normal: + // Min=0.00, Max=4.00: + // d=0.5 + // d = d - 0.00 (= 0.5) + // d = d / 4.00 (= 0.125, 12.5%) + // d is 12.5% visible + + float4 final = float4(0., 0., 0., 0.); + float4 base = _image.Sample(imageSampler, v_in.uv); + + //! Outer Shadow + // Are we allowed to draw an outer shadow? + float2 outer_sdf = _sdf.Sample(sdfSampler, v_in.uv + _outer_offset).rg * float2(MAX_DISTANCE, MAX_DISTANCE); + if ((_outer_color.a > 0.) && (outer_sdf.r < MAX_DISTANCE)) { + // Calculate the true distance value: + // - If we are outside, this will be positive. + // - If we are inside, this will be negative. + float sdf_distance = outer_sdf.r - outer_sdf.g; + + // Calculate the delta. + float delta = _outer_max - _outer_min; + float t1 = sdf_distance - _outer_min; + float t2 = clamp(t1 / delta, 0., 1.); + + final = lerp(final, _outer_color, 1. - t2); + } + + // Base Image + final += base; + + //! Inner Shadow + // Are we allowed to draw an inner shadow? + float2 inner_sdf = _sdf.Sample(sdfSampler, v_in.uv + _inner_offset).rg * float2(MAX_DISTANCE, MAX_DISTANCE); + if ((_inner_color.a > 0.) && (inner_sdf.g < MAX_DISTANCE) && (inner_sdf.r <= FLT_SMALL)) { + // Calculate the true distance value: + // - If we are outside, this will be positive. + // - If we are inside, this will be negative. + float sdf_distance = inner_sdf.g; + + // Calculate the delta. + float delta = _inner_max - _inner_min; + float t1 = sdf_distance - _inner_min; + float t2 = clamp(t1 / delta, 0., 1.); + + // Inner shadow does not affect alpha of image. + final.rgb = lerp(final.rgb, _inner_color.rgb, (1. - t2) * _inner_color.a); + } + + return final; +} + technique Draw { pass { vertex_shader = VSDefault(v_in); - pixel_shader = PS_SDFShadow_v1(v_in); + pixel_shader = PS_SDFShadow_v1_1(v_in); } } diff --git a/source/filter-sdf-effects.cpp b/source/filter-sdf-effects.cpp index 97361560..80b0ba1d 100644 --- a/source/filter-sdf-effects.cpp +++ b/source/filter-sdf-effects.cpp @@ -115,48 +115,54 @@ obs_properties_t* filter::sdf_effects::sdf_effects_instance::get_properties() obs_property_set_long_description(p, P_TRANSLATE(P_DESC(P_SHADOW_INNER))); obs_property_set_modified_callback2(p, cb_modified_inside, this); - p = obs_properties_add_float_slider(props, P_SHADOW_INNER_RANGE_MINIMUM, P_TRANSLATE(P_SHADOW_INNER_RANGE_MINIMUM), 0.0, 16.0, - 0.01); + p = obs_properties_add_float_slider(props, P_SHADOW_INNER_RANGE_MINIMUM, P_TRANSLATE(P_SHADOW_INNER_RANGE_MINIMUM), + 0.0, 16.0, 0.01); obs_property_set_long_description(p, P_TRANSLATE(P_DESC(P_SHADOW_INNER_RANGE_MINIMUM))); - p = obs_properties_add_float_slider(props, P_SHADOW_INNER_RANGE_MAXIMUM, P_TRANSLATE(P_SHADOW_INNER_RANGE_MAXIMUM), 0.0, 16.0, - 0.01); + p = obs_properties_add_float_slider(props, P_SHADOW_INNER_RANGE_MAXIMUM, P_TRANSLATE(P_SHADOW_INNER_RANGE_MAXIMUM), + 0.0, 16.0, 0.01); obs_property_set_long_description(p, P_TRANSLATE(P_DESC(P_SHADOW_INNER_RANGE_MAXIMUM))); - p = obs_properties_add_float_slider(props, P_SHADOW_INNER_OFFSET_X, P_TRANSLATE(P_SHADOW_INNER_OFFSET_X), -100.0, 100.0, 0.01); + p = obs_properties_add_float_slider(props, P_SHADOW_INNER_OFFSET_X, P_TRANSLATE(P_SHADOW_INNER_OFFSET_X), -100.0, + 100.0, 0.01); obs_property_set_long_description(p, P_TRANSLATE(P_DESC(P_SHADOW_INNER_OFFSET_X))); - p = obs_properties_add_float_slider(props, P_SHADOW_INNER_OFFSET_Y, P_TRANSLATE(P_SHADOW_INNER_OFFSET_Y), -100.0, 100.0, 0.01); + p = obs_properties_add_float_slider(props, P_SHADOW_INNER_OFFSET_Y, P_TRANSLATE(P_SHADOW_INNER_OFFSET_Y), -100.0, + 100.0, 0.01); obs_property_set_long_description(p, P_TRANSLATE(P_DESC(P_SHADOW_INNER_OFFSET_Y))); p = obs_properties_add_color(props, P_SHADOW_INNER_COLOR, P_TRANSLATE(P_SHADOW_INNER_COLOR)); obs_property_set_long_description(p, P_TRANSLATE(P_DESC(P_SHADOW_INNER_COLOR))); - p = obs_properties_add_float_slider(props, P_SHADOW_INNER_ALPHA, P_TRANSLATE(P_SHADOW_INNER_ALPHA), 0.0, 100.0, 0.1); + p = obs_properties_add_float_slider(props, P_SHADOW_INNER_ALPHA, P_TRANSLATE(P_SHADOW_INNER_ALPHA), 0.0, 100.0, + 0.1); obs_property_set_long_description(p, P_TRANSLATE(P_DESC(P_SHADOW_INNER_ALPHA))); p = obs_properties_add_bool(props, P_SHADOW_OUTER, P_TRANSLATE(P_SHADOW_OUTER)); obs_property_set_long_description(p, P_TRANSLATE(P_DESC(P_SHADOW_OUTER))); obs_property_set_modified_callback2(p, cb_modified_outside, this); - p = obs_properties_add_float_slider(props, P_SHADOW_OUTER_RANGE_MINIMUM, P_TRANSLATE(P_SHADOW_OUTER_RANGE_MINIMUM), 0.0, 16.0, - 0.01); + p = obs_properties_add_float_slider(props, P_SHADOW_OUTER_RANGE_MINIMUM, P_TRANSLATE(P_SHADOW_OUTER_RANGE_MINIMUM), + 0.0, 16.0, 0.01); obs_property_set_long_description(p, P_TRANSLATE(P_DESC(P_SHADOW_OUTER_RANGE_MINIMUM))); - p = obs_properties_add_float_slider(props, P_SHADOW_OUTER_RANGE_MAXIMUM, P_TRANSLATE(P_SHADOW_OUTER_RANGE_MAXIMUM), 0.0, 16.0, - 0.01); + p = obs_properties_add_float_slider(props, P_SHADOW_OUTER_RANGE_MAXIMUM, P_TRANSLATE(P_SHADOW_OUTER_RANGE_MAXIMUM), + 0.0, 16.0, 0.01); obs_property_set_long_description(p, P_TRANSLATE(P_DESC(P_SHADOW_OUTER_RANGE_MAXIMUM))); - p = obs_properties_add_float_slider(props, P_SHADOW_OUTER_OFFSET_X, P_TRANSLATE(P_SHADOW_OUTER_OFFSET_X), -100.0, 100.0, 0.01); + p = obs_properties_add_float_slider(props, P_SHADOW_OUTER_OFFSET_X, P_TRANSLATE(P_SHADOW_OUTER_OFFSET_X), -100.0, + 100.0, 0.01); obs_property_set_long_description(p, P_TRANSLATE(P_DESC(P_SHADOW_OUTER_OFFSET_X))); - p = obs_properties_add_float_slider(props, P_SHADOW_OUTER_OFFSET_Y, P_TRANSLATE(P_SHADOW_OUTER_OFFSET_Y), -100.0, 100.0, 0.01); + p = obs_properties_add_float_slider(props, P_SHADOW_OUTER_OFFSET_Y, P_TRANSLATE(P_SHADOW_OUTER_OFFSET_Y), -100.0, + 100.0, 0.01); obs_property_set_long_description(p, P_TRANSLATE(P_DESC(P_SHADOW_OUTER_OFFSET_Y))); p = obs_properties_add_color(props, P_SHADOW_OUTER_COLOR, P_TRANSLATE(P_SHADOW_OUTER_COLOR)); obs_property_set_long_description(p, P_TRANSLATE(P_DESC(P_SHADOW_OUTER_COLOR))); - p = obs_properties_add_float_slider(props, P_SHADOW_OUTER_ALPHA, P_TRANSLATE(P_SHADOW_OUTER_ALPHA), 0.0, 100.0, 0.1); + p = obs_properties_add_float_slider(props, P_SHADOW_OUTER_ALPHA, P_TRANSLATE(P_SHADOW_OUTER_ALPHA), 0.0, 100.0, + 0.1); obs_property_set_long_description(p, P_TRANSLATE(P_DESC(P_SHADOW_OUTER_ALPHA))); return props; @@ -167,23 +173,17 @@ void filter::sdf_effects::sdf_effects_instance::update(obs_data_t* data) this->m_inner_shadow = obs_data_get_bool(data, P_SHADOW_INNER); this->m_inner_range_min = float_t(obs_data_get_double(data, P_SHADOW_INNER_RANGE_MINIMUM)); this->m_inner_range_max = float_t(obs_data_get_double(data, P_SHADOW_INNER_RANGE_MAXIMUM)); - if (this->m_inner_range_max < this->m_inner_range_min) { - std::swap(this->m_inner_range_max, this->m_inner_range_min); - } - this->m_inner_offset_x = float_t(obs_data_get_double(data, P_SHADOW_INNER_OFFSET_X)); - this->m_inner_offset_y = float_t(obs_data_get_double(data, P_SHADOW_INNER_OFFSET_Y)); - this->m_inner_color = (obs_data_get_int(data, P_SHADOW_INNER_COLOR) & 0x00FFFFFF) + this->m_inner_offset_x = float_t(obs_data_get_double(data, P_SHADOW_INNER_OFFSET_X)); + this->m_inner_offset_y = float_t(obs_data_get_double(data, P_SHADOW_INNER_OFFSET_Y)); + this->m_inner_color = (obs_data_get_int(data, P_SHADOW_INNER_COLOR) & 0x00FFFFFF) | (int32_t(obs_data_get_double(data, P_SHADOW_INNER_ALPHA) * 2.55) << 24); this->m_outer_shadow = obs_data_get_bool(data, P_SHADOW_OUTER); this->m_outer_range_min = float_t(obs_data_get_double(data, P_SHADOW_OUTER_RANGE_MINIMUM)); this->m_outer_range_max = float_t(obs_data_get_double(data, P_SHADOW_OUTER_RANGE_MAXIMUM)); - if (this->m_outer_range_max < this->m_outer_range_min) { - std::swap(this->m_outer_range_max, this->m_outer_range_min); - } - this->m_outer_offset_x = float_t(obs_data_get_double(data, P_SHADOW_OUTER_OFFSET_X)); - this->m_outer_offset_y = float_t(obs_data_get_double(data, P_SHADOW_OUTER_OFFSET_Y)); - this->m_outer_color = (obs_data_get_int(data, P_SHADOW_OUTER_COLOR) & 0x00FFFFFF) + this->m_outer_offset_x = float_t(obs_data_get_double(data, P_SHADOW_OUTER_OFFSET_X)); + this->m_outer_offset_y = float_t(obs_data_get_double(data, P_SHADOW_OUTER_OFFSET_Y)); + this->m_outer_color = (obs_data_get_int(data, P_SHADOW_OUTER_COLOR) & 0x00FFFFFF) | (int32_t(obs_data_get_double(data, P_SHADOW_OUTER_ALPHA) * 2.55) << 24); } @@ -203,7 +203,6 @@ void filter::sdf_effects::sdf_effects_instance::deactivate() {} void filter::sdf_effects::sdf_effects_instance::video_tick(float time) { - this->m_tick += time; m_source_rendered = false; } @@ -223,20 +222,26 @@ void filter::sdf_effects::sdf_effects_instance::video_render(gs_effect_t*) } try { + gs_blend_state_push(); + gs_reset_blend_state(); + gs_enable_blending(false); + gs_blend_function(GS_BLEND_ONE, GS_BLEND_ZERO); + + gs_set_cull_mode(GS_NEITHER); + gs_enable_color(true, true, true, true); + gs_enable_depth_test(false); + gs_depth_function(GS_ALWAYS); + gs_enable_stencil_test(false); + gs_enable_stencil_write(false); + gs_stencil_function(GS_STENCIL_BOTH, GS_ALWAYS); + gs_stencil_op(GS_STENCIL_BOTH, GS_ZERO, GS_ZERO, GS_ZERO); + if (!this->m_source_rendered) { // Store input texture. { auto op = m_source_rt->render(baseW, baseH); gs_ortho(0, (float)baseW, 0, (float)baseH, -1, 1); gs_clear(GS_CLEAR_COLOR | GS_CLEAR_DEPTH, &color_transparent, 0, 0); - gs_set_cull_mode(GS_NEITHER); - gs_reset_blend_state(); - gs_enable_blending(false); - gs_blend_function(GS_BLEND_SRCALPHA, GS_BLEND_ZERO); - gs_enable_depth_test(false); - gs_enable_stencil_test(false); - gs_enable_stencil_write(false); - gs_enable_color(true, true, true, true); if (obs_source_process_filter_begin(this->m_self, GS_RGBA, OBS_ALLOW_DIRECT_RENDERING)) { obs_source_process_filter_end(this->m_self, default_effect, baseW, baseH); @@ -266,13 +271,6 @@ void filter::sdf_effects::sdf_effects_instance::video_render(gs_effect_t*) auto op = m_sdf_write->render(baseW, baseH); gs_ortho(0, (float)baseW, 0, (float)baseH, -1, 1); gs_clear(GS_CLEAR_COLOR | GS_CLEAR_DEPTH, &color_transparent, 0, 0); - gs_set_cull_mode(GS_NEITHER); - gs_reset_blend_state(); - gs_enable_blending(false); - gs_enable_depth_test(false); - gs_enable_stencil_test(false); - gs_enable_stencil_write(false); - gs_enable_color(true, true, true, true); sdf_effect->get_parameter("_image").set_texture(this->m_source_texture); sdf_effect->get_parameter("_size").set_float2(float_t(baseW), float_t(baseH)); @@ -291,70 +289,62 @@ void filter::sdf_effects::sdf_effects_instance::video_render(gs_effect_t*) } } - { - std::shared_ptr shadow_effect = - filter::sdf_effects::sdf_effects_factory::get()->get_sdf_shadow_effect(); - if (!shadow_effect) { - throw std::runtime_error("Shadow Effect no loaded"); - } - - gs_set_cull_mode(GS_NEITHER); - gs_reset_blend_state(); - gs_enable_blending(true); - gs_blend_function(GS_BLEND_SRCALPHA, GS_BLEND_INVSRCALPHA); - gs_enable_depth_test(false); - gs_enable_stencil_test(false); - gs_enable_stencil_write(false); - gs_enable_color(true, true, true, true); - - shadow_effect->get_parameter("_sdf").set_texture(this->m_sdf_texture); - shadow_effect->get_parameter("_image").set_texture(this->m_source_texture); - shadow_effect->get_parameter("_threshold").set_float(0.5f); - - if (this->m_inner_shadow) { - shadow_effect->get_parameter("_inner_min").set_float(this->m_inner_range_min); - shadow_effect->get_parameter("_inner_max").set_float(this->m_inner_range_max); - shadow_effect->get_parameter("_inner_offset") - .set_float2(this->m_inner_offset_x / float_t(baseW), this->m_inner_offset_y / float_t(baseH)); - shadow_effect->get_parameter("_inner_color") - .set_float4((this->m_inner_color & 0xFF) / 255.0f, ((this->m_inner_color >> 8) & 0xFF) / 255.0f, - ((this->m_inner_color >> 16) & 0xFF) / 255.0f, - ((this->m_inner_color >> 24) & 0xFF) / 255.0f); - } else { - shadow_effect->get_parameter("_inner_min").set_float(0.); - shadow_effect->get_parameter("_inner_max").set_float(0.); - shadow_effect->get_parameter("_inner_offset").set_float2(0., 0.); - shadow_effect->get_parameter("_inner_color").set_float4(0., 0., 0., 0.); - } - if (this->m_outer_shadow) { - shadow_effect->get_parameter("_outer_min").set_float(this->m_outer_range_min); - shadow_effect->get_parameter("_outer_max").set_float(this->m_outer_range_max); - shadow_effect->get_parameter("_outer_offset") - .set_float2(this->m_outer_offset_x / float_t(baseW), this->m_outer_offset_y / float_t(baseH)); - shadow_effect->get_parameter("_outer_color") - .set_float4((this->m_outer_color & 0xFF) / 255.0f, ((this->m_outer_color >> 8) & 0xFF) / 255.0f, - ((this->m_outer_color >> 16) & 0xFF) / 255.0f, - ((this->m_outer_color >> 24) & 0xFF) / 255.0f); - } else { - shadow_effect->get_parameter("_outer_min").set_float(0.); - shadow_effect->get_parameter("_outer_max").set_float(0.); - shadow_effect->get_parameter("_outer_offset").set_float2(0., 0.); - shadow_effect->get_parameter("_outer_color").set_float4(0., 0., 0., 0.); - } - - while (gs_effect_loop(shadow_effect->get_object(), "Draw")) { - gs_draw_sprite(this->m_source_texture->get_object(), 0, baseW, baseH); - } - } + gs_blend_state_pop(); } catch (...) { - gs_reset_blend_state(); - gs_enable_depth_test(false); + gs_blend_state_pop(); obs_source_skip_video_filter(this->m_self); return; } - gs_reset_blend_state(); - gs_enable_depth_test(false); + try { + std::shared_ptr shadow_effect = + filter::sdf_effects::sdf_effects_factory::get()->get_sdf_shadow_effect(); + if (!shadow_effect) { + throw std::runtime_error("Shadow Effect no loaded"); + } + + shadow_effect->get_parameter("_sdf").set_texture(this->m_sdf_texture); + shadow_effect->get_parameter("_image").set_texture(this->m_source_texture); + shadow_effect->get_parameter("_threshold").set_float(0.5f); + + if (this->m_inner_shadow) { + shadow_effect->get_parameter("_inner_min").set_float(this->m_inner_range_min); + shadow_effect->get_parameter("_inner_max").set_float(this->m_inner_range_max); + shadow_effect->get_parameter("_inner_offset") + .set_float2(this->m_inner_offset_x / float_t(baseW), this->m_inner_offset_y / float_t(baseH)); + shadow_effect->get_parameter("_inner_color") + .set_float4((this->m_inner_color & 0xFF) / 255.0f, ((this->m_inner_color >> 8) & 0xFF) / 255.0f, + ((this->m_inner_color >> 16) & 0xFF) / 255.0f, + ((this->m_inner_color >> 24) & 0xFF) / 255.0f); + } else { + shadow_effect->get_parameter("_inner_min").set_float(0.); + shadow_effect->get_parameter("_inner_max").set_float(0.); + shadow_effect->get_parameter("_inner_offset").set_float2(0., 0.); + shadow_effect->get_parameter("_inner_color").set_float4(0., 0., 0., 0.); + } + if (this->m_outer_shadow) { + shadow_effect->get_parameter("_outer_min").set_float(this->m_outer_range_min); + shadow_effect->get_parameter("_outer_max").set_float(this->m_outer_range_max); + shadow_effect->get_parameter("_outer_offset") + .set_float2(this->m_outer_offset_x / float_t(baseW), this->m_outer_offset_y / float_t(baseH)); + shadow_effect->get_parameter("_outer_color") + .set_float4((this->m_outer_color & 0xFF) / 255.0f, ((this->m_outer_color >> 8) & 0xFF) / 255.0f, + ((this->m_outer_color >> 16) & 0xFF) / 255.0f, + ((this->m_outer_color >> 24) & 0xFF) / 255.0f); + } else { + shadow_effect->get_parameter("_outer_min").set_float(0.); + shadow_effect->get_parameter("_outer_max").set_float(0.); + shadow_effect->get_parameter("_outer_offset").set_float2(0., 0.); + shadow_effect->get_parameter("_outer_color").set_float4(0., 0., 0., 0.); + } + + while (gs_effect_loop(shadow_effect->get_object(), "Draw")) { + gs_draw_sprite(this->m_source_texture->get_object(), 0, baseW, baseH); + } + } catch (...) { + obs_source_skip_video_filter(this->m_self); + return; + } } filter::sdf_effects::sdf_effects_factory::sdf_effects_factory() diff --git a/source/filter-sdf-effects.hpp b/source/filter-sdf-effects.hpp index aa67d742..a40446f5 100644 --- a/source/filter-sdf-effects.hpp +++ b/source/filter-sdf-effects.hpp @@ -95,9 +95,7 @@ namespace filter { // Distance Field std::shared_ptr m_sdf_write, m_sdf_read; std::shared_ptr m_sdf_texture; - - float_t m_tick = 0.; - + bool m_inner_shadow; float_t m_inner_range_min; float_t m_inner_range_max;