obs-filters: Increase opacity precision

For v2 filters, switch Opacity settings from integer [0, 100] to
floating-point [0.0, 1.0] with four decimal places for granular blacks.

Also multiply alpha in shader to maintain precision.
This commit is contained in:
jpark37 2021-04-29 23:36:40 -07:00 committed by Jim
parent ec25ade9f2
commit e55bfa8e20
12 changed files with 123 additions and 37 deletions

View File

@ -119,8 +119,7 @@ static inline void
color_settings_update_v2(struct chroma_key_filter_data_v2 *filter,
obs_data_t *settings)
{
filter->opacity =
(float)obs_data_get_int(settings, SETTING_OPACITY) * 0.01f;
filter->opacity = (float)obs_data_get_double(settings, SETTING_OPACITY);
double contrast = obs_data_get_double(settings, SETTING_CONTRAST);
contrast = (contrast < 0.0) ? (1.0 / (-contrast + 1.0))
@ -388,9 +387,14 @@ static void chroma_key_render_v2(void *data, gs_effect_t *effect)
gs_effect_set_float(filter->smoothness_param, filter->smoothness);
gs_effect_set_float(filter->spill_param, filter->spill);
gs_blend_state_push();
gs_blend_function(GS_BLEND_ONE, GS_BLEND_INVSRCALPHA);
obs_source_process_filter_end_srgb(filter->context, filter->effect, 0,
0);
gs_blend_state_pop();
UNUSED_PARAMETER(effect);
}
@ -466,8 +470,8 @@ static obs_properties_t *chroma_key_properties_v2(void *data)
obs_properties_add_int_slider(props, SETTING_SPILL, TEXT_SPILL, 1, 1000,
1);
obs_properties_add_int_slider(props, SETTING_OPACITY, TEXT_OPACITY, 0,
100, 1);
obs_properties_add_float_slider(props, SETTING_OPACITY, TEXT_OPACITY,
0.0, 1.0, 0.0001);
obs_properties_add_float_slider(props, SETTING_CONTRAST, TEXT_CONTRAST,
-4.0, 4.0, 0.01);
obs_properties_add_float_slider(props, SETTING_BRIGHTNESS,
@ -479,7 +483,7 @@ static obs_properties_t *chroma_key_properties_v2(void *data)
return props;
}
static void chroma_key_defaults(obs_data_t *settings)
static void chroma_key_defaults_v1(obs_data_t *settings)
{
obs_data_set_default_int(settings, SETTING_OPACITY, 100);
obs_data_set_default_double(settings, SETTING_CONTRAST, 0.0);
@ -492,6 +496,19 @@ static void chroma_key_defaults(obs_data_t *settings)
obs_data_set_default_int(settings, SETTING_SPILL, 100);
}
static void chroma_key_defaults_v2(obs_data_t *settings)
{
obs_data_set_default_double(settings, SETTING_OPACITY, 1.0);
obs_data_set_default_double(settings, SETTING_CONTRAST, 0.0);
obs_data_set_default_double(settings, SETTING_BRIGHTNESS, 0.0);
obs_data_set_default_double(settings, SETTING_GAMMA, 0.0);
obs_data_set_default_int(settings, SETTING_KEY_COLOR, 0x00FF00);
obs_data_set_default_string(settings, SETTING_COLOR_TYPE, "green");
obs_data_set_default_int(settings, SETTING_SIMILARITY, 400);
obs_data_set_default_int(settings, SETTING_SMOOTHNESS, 80);
obs_data_set_default_int(settings, SETTING_SPILL, 100);
}
struct obs_source_info chroma_key_filter = {
.id = "chroma_key_filter",
.type = OBS_SOURCE_TYPE_FILTER,
@ -502,7 +519,7 @@ struct obs_source_info chroma_key_filter = {
.video_render = chroma_key_render_v1,
.update = chroma_key_update_v1,
.get_properties = chroma_key_properties_v1,
.get_defaults = chroma_key_defaults,
.get_defaults = chroma_key_defaults_v1,
};
struct obs_source_info chroma_key_filter_v2 = {
@ -516,5 +533,5 @@ struct obs_source_info chroma_key_filter_v2 = {
.video_render = chroma_key_render_v2,
.update = chroma_key_update_v2,
.get_properties = chroma_key_properties_v2,
.get_defaults = chroma_key_defaults,
.get_defaults = chroma_key_defaults_v2,
};

View File

@ -325,8 +325,7 @@ static void color_correction_filter_update_v2(void *data, obs_data_t *settings)
(float)obs_data_get_double(settings, SETTING_HUESHIFT);
/* Build our Transparency number. */
float opacity =
(float)obs_data_get_int(settings, SETTING_OPACITY) * 0.01f;
float opacity = (float)obs_data_get_double(settings, SETTING_OPACITY);
/* Hue is the radian of 0 to 360 degrees. */
float half_angle = 0.5f * (float)(hue_shift / (180.0f / M_PI));
@ -588,8 +587,13 @@ static void color_correction_filter_render_v1(void *data, gs_effect_t *effect)
gs_effect_set_matrix4(filter->final_matrix_param,
&filter->final_matrix);
gs_blend_state_push();
gs_blend_function(GS_BLEND_ONE, GS_BLEND_INVSRCALPHA);
obs_source_process_filter_end(filter->context, filter->effect, 0, 0);
gs_blend_state_pop();
UNUSED_PARAMETER(effect);
}
@ -606,9 +610,14 @@ static void color_correction_filter_render_v2(void *data, gs_effect_t *effect)
gs_effect_set_matrix4(filter->final_matrix_param,
&filter->final_matrix);
gs_blend_state_push();
gs_blend_function(GS_BLEND_ONE, GS_BLEND_INVSRCALPHA);
obs_source_process_filter_end_srgb(filter->context, filter->effect, 0,
0);
gs_blend_state_pop();
UNUSED_PARAMETER(effect);
}
@ -657,8 +666,8 @@ static obs_properties_t *color_correction_filter_properties_v2(void *data)
TEXT_SATURATION, -1.0, 5.0, 0.01);
obs_properties_add_float_slider(props, SETTING_HUESHIFT, TEXT_HUESHIFT,
-180.0, 180.0, 0.01);
obs_properties_add_int_slider(props, SETTING_OPACITY, TEXT_OPACITY, 0,
100, 1);
obs_properties_add_float_slider(props, SETTING_OPACITY, TEXT_OPACITY,
0.0, 1.0, 0.0001);
obs_properties_add_color(props, SETTING_COLOR_MULTIPLY,
TEXT_COLOR_MULTIPLY);
@ -693,7 +702,7 @@ static void color_correction_filter_defaults_v2(obs_data_t *settings)
obs_data_set_default_double(settings, SETTING_BRIGHTNESS, 0.0);
obs_data_set_default_double(settings, SETTING_SATURATION, 0.0);
obs_data_set_default_double(settings, SETTING_HUESHIFT, 0.0);
obs_data_set_default_int(settings, SETTING_OPACITY, 100);
obs_data_set_default_double(settings, SETTING_OPACITY, 1.0);
obs_data_set_default_int(settings, SETTING_COLOR_MULTIPLY, 0x00FFFFFF);
obs_data_set_default_int(settings, SETTING_COLOR_ADD, 0x00000000);
}

