[Bf-blender-cvs] [633117669bc] master: Realtime Compositor: Implement dilate erode node

Omar Emara noreply at git.blender.org
Fri Sep 2 14:48:40 CEST 2022


Commit: 633117669bcec0f5320cb88443d12b6661bc4886
Author: Omar Emara
Date:   Fri Sep 2 14:47:39 2022 +0200
Branches: master
https://developer.blender.org/rB633117669bcec0f5320cb88443d12b6661bc4886

Realtime Compositor: Implement dilate erode node

This patch implements the dilate/erode node for the realtime compositor.

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

Reviewed By: Clement Foucault

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

M	source/blender/compositor/nodes/COM_DilateErodeNode.cc
M	source/blender/draw/intern/shaders/common_math_lib.glsl
M	source/blender/gpu/CMakeLists.txt
A	source/blender/gpu/shaders/compositor/compositor_morphological_distance.glsl
A	source/blender/gpu/shaders/compositor/compositor_morphological_distance_feather.glsl
A	source/blender/gpu/shaders/compositor/compositor_morphological_distance_threshold.glsl
A	source/blender/gpu/shaders/compositor/compositor_morphological_step.glsl
A	source/blender/gpu/shaders/compositor/infos/compositor_morphological_distance_feather_info.hh
A	source/blender/gpu/shaders/compositor/infos/compositor_morphological_distance_info.hh
A	source/blender/gpu/shaders/compositor/infos/compositor_morphological_distance_threshold_info.hh
A	source/blender/gpu/shaders/compositor/infos/compositor_morphological_step_info.hh
M	source/blender/gpu/shaders/compositor/library/gpu_shader_compositor_texture_utilities.glsl
M	source/blender/makesdna/DNA_node_types.h
M	source/blender/makesrna/intern/rna_nodetree.c
M	source/blender/nodes/composite/nodes/node_composite_dilate.cc

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

