[Bf-blender-cvs] [b828d453e93] master: Realtime Compositor: Implement filter node

Omar Emara noreply at git.blender.org
Thu Aug 18 12:01:06 CEST 2022


Commit: b828d453e93c30e81d3cb0d5aa3edc553ea9a333
Author: Omar Emara
Date:   Thu Aug 18 12:00:14 2022 +0200
Branches: master
https://developer.blender.org/rBb828d453e93c30e81d3cb0d5aa3edc553ea9a333

Realtime Compositor: Implement filter node

This patch implements the filter node for the realtime compositor.

Differential Revision: https://developer.blender.org/D15661

Reviewed By: Clement Foucault

===================================================================

M	source/blender/gpu/CMakeLists.txt
A	source/blender/gpu/shaders/compositor/compositor_edge_filter.glsl
A	source/blender/gpu/shaders/compositor/compositor_filter.glsl
A	source/blender/gpu/shaders/compositor/infos/compositor_edge_filter_info.hh
A	source/blender/gpu/shaders/compositor/infos/compositor_filter_info.hh
M	source/blender/nodes/composite/nodes/node_composite_filter.cc

===================================================================

diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index bbc27a26835..33a0ccec24b 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -318,7 +318,9 @@ set(GLSL_SRC
   shaders/compositor/compositor_bokeh_image.glsl
   shaders/compositor/compositor_box_mask.glsl
   shaders/compositor/compositor_convert.glsl
+  shaders/compositor/compositor_edge_filter.glsl
   shaders/compositor/compositor_ellipse_mask.glsl
+  shaders/compositor/compositor_filter.glsl
   shaders/compositor/compositor_flip.glsl
   shaders/compositor/compositor_image_crop.glsl
   shaders/compositor/compositor_projector_lens_distortion.glsl
@@ -565,7 +567,9 @@ set(SRC_SHADER_CREATE_INFOS
   shaders/compositor/infos/compositor_bokeh_image_info.hh
   shaders/compositor/infos/compositor_box_mask_info.hh
   shaders/compositor/infos/compositor_convert_info.hh
+  shaders/compositor/infos/compositor_edge_filter_info.hh
   shaders/compositor/infos/compositor_ellipse_mask_info.hh
+  shaders/compositor/infos/compositor_filter_info.hh
   shaders/compositor/infos/compositor_flip_info.hh
   shaders/compositor/infos/compositor_image_crop_info.hh
   shaders/compositor/infos/compositor_projector_lens_distortion_info.hh
diff --git a/source/blender/gpu/shaders/compositor/compositor_edge_filter.glsl b/source/blender/gpu/shaders/compositor/compositor_edge_filter.glsl
new file mode 100644
index 00000000000..67e27c22602
--- /dev/null
+++ b/source/blender/gpu/shaders/compositor/compositor_edge_filter.glsl
@@ -0,0 +1,31 @@
+#pragma BLENDER_REQUIRE(gpu_shader_compositor_texture_utilities.glsl)
+
+void main()
+{
+  ivec2 texel = ivec2(gl_GlobalInvocationID.xy);
+
+  /* Compute the dot product between the 3x3 window around the pixel and the edge detection kernel
+   * in the X direction and Y direction. The Y direction kernel is computed by transposing the
+   * given X direction kernel. */
+  vec3 color_x = vec3(0);
+  vec3 color_y = vec3(0);
+  for (int j = 0; j < 3; j++) {
+    for (int i = 0; i < 3; i++) {
+      vec3 color = texture_load(input_tx, texel + ivec2(i - 1, j - 1)).rgb;
+      color_x += color * kernel[j][i];
+      color_y += color * kernel[i][j];
+    }
+  }
+
+  /* Compute the channel-wise magnitude of the 2D vector composed from the X and Y edge detection
+   * filter results. */
+  vec3 magnitude = sqrt(color_x * color_x + color_y * color_y);
+
+  /* Mix the channel-wise magnitude with the original color at the center of the kernel using the
+   * input factor. */
+  vec4 color = texture_load(input_tx, texel);
+  magnitude = mix(color.rgb, magnitude, texture_load(factor_tx, texel).x);
+
+  /* Store the channel-wise magnitude with the original alpha of the input. */
+  imageStore(output_img, texel, vec4(magnitude, color.a));
+}
diff --git a/source/blender/gpu/shaders/compositor/compositor_filter.glsl b/source/blender/gpu/shaders/compositor/compositor_filter.glsl
new file mode 100644
index 00000000000..e501c563dda
--- /dev/null
+++ b/source/blender/gpu/shaders/compositor/compositor_filter.glsl
@@ -0,0 +1,20 @@
+#pragma BLENDER_REQUIRE(gpu_shader_compositor_texture_utilities.glsl)
+
+void main()
+{
+  ivec2 texel = ivec2(gl_GlobalInvocationID.xy);
+
+  /* Compute the dot product between the 3x3 window around the pixel and the filter kernel. */
+  vec4 color = vec4(0);
+  for (int j = 0; j < 3; j++) {
+    for (int i = 0; i < 3; i++) {
+      color += texture_load(input_tx, texel + ivec2(i - 1, j - 1)) * kernel[j][i];
+    }
+  }
+
+  /* Mix with the original color at the center of the kernel using the input factor. */
+  color = mix(texture_load(input_tx, texel), color, texture_load(factor_tx, texel).x);
+
+  /* Store the color making sure it is not negative. */
+  imageStore(output_img, texel, max(color, 0.0));
+}
diff --git a/source/blender/gpu/shaders/compositor/infos/compositor_edge_filter_info.hh b/source/blender/gpu/shaders/compositor/infos/compositor_edge_filter_info.hh
new file mode 100644
index 00000000000..916ec62bdba
--- /dev/null
+++ b/source/blender/gpu/shaders/compositor/infos/compositor_edge_filter_info.hh
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(compositor_edge_filter)
+    .local_group_size(16, 16)
+    .push_constant(Type::MAT4, "kernel")
+    .sampler(0, ImageType::FLOAT_2D, "input_tx")
+    .sampler(1, ImageType::FLOAT_2D, "factor_tx")
+    .image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img")
+    .compute_source("compositor_edge_filter.glsl")
+    .do_static_compilation(true);
diff --git a/source/blender/gpu/shaders/compositor/infos/compositor_filter_info.hh b/source/blender/gpu/shaders/compositor/infos/compositor_filter_info.hh
new file mode 100644
index 00000000000..9d565cf4b8a
--- /dev/null
+++ b/source/blender/gpu/shaders/compositor/infos/compositor_filter_info.hh
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(compositor_filter)
+    .local_group_size(16, 16)
+    .push_constant(Type::MAT4, "kernel")
+    .sampler(0, ImageType::FLOAT_2D, "input_tx")
+    .sampler(1, ImageType::FLOAT_2D, "factor_tx")
+    .image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img")
+    .compute_source("compositor_filter.glsl")
+    .do_static_compilation(true);
diff --git a/source/blender/nodes/composite/nodes/node_composite_filter.cc b/source/blender/nodes/composite/nodes/node_composite_filter.cc
index 854cf684806..c071becac54 100644
--- a/source/blender/nodes/composite/nodes/node_composite_filter.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_filter.cc
@@ -5,6 +5,8 @@
  * \ingroup cmpnodes
  */
 
+#include "BLI_float3x3.hh"
+
 #include "UI_interface.h"
 #include "UI_resources.h"
 
@@ -36,7 +38,103 @@ class FilterOperation : public NodeOperation {
 
   void execute() override
   {
-    get_input("Image").pass_through(get_result("Image"));
+    GPUShader *shader = shader_manager().get(get_shader_name());
+    GPU_shader_bind(shader);
+
+    GPU_shader_uniform_mat3_as_mat4(shader, "kernel", get_filter_kernel().ptr());
+
+    const Result &input_image = get_input("Image");
+    input_image.bind_as_texture(shader, "input_tx");
+
+    const Result &factor = get_input("Fac");
+    factor.bind_as_texture(shader, "factor_tx");
+
+    const Domain domain = compute_domain();
+
+    Result &output_image = get_result("Image");
+    output_image.allocate_texture(domain);
+    output_image.bind_as_image(shader, "output_img");
+
+    compute_dispatch_threads_at_least(shader, domain.size);
+
+    input_image.unbind_as_texture();
+    factor.unbind_as_texture();
+    output_image.unbind_as_image();
+    GPU_shader_unbind();
+  }
+
+  int get_filter_method()
+  {
+    return bnode().custom1;
+  }
+
+  float3x3 get_filter_kernel()
+  {
+    /* Initialize the kernels as arrays of rows with the top row first. Edge detection kernels
+     * return the kernel in the X direction, while the kernel in the Y direction will be computed
+     * inside the shader by transposing the kernel in the X direction. */
+    switch (get_filter_method()) {
+      case CMP_FILT_SOFT: {
+        const float kernel[3][3] = {{1.0f / 16.0f, 2.0f / 16.0f, 1.0f / 16.0f},
+                                    {2.0f / 16.0f, 4.0f / 16.0f, 2.0f / 16.0f},
+                                    {1.0f / 16.0f, 2.0f / 16.0f, 1.0f / 16.0f}};
+        return float3x3(kernel);
+      }
+      case CMP_FILT_SHARP_BOX: {
+        const float kernel[3][3] = {
+            {-1.0f, -1.0f, -1.0f}, {-1.0f, 9.0f, -1.0f}, {-1.0f, -1.0f, -1.0f}};
+        return float3x3(kernel);
+      }
+      case CMP_FILT_LAPLACE: {
+        const float kernel[3][3] = {{-1.0f / 8.0f, -1.0f / 8.0f, -1.0f / 8.0f},
+                                    {-1.0f / 8.0f, 1.0f, -1.0f / 8.0f},
+                                    {-1.0f / 8.0f, -1.0f / 8.0f, -1.0f / 8.0f}};
+        return float3x3(kernel);
+      }
+      case CMP_FILT_SOBEL: {
+        const float kernel[3][3] = {{1.0f, 0.0f, -1.0f}, {2.0f, 0.0f, -2.0f}, {1.0f, 0.0f, -1.0f}};
+        return float3x3(kernel);
+      }
+      case CMP_FILT_PREWITT: {
+        const float kernel[3][3] = {{1.0f, 0.0f, -1.0f}, {1.0f, 0.0f, -1.0f}, {1.0f, 0.0f, -1.0f}};
+        return float3x3(kernel);
+      }
+      case CMP_FILT_KIRSCH: {
+        const float kernel[3][3] = {
+            {5.0f, -3.0f, -2.0f}, {5.0f, -3.0f, -2.0f}, {5.0f, -3.0f, -2.0f}};
+        return float3x3(kernel);
+      }
+      case CMP_FILT_SHADOW: {
+        const float kernel[3][3] = {{1.0f, 2.0f, 1.0f}, {0.0f, 1.0f, 0.0f}, {-1.0f, -2.0f, -1.0f}};
+        return float3x3(kernel);
+      }
+      case CMP_FILT_SHARP_DIAMOND: {
+        const float kernel[3][3] = {
+            {0.0f, -1.0f, 0.0f}, {-1.0f, 5.0f, -1.0f}, {0.0f, -1.0f, 0.0f}};
+        return float3x3(kernel);
+      }
+      default: {
+        const float kernel[3][3] = {{0.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f}, {0.0f, 0.0f, 0.0f}};
+        return float3x3(kernel);
+      }
+    }
+  }
+
+  const char *get_shader_name()
+  {
+    switch (get_filter_method()) {
+      case CMP_FILT_LAPLACE:
+      case CMP_FILT_SOBEL:
+      case CMP_FILT_PREWITT:
+      case CMP_FILT_KIRSCH:
+        return "compositor_edge_filter";
+      case CMP_FILT_SOFT:
+      case CMP_FILT_SHARP_BOX:
+      case CMP_FILT_SHADOW:
+      case CMP_FILT_SHARP_DIAMOND:
+      default:
+        return "compositor_filter";
+    }
   }
 };



More information about the Bf-blender-cvs mailing list