View File

@ -108,8 +108,7 @@ static inline void
color_settings_update_v2(struct color_key_filter_data_v2 *filter,
obs_data_t *settings)
{
filter->opacity =
(float)obs_data_get_int(settings, SETTING_OPACITY) / 100.0f;
filter->opacity = (float)obs_data_get_double(settings, SETTING_OPACITY);
double contrast = obs_data_get_double(settings, SETTING_CONTRAST);
contrast = (contrast < 0.0) ? (1.0 / (-contrast + 1.0))
@ -336,9 +335,14 @@ static void color_key_render_v2(void *data, gs_effect_t *effect)
gs_effect_set_float(filter->similarity_param, filter->similarity);
gs_effect_set_float(filter->smoothness_param, filter->smoothness);
gs_blend_state_push();
gs_blend_function(GS_BLEND_ONE, GS_BLEND_INVSRCALPHA);
obs_source_process_filter_end_srgb(filter->context, filter->effect, 0,
0);
gs_blend_state_pop();
UNUSED_PARAMETER(effect);
}
@ -414,8 +418,8 @@ static obs_properties_t *color_key_properties_v2(void *data)
obs_properties_add_int_slider(props, SETTING_SMOOTHNESS,
TEXT_SMOOTHNESS, 1, 1000, 1);
obs_properties_add_int_slider(props, SETTING_OPACITY, TEXT_OPACITY, 0,
100, 1);
obs_properties_add_float_slider(props, SETTING_OPACITY, TEXT_OPACITY,
0.0, 1.0, 0.0001);
obs_properties_add_float_slider(props, SETTING_CONTRAST, TEXT_CONTRAST,
-4.0, 4.0, 0.01);
obs_properties_add_float_slider(props, SETTING_BRIGHTNESS,
@ -427,7 +431,7 @@ static obs_properties_t *color_key_properties_v2(void *data)
return props;
}
static void color_key_defaults(obs_data_t *settings)
static void color_key_defaults_v1(obs_data_t *settings)
{
obs_data_set_default_int(settings, SETTING_OPACITY, 100);
obs_data_set_default_double(settings, SETTING_CONTRAST, 0.0);
@ -439,6 +443,18 @@ static void color_key_defaults(obs_data_t *settings)
obs_data_set_default_int(settings, SETTING_SMOOTHNESS, 50);
}
static void color_key_defaults_v2(obs_data_t *settings)
{
obs_data_set_default_double(settings, SETTING_OPACITY, 1.0);
obs_data_set_default_double(settings, SETTING_CONTRAST, 0.0);
obs_data_set_default_double(settings, SETTING_BRIGHTNESS, 0.0);
obs_data_set_default_double(settings, SETTING_GAMMA, 0.0);
obs_data_set_default_int(settings, SETTING_KEY_COLOR, 0x00FF00);
obs_data_set_default_string(settings, SETTING_COLOR_TYPE, "green");
obs_data_set_default_int(settings, SETTING_SIMILARITY, 80);
obs_data_set_default_int(settings, SETTING_SMOOTHNESS, 50);
}
struct obs_source_info color_key_filter = {
.id = "color_key_filter",
.type = OBS_SOURCE_TYPE_FILTER,
@ -449,7 +465,7 @@ struct obs_source_info color_key_filter = {
.video_render = color_key_render_v1,
.update = color_key_update_v1,
.get_properties = color_key_properties_v1,
.get_defaults = color_key_defaults,
.get_defaults = color_key_defaults_v1,
};
struct obs_source_info color_key_filter_v2 = {
@ -463,5 +479,5 @@ struct obs_source_info color_key_filter_v2 = {
.video_render = color_key_render_v2,
.update = color_key_update_v2,
.get_properties = color_key_properties_v2,
.get_defaults = color_key_defaults,
.get_defaults = color_key_defaults_v2,
};

View File

@ -40,6 +40,7 @@ float4 PSAddImageRGBA(VertDataOut v_in) : TARGET
float3 targetRGB = target.Sample(textureSampler, v_in.uv2).rgb;
rgba.rgb = saturate(rgba.rgb + targetRGB);
rgba.rgb *= rgba.a;
return rgba;
}

View File

@ -40,6 +40,7 @@ float4 PSMuliplyImageRGBA(VertDataOut v_in) : TARGET
float3 targetRGB = target.Sample(textureSampler, v_in.uv2).rgb;
rgba.rgb = saturate(rgba.rgb * targetRGB);
rgba.rgb *= rgba.a;
return rgba;
}