diff --git a/source/blender/compositor/nodes/COM_DilateErodeNode.cc b/source/blender/compositor/nodes/COM_DilateErodeNode.cc
index f1fc730776d..1b8c9d3b0a0 100644
--- a/source/blender/compositor/nodes/COM_DilateErodeNode.cc
+++ b/source/blender/compositor/nodes/COM_DilateErodeNode.cc
@@ -28,7 +28,7 @@ void DilateErodeNode::convert_to_operations(NodeConverter &converter,
                                             const CompositorContext &context) const
 {
   const bNode *editor_node = this->get_bnode();
-  if (editor_node->custom1 == CMP_NODE_DILATEERODE_DISTANCE_THRESH) {
+  if (editor_node->custom1 == CMP_NODE_DILATE_ERODE_DISTANCE_THRESHOLD) {
     DilateErodeThresholdOperation *operation = new DilateErodeThresholdOperation();
     operation->set_distance(editor_node->custom2);
     operation->set_inset(editor_node->custom3);
@@ -47,7 +47,7 @@ void DilateErodeNode::convert_to_operations(NodeConverter &converter,
       converter.map_output_socket(get_output_socket(0), operation->get_output_socket(0));
     }
   }
-  else if (editor_node->custom1 == CMP_NODE_DILATEERODE_DISTANCE) {
+  else if (editor_node->custom1 == CMP_NODE_DILATE_ERODE_DISTANCE) {
     if (editor_node->custom2 > 0) {
       DilateDistanceOperation *operation = new DilateDistanceOperation();
       operation->set_distance(editor_node->custom2);
@@ -65,7 +65,7 @@ void DilateErodeNode::convert_to_operations(NodeConverter &converter,
       converter.map_output_socket(get_output_socket(0), operation->get_output_socket(0));
     }
   }
-  else if (editor_node->custom1 == CMP_NODE_DILATEERODE_DISTANCE_FEATHER) {
+  else if (editor_node->custom1 == CMP_NODE_DILATE_ERODE_DISTANCE_FEATHER) {
     /* this uses a modified gaussian blur function otherwise its far too slow */
     eCompositorQuality quality = context.get_quality();
 
diff --git a/source/blender/draw/intern/shaders/common_math_lib.glsl b/source/blender/draw/intern/shaders/common_math_lib.glsl
index e3734939b3f..5842df424be 100644
--- a/source/blender/draw/intern/shaders/common_math_lib.glsl
+++ b/source/blender/draw/intern/shaders/common_math_lib.glsl
@@ -17,6 +17,7 @@
 #define M_SQRT2 1.41421356237309504880   /* sqrt(2) */
 #define M_SQRT1_2 0.70710678118654752440 /* 1/sqrt(2) */
 #define FLT_MAX 3.402823e+38
+#define FLT_MIN 1.175494e-38
 
 vec3 mul(mat3 m, vec3 v)
 {
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index 979bfc63572..7ae9eae6d44 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -340,6 +340,10 @@ set(GLSL_SRC
   shaders/compositor/compositor_filter.glsl
   shaders/compositor/compositor_flip.glsl
   shaders/compositor/compositor_image_crop.glsl
+  shaders/compositor/compositor_morphological_distance.glsl
+  shaders/compositor/compositor_morphological_distance_feather.glsl
+  shaders/compositor/compositor_morphological_distance_threshold.glsl
+  shaders/compositor/compositor_morphological_step.glsl
   shaders/compositor/compositor_projector_lens_distortion.glsl
   shaders/compositor/compositor_realize_on_domain.glsl
   shaders/compositor/compositor_screen_lens_distortion.glsl
@@ -616,6 +620,10 @@ set(SRC_SHADER_CREATE_INFOS
   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_morphological_distance_feather_info.hh
+  shaders/compositor/infos/compositor_morphological_distance_info.hh
+  shaders/compositor/infos/compositor_morphological_distance_threshold_info.hh
+  shaders/compositor/infos/compositor_morphological_step_info.hh
   shaders/compositor/infos/compositor_projector_lens_distortion_info.hh
   shaders/compositor/infos/compositor_realize_on_domain_info.hh
   shaders/compositor/infos/compositor_screen_lens_distortion_info.hh
diff --git a/source/blender/gpu/shaders/compositor/compositor_morphological_distance.glsl b/source/blender/gpu/shaders/compositor/compositor_morphological_distance.glsl
new file mode 100644
index 00000000000..09f896b7a9d
--- /dev/null
+++ b/source/blender/gpu/shaders/compositor/compositor_morphological_distance.glsl
@@ -0,0 +1,24 @@
+#pragma BLENDER_REQUIRE(common_math_lib.glsl)
+#pragma BLENDER_REQUIRE(gpu_shader_compositor_texture_utilities.glsl)
+
+void main()
+{
+  ivec2 texel = ivec2(gl_GlobalInvocationID.xy);
+
+  /* Find the minimum/maximum value in the circular window of the given radius around the pixel. By
+   * circular window, we mean that pixels in the window whose distance to the center of window is
+   * larger than the given radius are skipped and not considered. Consequently, the dilation or
+   * erosion that take place produces round results as opposed to squarish ones. This is
+   * essentially a morphological operator with a circular structuring element. The LIMIT value
+   * should be FLT_MAX if OPERATOR is min and FLT_MIN if OPERATOR is max. */
+  float value = LIMIT;
+  for (int y = -radius; y <= radius; y++) {
+    for (int x = -radius; x <= radius; x++) {
+      if (x * x + y * y <= radius * radius) {
+        value = OPERATOR(value, texture_load(input_tx, texel + ivec2(x, y), vec4(LIMIT)).x);
+      }
+    }
+  }
+
+  imageStore(output_img, texel, vec4(value));
+}
diff --git a/source/blender/gpu/shaders/compositor/compositor_morphological_distance_feather.glsl b/source/blender/gpu/shaders/compositor/compositor_morphological_distance_feather.glsl
new file mode 100644
index 00000000000..8034f4a3ebd
--- /dev/null
+++ b/source/blender/gpu/shaders/compositor/compositor_morphological_distance_feather.glsl
@@ -0,0 +1,101 @@
+#pragma BLENDER_REQUIRE(gpu_shader_compositor_texture_utilities.glsl)
+
+/* The Morphological Distance Feather operation is a linear combination between the result of two
+ * operations. The first operation is a Gaussian blur with a radius equivalent to the dilate/erode
+ * distance, which is straightforward and implemented as a separable filter similar to the blur
+ * operation.
+ *
+ * The second operation is an approximation of a morphological inverse distance operation evaluated
+ * at a distance falloff function. The result of a morphological inverse distance operation is a
+ * narrow band distance field that starts at its maximum value at boundaries where a difference in
+ * values took place and linearly deceases until it reaches zero in the span of a number of pixels
+ * equivalent to the erode/dilate distance. Additionally, instead of linearly decreasing, the user
+ * may choose a different falloff which is evaluated at the computed distance. For dilation, the
+ * distance field decreases outwards, and for erosion, the distance field decreased inwards.
+ *
+ * The reason why the result of a Gaussian blur is mixed in with the distance field is because the
+ * distance field is merely approximated and not accurately computed, the defects of which is more
+ * apparent away from boundaries and especially at corners where the distance field should take a
+ * circular shape. That's why the Gaussian blur is mostly mixed only further from boundaries.
+ *
+ * The morphological inverse distance operation is approximated using a separable implementation
+ * and intertwined with the Gaussian blur implementation as follows. A search window of a radius
+ * equivalent to the dilate/erode distance is applied on the image to find either the minimum or
+ * maximum pixel value multiplied by its corresponding falloff value in the window. For dilation,
+ * we try to find the maximum, and for erosion, we try to find the minimum. Additionally, we also
+ * save the falloff value where the minimum or maximum was found. The found value will be that of
+ * the narrow band distance field and the saved falloff value will be used as the mixing factor
+ * with the Gaussian blur.
+ *
+ * To make sense of the aforementioned algorithm, assume we are dilating a binary image by 5 pixels
+ * whose half has a value of 1 and the other half has a value of zero. Consider the following:
+ *
+ * - A pixel of value 1 already has the maximum possible value, so its value will remain unchanged
+ *   regardless of its position.
+ * - A pixel of value 0 that is right at the boundary of the 1's region will have a maximum value
+ *   of around 0.8 depending on the falloff. That's because the search window intersects the 1's
+ *   region, which when multiplied by the falloff gives the first value of the falloff, which is
+ *   larger than the initially zero value computed at the center of the search window.
+ * - A pixel of value 0 that is 3 pixels away from the boundary will have a maximum value of around
+ *   0.4 depending on the falloff. That's because the search window intersects the 1's region,
+ *   which when multiplied by the falloff gives the third value of the falloff, which is larger
+ *   than the initially zero value computed at the center of the search window.
+ * - Finally, a pixel of value 0 that is 6 pixels away from the boundary will have a maximum value
+ *   of 0, because the search window doesn't intersects the 1's region and only spans zero values.
+ *
+ * The previous example demonstrates how the distance field naturally arises, and the same goes for
+ * the erode case, except the minimum value is computed instead.
+ */
+void main()
+{
+  ivec2 texel = ivec2(gl_GlobalInvocationID.xy);
+
+  /* A value for accumulating the blur result. */
+  float accumulated_value = 0.0;
+
+  /* Compute the contribution of the center pixel to the blur result. */
+  float center_value = texture_load(input_tx, texel).x;
+  accumulated_value += center_value * texture_load(weights_tx, 0).x;
+
+  /* Start with the center value as the maximum/minimum distance and reassign to the true maximum
+   * or minimum in the search loop below. Additionally, the center falloff is always 1.0, so start
+   * with that.  */
+  float limit_distance = center_value;
+  float limit_distance_falloff = 1.0;
+
+  /* Compute the contributions of the pixels to the right and left, noting that the weights and
+   * falloffs textures only store the weights and falloffs for the positive half, but since the
+   * they are both symmetric, the same weights and falloffs are used for the ne

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list