Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOmar Emara <mail@OmarEmara.dev>2022-08-10 11:21:18 +0300
committerOmar Emara <mail@OmarEmara.dev>2022-08-10 11:21:18 +0300
commitc014021802c323c3ed55c3c283717975a3d93edf (patch)
treea2537ce8187e6acff56b3936d994ab73447b3ad0 /source/blender/gpu/shaders
parentb5df7a02ac754de8e04fdeda4d1c3f0fcdf6a7a2 (diff)
Realtime Compositor: Add basic matte nodes
This patch implements the following nodes for the realtime compositor: - Box mask node. - Channel matte node. - Chroma matte node. - Color matte node. - Color spill node. - Difference matte node. - Distance matte node. - Ellipse matte node. - Luminance matte node. Differential Revision: https://developer.blender.org/D15230 Reviewed By: Clement Foucault
Diffstat (limited to 'source/blender/gpu/shaders')
-rw-r--r--source/blender/gpu/shaders/common/gpu_shader_common_math_utils.glsl9
-rw-r--r--source/blender/gpu/shaders/compositor/compositor_box_mask.glsl27
-rw-r--r--source/blender/gpu/shaders/compositor/compositor_ellipse_mask.glsl27
-rw-r--r--source/blender/gpu/shaders/compositor/infos/compositor_box_mask_info.hh35
-rw-r--r--source/blender/gpu/shaders/compositor/infos/compositor_ellipse_mask_info.hh35
-rw-r--r--source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_channel_matte.glsl52
-rw-r--r--source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_chroma_matte.glsl43
-rw-r--r--source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_color_matte.glsl27
-rw-r--r--source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_color_spill.glsl13
-rw-r--r--source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_difference_matte.glsl10
-rw-r--r--source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_distance_matte.glsl26
-rw-r--r--source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_luminance_matte.glsl14
12 files changed, 318 insertions, 0 deletions
diff --git a/source/blender/gpu/shaders/common/gpu_shader_common_math_utils.glsl b/source/blender/gpu/shaders/common/gpu_shader_common_math_utils.glsl
index a28705f158d..1ba22b4c5da 100644
--- a/source/blender/gpu/shaders/common/gpu_shader_common_math_utils.glsl
+++ b/source/blender/gpu/shaders/common/gpu_shader_common_math_utils.glsl
@@ -134,6 +134,15 @@ vec3 fallback_pow(vec3 a, float b, vec3 fallback)
/* Matirx Math */
+/* Return a 2D rotation matrix with the angle that the input 2D vector makes with the x axis. */
+mat2 vector_to_rotation_matrix(vec2 vector)
+{
+ vec2 normalized_vector = normalize(vector);
+ float cos_angle = normalized_vector.x;
+ float sin_angle = normalized_vector.y;
+ return mat2(cos_angle, sin_angle, -sin_angle, cos_angle);
+}
+
mat3 euler_to_mat3(vec3 euler)
{
float cx = cos(euler.x);
diff --git a/source/blender/gpu/shaders/compositor/compositor_box_mask.glsl b/source/blender/gpu/shaders/compositor/compositor_box_mask.glsl
new file mode 100644
index 00000000000..fad23f28fde
--- /dev/null
+++ b/source/blender/gpu/shaders/compositor/compositor_box_mask.glsl
@@ -0,0 +1,27 @@
+#pragma BLENDER_REQUIRE(gpu_shader_compositor_texture_utilities.glsl)
+
+void main()
+{
+ ivec2 texel = ivec2(gl_GlobalInvocationID.xy);
+
+ vec2 uv = vec2(texel) / vec2(domain_size - ivec2(1));
+ uv -= location;
+ uv.y *= float(domain_size.y) / float(domain_size.x);
+ uv = mat2(cos_angle, -sin_angle, sin_angle, cos_angle) * uv;
+ bool is_inside = all(lessThan(abs(uv), size));
+
+ float base_mask_value = texture_load(base_mask_tx, texel).x;
+ float value = texture_load(mask_value_tx, texel).x;
+
+#if defined(CMP_NODE_MASKTYPE_ADD)
+ float output_mask_value = is_inside ? max(base_mask_value, value) : base_mask_value;
+#elif defined(CMP_NODE_MASKTYPE_SUBTRACT)
+ float output_mask_value = is_inside ? clamp(base_mask_value - value, 0.0, 1.0) : base_mask_value;
+#elif defined(CMP_NODE_MASKTYPE_MULTIPLY)
+ float output_mask_value = is_inside ? base_mask_value * value : 0.0;
+#elif defined(CMP_NODE_MASKTYPE_NOT)
+ float output_mask_value = is_inside ? (base_mask_value > 0.0 ? 0.0 : value) : base_mask_value;
+#endif
+
+ imageStore(output_mask_img, texel, vec4(output_mask_value));
+}
diff --git a/source/blender/gpu/shaders/compositor/compositor_ellipse_mask.glsl b/source/blender/gpu/shaders/compositor/compositor_ellipse_mask.glsl
new file mode 100644
index 00000000000..28f725067e0
--- /dev/null
+++ b/source/blender/gpu/shaders/compositor/compositor_ellipse_mask.glsl
@@ -0,0 +1,27 @@
+#pragma BLENDER_REQUIRE(gpu_shader_compositor_texture_utilities.glsl)
+
+void main()
+{
+ ivec2 texel = ivec2(gl_GlobalInvocationID.xy);
+
+ vec2 uv = vec2(texel) / vec2(domain_size - ivec2(1));
+ uv -= location;
+ uv.y *= float(domain_size.y) / float(domain_size.x);
+ uv = mat2(cos_angle, -sin_angle, sin_angle, cos_angle) * uv;
+ bool is_inside = length(uv / radius) < 1.0;
+
+ float base_mask_value = texture_load(base_mask_tx, texel).x;
+ float value = texture_load(mask_value_tx, texel).x;
+
+#if defined(CMP_NODE_MASKTYPE_ADD)
+ float output_mask_value = is_inside ? max(base_mask_value, value) : base_mask_value;
+#elif defined(CMP_NODE_MASKTYPE_SUBTRACT)
+ float output_mask_value = is_inside ? clamp(base_mask_value - value, 0.0, 1.0) : base_mask_value;
+#elif defined(CMP_NODE_MASKTYPE_MULTIPLY)
+ float output_mask_value = is_inside ? base_mask_value * value : 0.0;
+#elif defined(CMP_NODE_MASKTYPE_NOT)
+ float output_mask_value = is_inside ? (base_mask_value > 0.0 ? 0.0 : value) : base_mask_value;
+#endif
+
+ imageStore(output_mask_img, texel, vec4(output_mask_value));
+}
diff --git a/source/blender/gpu/shaders/compositor/infos/compositor_box_mask_info.hh b/source/blender/gpu/shaders/compositor/infos/compositor_box_mask_info.hh
new file mode 100644
index 00000000000..ecb253bbab1
--- /dev/null
+++ b/source/blender/gpu/shaders/compositor/infos/compositor_box_mask_info.hh
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(compositor_box_mask_shared)
+ .local_group_size(16, 16)
+ .push_constant(Type::IVEC2, "domain_size")
+ .push_constant(Type::VEC2, "location")
+ .push_constant(Type::VEC2, "size")
+ .push_constant(Type::FLOAT, "cos_angle")
+ .push_constant(Type::FLOAT, "sin_angle")
+ .sampler(0, ImageType::FLOAT_2D, "base_mask_tx")
+ .sampler(1, ImageType::FLOAT_2D, "mask_value_tx")
+ .image(0, GPU_R16F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_mask_img")
+ .compute_source("compositor_box_mask.glsl");
+
+GPU_SHADER_CREATE_INFO(compositor_box_mask_add)
+ .additional_info("compositor_box_mask_shared")
+ .define("CMP_NODE_MASKTYPE_ADD")
+ .do_static_compilation(true);
+
+GPU_SHADER_CREATE_INFO(compositor_box_mask_subtract)
+ .additional_info("compositor_box_mask_shared")
+ .define("CMP_NODE_MASKTYPE_SUBTRACT")
+ .do_static_compilation(true);
+
+GPU_SHADER_CREATE_INFO(compositor_box_mask_multiply)
+ .additional_info("compositor_box_mask_shared")
+ .define("CMP_NODE_MASKTYPE_MULTIPLY")
+ .do_static_compilation(true);
+
+GPU_SHADER_CREATE_INFO(compositor_box_mask_not)
+ .additional_info("compositor_box_mask_shared")
+ .define("CMP_NODE_MASKTYPE_NOT")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/compositor/infos/compositor_ellipse_mask_info.hh b/source/blender/gpu/shaders/compositor/infos/compositor_ellipse_mask_info.hh
new file mode 100644
index 00000000000..52db91c94e5
--- /dev/null
+++ b/source/blender/gpu/shaders/compositor/infos/compositor_ellipse_mask_info.hh
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(compositor_ellipse_mask_shared)
+ .local_group_size(16, 16)
+ .push_constant(Type::IVEC2, "domain_size")
+ .push_constant(Type::VEC2, "location")
+ .push_constant(Type::VEC2, "radius")
+ .push_constant(Type::FLOAT, "cos_angle")
+ .push_constant(Type::FLOAT, "sin_angle")
+ .sampler(0, ImageType::FLOAT_2D, "base_mask_tx")
+ .sampler(1, ImageType::FLOAT_2D, "mask_value_tx")
+ .image(0, GPU_R16F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_mask_img")
+ .compute_source("compositor_ellipse_mask.glsl");
+
+GPU_SHADER_CREATE_INFO(compositor_ellipse_mask_add)
+ .additional_info("compositor_ellipse_mask_shared")
+ .define("CMP_NODE_MASKTYPE_ADD")
+ .do_static_compilation(true);
+
+GPU_SHADER_CREATE_INFO(compositor_ellipse_mask_subtract)
+ .additional_info("compositor_ellipse_mask_shared")
+ .define("CMP_NODE_MASKTYPE_SUBTRACT")
+ .do_static_compilation(true);
+
+GPU_SHADER_CREATE_INFO(compositor_ellipse_mask_multiply)
+ .additional_info("compositor_ellipse_mask_shared")
+ .define("CMP_NODE_MASKTYPE_MULTIPLY")
+ .do_static_compilation(true);
+
+GPU_SHADER_CREATE_INFO(compositor_ellipse_mask_not)
+ .additional_info("compositor_ellipse_mask_shared")
+ .define("CMP_NODE_MASKTYPE_NOT")
+ .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_channel_matte.glsl b/source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_channel_matte.glsl
new file mode 100644
index 00000000000..f2dcc9543f2
--- /dev/null
+++ b/source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_channel_matte.glsl
@@ -0,0 +1,52 @@
+#pragma BLENDER_REQUIRE(gpu_shader_common_color_utils.glsl)
+
+#define CMP_NODE_CHANNEL_MATTE_CS_RGB 1.0
+#define CMP_NODE_CHANNEL_MATTE_CS_HSV 2.0
+#define CMP_NODE_CHANNEL_MATTE_CS_YUV 3.0
+#define CMP_NODE_CHANNEL_MATTE_CS_YCC 4.0
+
+void node_composite_channel_matte(vec4 color,
+ const float color_space,
+ const float matte_channel,
+ const vec2 limit_channels,
+ float max_limit,
+ float min_limit,
+ out vec4 result,
+ out float matte)
+{
+ vec4 channels;
+ if (color_space == CMP_NODE_CHANNEL_MATTE_CS_HSV) {
+ rgb_to_hsv(color, channels);
+ }
+ else if (color_space == CMP_NODE_CHANNEL_MATTE_CS_YUV) {
+ rgba_to_yuva_itu_709(color, channels);
+ }
+ else if (color_space == CMP_NODE_CHANNEL_MATTE_CS_YCC) {
+ rgba_to_ycca_itu_709(color, channels);
+ }
+ else {
+ channels = color;
+ }
+
+ float matte_value = channels[int(matte_channel)];
+ float limit_value = max(channels[int(limit_channels.x)], channels[int(limit_channels.y)]);
+
+ float alpha = 1.0 - (matte_value - limit_value);
+ if (alpha > max_limit) {
+ alpha = color.a;
+ }
+ else if (alpha < min_limit) {
+ alpha = 0.0;
+ }
+ else {
+ alpha = (alpha - min_limit) / (max_limit - min_limit);
+ }
+
+ matte = min(alpha, color.a);
+ result = color * matte;
+}
+
+#undef CMP_NODE_CHANNEL_MATTE_CS_RGB
+#undef CMP_NODE_CHANNEL_MATTE_CS_HSV
+#undef CMP_NODE_CHANNEL_MATTE_CS_YUV
+#undef CMP_NODE_CHANNEL_MATTE_CS_YCC
diff --git a/source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_chroma_matte.glsl b/source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_chroma_matte.glsl
new file mode 100644
index 00000000000..5d6bea0c9db
--- /dev/null
+++ b/source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_chroma_matte.glsl
@@ -0,0 +1,43 @@
+#pragma BLENDER_REQUIRE(gpu_shader_common_math_utils.glsl)
+#pragma BLENDER_REQUIRE(gpu_shader_common_color_utils.glsl)
+
+/* Algorithm from the book Video Demystified. Chapter 7. Chroma Keying. */
+void node_composite_chroma_matte(vec4 color,
+ vec4 key,
+ float acceptance,
+ float cutoff,
+ float falloff,
+ out vec4 result,
+ out float matte)
+{
+ vec4 color_ycca;
+ rgba_to_ycca_itu_709(color, color_ycca);
+ vec4 key_ycca;
+ rgba_to_ycca_itu_709(key, key_ycca);
+
+ /* Normalize the CrCb components into the [-1, 1] range. */
+ vec2 color_cc = color_ycca.yz * 2.0 - 1.0;
+ vec2 key_cc = key_ycca.yz * 2.0 - 1.0;
+
+ /* Rotate the color onto the space of the key such that x axis of the color space passes through
+ * the key color. */
+ color_cc = vector_to_rotation_matrix(key_cc * vec2(1.0, -1.0)) * color_cc;
+
+ /* Compute foreground key. If positive, the value is in the [0, 1] range. */
+ float foreground_key = color_cc.x - (abs(color_cc.y) / acceptance);
+
+ /* Negative foreground key values retain the original alpha. Positive values are scaled by the
+ * falloff, while colors that make an angle less than the cutoff angle get a zero alpha. */
+ float alpha = color.a;
+ if (foreground_key > 0.0) {
+ alpha = 1.0 - (foreground_key / falloff);
+
+ if (abs(atan(color_cc.y, color_cc.x)) < (cutoff / 2.0)) {
+ alpha = 0.0;
+ }
+ }
+
+ /* Compute output. */
+ matte = min(alpha, color.a);
+ result = color * matte;
+}
diff --git a/source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_color_matte.glsl b/source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_color_matte.glsl
new file mode 100644
index 00000000000..038471bc1bc
--- /dev/null
+++ b/source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_color_matte.glsl
@@ -0,0 +1,27 @@
+#pragma BLENDER_REQUIRE(gpu_shader_common_color_utils.glsl)
+
+void node_composite_color_matte(vec4 color,
+ vec4 key,
+ float hue_epsilon,
+ float saturation_epsilon,
+ float value_epsilon,
+ out vec4 result,
+ out float matte)
+
+{
+ vec4 color_hsva;
+ rgb_to_hsv(color, color_hsva);
+ vec4 key_hsva;
+ rgb_to_hsv(key, key_hsva);
+
+ bool is_within_saturation = distance(color_hsva.y, key_hsva.y) < saturation_epsilon;
+ bool is_within_value = distance(color_hsva.z, key_hsva.z) < value_epsilon;
+ bool is_within_hue = distance(color_hsva.x, key_hsva.x) < hue_epsilon;
+ /* Hue wraps around, so check the distance around the boundary. */
+ float min_hue = min(color_hsva.x, key_hsva.x);
+ float max_hue = max(color_hsva.x, key_hsva.x);
+ is_within_hue = is_within_hue || ((min_hue + (1.0 - max_hue)) < hue_epsilon);
+
+ matte = (is_within_hue && is_within_saturation && is_within_value) ? 0.0 : color.a;
+ result = color * matte;
+}
diff --git a/source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_color_spill.glsl b/source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_color_spill.glsl
new file mode 100644
index 00000000000..0adad53ad80
--- /dev/null
+++ b/source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_color_spill.glsl
@@ -0,0 +1,13 @@
+void node_composite_color_spill(vec4 color,
+ float factor,
+ const float spill_channel,
+ vec3 spill_scale,
+ const vec2 limit_channels,
+ float limit_scale,
+ out vec4 result)
+{
+ float average_limit = (color[int(limit_channels.x)] + color[int(limit_channels.y)]) / 2.0;
+ float map = factor * color[int(spill_channel)] - limit_scale * average_limit;
+ result.rgb = map > 0.0 ? color.rgb + spill_scale * map : color.rgb;
+ result.a = color.a;
+}
diff --git a/source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_difference_matte.glsl b/source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_difference_matte.glsl
new file mode 100644
index 00000000000..d769cadce3c
--- /dev/null
+++ b/source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_difference_matte.glsl
@@ -0,0 +1,10 @@
+void node_composite_difference_matte(
+ vec4 color, vec4 key, float tolerance, float falloff, out vec4 result, out float matte)
+{
+ vec4 difference = abs(color - key);
+ float average_difference = (difference.r + difference.g + difference.b) / 3.0;
+ bool is_opaque = average_difference > tolerance + falloff;
+ float alpha = is_opaque ? color.a : (max(0.0, average_difference - tolerance) / falloff);
+ matte = min(alpha, color.a);
+ result = color * matte;
+}
diff --git a/source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_distance_matte.glsl b/source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_distance_matte.glsl
new file mode 100644
index 00000000000..9beed66826c
--- /dev/null
+++ b/source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_distance_matte.glsl
@@ -0,0 +1,26 @@
+#pragma BLENDER_REQUIRE(gpu_shader_common_color_utils.glsl)
+
+void node_composite_distance_matte_rgba(
+ vec4 color, vec4 key, float tolerance, float falloff, out vec4 result, out float matte)
+{
+ float difference = distance(color.rgb, key.rgb);
+ bool is_opaque = difference > tolerance + falloff;
+ float alpha = is_opaque ? color.a : max(0.0, difference - tolerance) / falloff;
+ matte = min(alpha, color.a);
+ result = color * matte;
+}
+
+void node_composite_distance_matte_ycca(
+ vec4 color, vec4 key, float tolerance, float falloff, out vec4 result, out float matte)
+{
+ vec4 color_ycca;
+ rgba_to_ycca_itu_709(color, color_ycca);
+ vec4 key_ycca;
+ rgba_to_ycca_itu_709(key, key_ycca);
+
+ float difference = distance(color_ycca.yz, key_ycca.yz);
+ bool is_opaque = difference > tolerance + falloff;
+ float alpha = is_opaque ? color.a : max(0.0, difference - tolerance) / falloff;
+ matte = min(alpha, color.a);
+ result = color * matte;
+}
diff --git a/source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_luminance_matte.glsl b/source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_luminance_matte.glsl
new file mode 100644
index 00000000000..3647ac583fe
--- /dev/null
+++ b/source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_luminance_matte.glsl
@@ -0,0 +1,14 @@
+#pragma BLENDER_REQUIRE(gpu_shader_common_color_utils.glsl)
+
+void node_composite_luminance_matte(vec4 color,
+ float high,
+ float low,
+ const vec3 luminance_coefficients,
+ out vec4 result,
+ out float matte)
+{
+ float luminance = get_luminance(color.rgb, luminance_coefficients);
+ float alpha = clamp(0.0, 1.0, (luminance - low) / (high - low));
+ matte = min(alpha, color.a);
+ result = color * matte;
+}