View File

@ -40,6 +40,7 @@ float4 PSSubtractImageRGBA(VertDataOut v_in) : TARGET
float3 targetRGB = target.Sample(textureSampler, v_in.uv2).rgb;
rgba.rgb = saturate(rgba.rgb - targetRGB);
rgba.rgb *= rgba.a;
return rgba;
}

View File

@ -96,7 +96,9 @@ float4 PSChromaKeyRGBA(VertData v_in) : TARGET
{
float4 rgba = image.Sample(textureSampler, v_in.uv);
rgba.rgb = max(float3(0.0, 0.0, 0.0), rgba.rgb / rgba.a);
return ProcessChromaKey(rgba, v_in);
rgba = ProcessChromaKey(rgba, v_in);
rgba.rgb *= rgba.a;
return rgba;
}
technique Draw

View File

@ -59,6 +59,8 @@ float4 PSColorFilterRGBA(VertData vert_in) : TARGET
*/
currentPixel = mul(color_matrix, currentPixel);
currentPixel.rgb *= currentPixel.a;
return currentPixel;
}

View File

@ -52,7 +52,9 @@ float4 PSColorKeyRGBA(VertData v_in) : TARGET
float4 rgba = image.Sample(textureSampler, v_in.uv);
rgba.rgb = max(float3(0.0, 0.0, 0.0), rgba.rgb / rgba.a);
rgba.a *= opacity;
return ProcessColorKey(rgba, v_in);
rgba = ProcessColorKey(rgba, v_in);
rgba.rgb *= rgba.a;
return rgba;
}
technique Draw

