[Bf-blender-cvs] [6cb0a122dfc] master: Realtime Compositor: Implement bokeh image node

Omar Emara noreply at git.blender.org
Thu Aug 18 11:54:01 CEST 2022


Commit: 6cb0a122dfcd7d3e75e8bc0d12e09b75b97cee99
Author: Omar Emara
Date:   Thu Aug 18 11:53:08 2022 +0200
Branches: master
https://developer.blender.org/rB6cb0a122dfcd7d3e75e8bc0d12e09b75b97cee99

Realtime Compositor: Implement bokeh image node

This patch implements the bokeh image node for the realtime compositor.

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

Reviewed By: Clement Foucault

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

M	source/blender/gpu/CMakeLists.txt
A	source/blender/gpu/shaders/compositor/compositor_bokeh_image.glsl
A	source/blender/gpu/shaders/compositor/infos/compositor_bokeh_image_info.hh
M	source/blender/nodes/composite/nodes/node_composite_bokehimage.cc

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

diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index 92dacee1879..bbc27a26835 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -315,6 +315,7 @@ set(GLSL_SRC
   shaders/common/gpu_shader_common_mix_rgb.glsl
 
   shaders/compositor/compositor_alpha_crop.glsl
+  shaders/compositor/compositor_bokeh_image.glsl
   shaders/compositor/compositor_box_mask.glsl
   shaders/compositor/compositor_convert.glsl
   shaders/compositor/compositor_ellipse_mask.glsl
@@ -561,6 +562,7 @@ set(SRC_SHADER_CREATE_INFOS
   shaders/infos/gpu_srgb_to_framebuffer_space_info.hh
 
   shaders/compositor/infos/compositor_alpha_crop_info.hh
+  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_ellipse_mask_info.hh
diff --git a/source/blender/gpu/shaders/compositor/compositor_bokeh_image.glsl b/source/blender/gpu/shaders/compositor/compositor_bokeh_image.glsl
new file mode 100644
index 00000000000..6e98aa9fe17
--- /dev/null
+++ b/source/blender/gpu/shaders/compositor/compositor_bokeh_image.glsl
@@ -0,0 +1,118 @@
+#pragma BLENDER_REQUIRE(common_math_lib.glsl)
+#pragma BLENDER_REQUIRE(gpu_shader_compositor_texture_utilities.glsl)
+
+/* Get the 2D vertex position of the vertex with the given index in the regular polygon
+ * representing this bokeh. The polygon is rotated by the rotation amount and have a unit
+ * circumradius. The regular polygon is one whose vertices' exterior angles are given by
+ * exterior_angle. See the bokeh function for more information. */
+vec2 get_regular_polygon_vertex_position(int vertex_index)
+{
+  float angle = exterior_angle * vertex_index - rotation;
+  return vec2(cos(angle), sin(angle));
+}
+
+/* Find the closest point to the given point on the given line. This assumes the length of the
+ * given line is not zero. */
+vec2 closest_point_on_line(vec2 point, vec2 line_start, vec2 line_end)
+{
+  vec2 line_vector = line_end - line_start;
+  vec2 point_vector = point - line_start;
+  float line_length_squared = dot(line_vector, line_vector);
+  float parameter = dot(point_vector, line_vector) / line_length_squared;
+  return line_start + line_vector * parameter;
+}
+
+/* Compute the value of the bokeh at the given point. The computed bokeh is essentially a regular
+ * polygon centered in space having the given circumradius. The regular polygon is one whose
+ * vertices' exterior angles are given by "exterior_angle", which relates to the number of vertices
+ * n through the equation "exterior angle = 2 pi / n". The regular polygon may additionally morph
+ * into a shape with the given properties:
+ *
+ * - The regular polygon may have a circular hole in its center whose radius is controlled by the
+ *   "catadioptric" value.
+ * - The regular polygon is rotated by the "rotation" value.
+ * - The regular polygon can morph into a circle controlled by the "roundness" value, such that it
+ *   becomes a full circle at unit roundness.
+ *
+ * The function returns 0 when the point lies inside the regular polygon and 1 otherwise. However,
+ * at the edges, it returns a narrow band gradient as a form of anti-aliasing. */
+float bokeh(vec2 point, float circumradius)
+{
+  /* Get the index of the vertex of the regular polygon whose polar angle is maximum but less than
+   * the polar angle of the given point, taking rotation into account. This essentially finds the
+   * vertex closest to the given point in the clock-wise direction. */
+  float angle = mod(atan(point.y, point.x) + rotation, M_2PI);
+  int vertex_index = int(angle / exterior_angle);
+
+  /* Compute the shortest distance between the origin and the polygon edge composed from the
+   * previously selected vertex and the one following it. */
+  vec2 first_vertex = get_regular_polygon_vertex_position(vertex_index) * circumradius;
+  vec2 second_vertex = get_regular_polygon_vertex_position(vertex_index + 1) * circumradius;
+  vec2 closest_point = closest_point_on_line(point, first_vertex, second_vertex);
+  float distance_to_edge = length(closest_point);
+
+  /* Mix the distance to the edge with the circumradius, making it tend to the distance to a
+   * circle when roundness tends to 1. */
+  float distance_to_edge_round = mix(distance_to_edge, circumradius, roundness);
+
+  /* The point is outside of the bokeh, so we return 0. */
+  float distance = length(point);
+  if (distance > distance_to_edge_round) {
+    return 0.0;
+  }
+
+  /* The point is inside the catadioptric hole and is not part of the bokeh, so we return 0. */
+  float catadioptric_distance = distance_to_edge_round * catadioptric;
+  if (distance < catadioptric_distance) {
+    return 0.0;
+  }
+
+  /* The point is very close to the edge of the bokeh, so we return the difference between the
+   * distance to the edge and the distance as a form of anti-aliasing. */
+  if (distance_to_edge_round - distance < 1.0) {
+    return distance_to_edge_round - distance;
+  }
+
+  /* The point is very close to the edge of the catadioptric hole, so we return the difference
+   * between the distance to the hole and the distance as a form of anti-aliasing. */
+  if (catadioptric != 0.0 && distance - catadioptric_distance < 1.0) {
+    return distance - catadioptric_distance;
+  }
+
+  /* Otherwise, the point is part of the bokeh and we return 1. */
+  return 1.0;
+}
+
+void main()
+{
+  ivec2 texel = ivec2(gl_GlobalInvocationID.xy);
+
+  /* Since we need the regular polygon to occupy the entirety of the output image, the circumradius
+   * of the regular polygon is half the width of the output image. */
+  float circumradius = float(imageSize(output_img).x) / 2.0;
+
+  /* Move the texel coordinates such that the regular polygon is centered. */
+  vec2 point = vec2(texel) - circumradius;
+
+  /* Each of the color channels of the output image contains a bokeh with a different circumradius.
+   * The largest one occupies the whole image as stated above, while the other two have circumradii
+   * that are shifted by an amount that is proportional to the "lens_shift" value. The alpha
+   * channel of the output is the average of all three values. */
+  float min_shift = abs(lens_shift * circumradius);
+  float min = mix(bokeh(point, circumradius - min_shift), 0.0, min_shift == circumradius);
+
+  float median_shift = min_shift / 2.0;
+  float median = bokeh(point, circumradius - median_shift);
+
+  float max = bokeh(point, circumradius);
+  vec4 bokeh = vec4(min, median, max, (max + median + min) / 3.0);
+
+  /* If the lens shift is negative, swap the min and max bokeh values, which are stored in the red
+   * and blue channels respectively. Note that we take the absolute value of the lens shift above,
+   * so the sign of the lens shift only controls this swap. */
+  if (lens_shift < 0) {
+    bokeh = bokeh.zyxw;
+  }
+
+  imageStore(output_img, texel, bokeh);
+}
diff --git a/source/blender/gpu/shaders/compositor/infos/compositor_bokeh_image_info.hh b/source/blender/gpu/shaders/compositor/infos/compositor_bokeh_image_info.hh
new file mode 100644
index 00000000000..3541de53070
--- /dev/null
+++ b/source/blender/gpu/shaders/compositor/infos/compositor_bokeh_image_info.hh
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include "gpu_shader_create_info.hh"
+
+GPU_SHADER_CREATE_INFO(compositor_bokeh_image)
+    .local_group_size(16, 16)
+    .push_constant(Type::FLOAT, "exterior_angle")
+    .push_constant(Type::FLOAT, "rotation")
+    .push_constant(Type::FLOAT, "roundness")
+    .push_constant(Type::FLOAT, "catadioptric")
+    .push_constant(Type::FLOAT, "lens_shift")
+    .image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img")
+    .compute_source("compositor_bokeh_image.glsl")
+    .do_static_compilation(true);
diff --git a/source/blender/nodes/composite/nodes/node_composite_bokehimage.cc b/source/blender/nodes/composite/nodes/node_composite_bokehimage.cc
index a11cba37191..ddb1e569c52 100644
--- a/source/blender/nodes/composite/nodes/node_composite_bokehimage.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_bokehimage.cc
@@ -5,10 +5,16 @@
  * \ingroup cmpnodes
  */
 
+#include "BLI_math_base.h"
+#include "BLI_math_vec_types.hh"
+
 #include "UI_interface.h"
 #include "UI_resources.h"
 
+#include "GPU_shader.h"
+
 #include "COM_node_operation.hh"
+#include "COM_utilities.hh"
 
 #include "node_composite_util.hh"
 
@@ -55,7 +61,50 @@ class BokehImageOperation : public NodeOperation {
 
   void execute() override
   {
-    get_result("Image").allocate_invalid();
+    GPUShader *shader = shader_manager().get("compositor_bokeh_image");
+    GPU_shader_bind(shader);
+
+    GPU_shader_uniform_1f(shader, "exterior_angle", get_exterior_angle());
+    GPU_shader_uniform_1f(shader, "rotation", get_rotation());
+    GPU_shader_uniform_1f(shader, "roundness", get_node_bokeh_image().rounding);
+    GPU_shader_uniform_1f(shader, "catadioptric", get_node_bokeh_image().catadioptric);
+    GPU_shader_uniform_1f(shader, "lens_shift", get_node_bokeh_image().lensshift);
+
+    Result &output = get_result("Image");
+    const Domain domain = compute_domain();
+    output.allocate_texture(domain);
+    output.bind_as_image(shader, "output_img");
+
+    compute_dispatch_threads_at_least(shader, domain.size);
+
+    output.unbind_as_image();
+    GPU_shader_unbind();
+  }
+
+  Domain compute_domain() override
+  {
+    return Domain(int2(512));
+  }
+
+  NodeBokehImage &get_node_bokeh_image()
+  {
+    return *static_cast<NodeBokehImage *>(bnode().storage);
+  }
+
+  /* The exterior angle is the angle between each two consective vertices of the regular polygon
+   * from its center. */
+  float get_exterior_angle()
+  {
+    return (M_PI * 2.0f) / get_node_bokeh_image().flaps;
+  }
+
+  float get_rotation()
+  {
+    /* Offset the rotation such that the second vertex of the regular polygon lies on the positive
+     * y axis, which is 90 degrees minus the angle that it makes with the positive x axis assuming
+     * the first vertex lies on the positive x axis. */
+    const float offset = M_PI_2 - 

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list