Browse Source

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.
jpark37 4 years ago
parent
commit
e55bfa8e20

+ 24 - 7
plugins/obs-filters/chroma-key-filter.c

@@ -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,
 };

+ 14 - 5
plugins/obs-filters/color-correction-filter.c

@@ -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);
 }

+ 23 - 7
plugins/obs-filters/color-key-filter.c

@@ -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,
 };

+ 1 - 0
plugins/obs-filters/data/blend_add_filter.effect

@@ -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;
 }
 

+ 1 - 0
plugins/obs-filters/data/blend_mul_filter.effect

@@ -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;
 }
 

+ 1 - 0
plugins/obs-filters/data/blend_sub_filter.effect

@@ -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;
 }
 

+ 3 - 1
plugins/obs-filters/data/chroma_key_filter_v2.effect

@@ -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

+ 2 - 0
plugins/obs-filters/data/color_correction_filter.effect

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

+ 3 - 1
plugins/obs-filters/data/color_key_filter_v2.effect

@@ -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

+ 1 - 0
plugins/obs-filters/data/mask_alpha_filter.effect

@@ -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;
 }
 

+ 1 - 0
plugins/obs-filters/data/mask_color_filter.effect

@@ -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;
 }
 

+ 49 - 16
plugins/obs-filters/mask-filter.c

@@ -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,
 };