View File

@ -40,6 +40,7 @@ float4 PSAlphaMaskRGBA(VertDataOut v_in) : TARGET
float4 targetRGB = target.Sample(textureSampler, v_in.uv2);
rgba.a *= targetRGB.a;
rgba.rgb *= rgba.a;
return rgba;
}

View File

@ -40,6 +40,7 @@ float4 PSColorMaskRGBA(VertDataOut v_in) : TARGET
float4 targetRGB = target.Sample(textureSampler, v_in.uv2);
rgba.a *= (targetRGB.r + targetRGB.g + targetRGB.b) / 3.0;
rgba.rgb *= rgba.a;
return rgba;
}

View File

@ -81,27 +81,25 @@ static void mask_filter_image_load(struct mask_filter_data *filter)
}
static void mask_filter_update_internal(void *data, obs_data_t *settings,
bool srgb)
float opacity, bool srgb)
{
struct mask_filter_data *filter = data;
const char *path = obs_data_get_string(settings, SETTING_IMAGE_PATH);
const char *effect_file = obs_data_get_string(settings, SETTING_TYPE);
uint32_t color = (uint32_t)obs_data_get_int(settings, SETTING_COLOR);
int opacity = (int)obs_data_get_int(settings, SETTING_OPACITY);
char *effect_path;
if (filter->image_file)
bfree(filter->image_file);
filter->image_file = bstrdup(path);
color &= 0xFFFFFF;
color |= (uint32_t)(((double)opacity) * 2.55) << 24;
if (srgb)
vec4_from_rgba_srgb(&filter->color, color);
else
vec4_from_rgba(&filter->color, color);
filter->color.w = opacity;
mask_filter_image_load(filter);
filter->lock_aspect = !obs_data_get_bool(settings, SETTING_STRETCH);
@ -117,15 +115,19 @@ static void mask_filter_update_internal(void *data, obs_data_t *settings,
static void mask_filter_update_v1(void *data, obs_data_t *settings)
{
mask_filter_update_internal(data, settings, false);
const float opacity =
(float)(obs_data_get_int(settings, SETTING_OPACITY) * 0.01);
mask_filter_update_internal(data, settings, opacity, false);
}
static void mask_filter_update_v2(void *data, obs_data_t *settings)
{
mask_filter_update_internal(data, settings, true);
const float opacity =
(float)obs_data_get_double(settings, SETTING_OPACITY);
mask_filter_update_internal(data, settings, opacity, true);
}
static void mask_filter_defaults(obs_data_t *settings)
static void mask_filter_defaults_v1(obs_data_t *settings)
{
obs_data_set_default_string(settings, SETTING_TYPE,
"mask_color_filter.effect");
@ -133,9 +135,17 @@ static void mask_filter_defaults(obs_data_t *settings)
obs_data_set_default_int(settings, SETTING_OPACITY, 100);
}
static void mask_filter_defaults_v2(obs_data_t *settings)
{
obs_data_set_default_string(settings, SETTING_TYPE,
"mask_color_filter.effect");
obs_data_set_default_int(settings, SETTING_COLOR, 0xFFFFFF);
obs_data_set_default_double(settings, SETTING_OPACITY, 1.0);
}
#define IMAGE_FILTER_EXTENSIONS " (*.bmp *.jpg *.jpeg *.tga *.gif *.png)"
static obs_properties_t *mask_filter_properties(void *data)
static obs_properties_t *mask_filter_properties_internal(bool use_float_opacity)
{
obs_properties_t *props = obs_properties_create();
struct dstr filter_str = {0};
@ -169,16 +179,34 @@ static obs_properties_t *mask_filter_properties(void *data)
obs_properties_add_path(props, SETTING_IMAGE_PATH, TEXT_IMAGE_PATH,
OBS_PATH_FILE, filter_str.array, NULL);
obs_properties_add_color(props, SETTING_COLOR, TEXT_COLOR);
obs_properties_add_int_slider(props, SETTING_OPACITY, TEXT_OPACITY, 0,
100, 1);
if (use_float_opacity) {
obs_properties_add_float_slider(props, SETTING_OPACITY,
TEXT_OPACITY, 0.0, 1.0, 0.0001);
} else {
obs_properties_add_int_slider(props, SETTING_OPACITY,
TEXT_OPACITY, 0, 100, 1);
}
obs_properties_add_bool(props, SETTING_STRETCH, TEXT_STRETCH);
dstr_free(&filter_str);
UNUSED_PARAMETER(data);
return props;
}
static obs_properties_t *mask_filter_properties_v1(void *data)
{
UNUSED_PARAMETER(data);
return mask_filter_properties_internal(false);
}
static obs_properties_t *mask_filter_properties_v2(void *data)
{
UNUSED_PARAMETER(data);
return mask_filter_properties_internal(true);
}
static void *mask_filter_create(obs_data_t *settings, obs_source_t *context)
{
struct mask_filter_data *filter =
@ -293,6 +321,9 @@ static void mask_filter_render_internal(void *data, bool srgb)
param = gs_effect_get_param_by_name(filter->effect, "add_val");
gs_effect_set_vec2(param, &add_val);
gs_blend_state_push();
gs_blend_function(GS_BLEND_ONE, GS_BLEND_INVSRCALPHA);
if (srgb) {
obs_source_process_filter_end_srgb(filter->context,
filter->effect, 0, 0);
@ -300,6 +331,8 @@ static void mask_filter_render_internal(void *data, bool srgb)
obs_source_process_filter_end(filter->context, filter->effect,
0, 0);
}
gs_blend_state_pop();
}
static void mask_filter_render_v1(void *data, gs_effect_t *effect)
@ -324,8 +357,8 @@ struct obs_source_info mask_filter = {
.create = mask_filter_create,
.destroy = mask_filter_destroy,
.update = mask_filter_update_v1,
.get_defaults = mask_filter_defaults,
.get_properties = mask_filter_properties,
.get_defaults = mask_filter_defaults_v1,
.get_properties = mask_filter_properties_v1,
.video_tick = mask_filter_tick,
.video_render = mask_filter_render_v1,
};
@ -339,8 +372,8 @@ struct obs_source_info mask_filter_v2 = {
.create = mask_filter_create,
.destroy = mask_filter_destroy,
.update = mask_filter_update_v2,
.get_defaults = mask_filter_defaults,
.get_properties = mask_filter_properties,
.get_defaults = mask_filter_defaults_v2,
.get_properties = mask_filter_properties_v2,
.video_tick = mask_filter_tick,
.video_render = mask_filter_render_v2,
};