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:
-rw-r--r--source/blender/gpu/CMakeLists.txt2
-rw-r--r--source/blender/gpu/shaders/compositor/compositor_blur.glsl55
-rw-r--r--source/blender/gpu/shaders/compositor/infos/compositor_blur_info.hh14
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_bokehblur.cc103
4 files changed, 169 insertions, 5 deletions
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index cb5bb4331f9..8b38c22ae28 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -326,6 +326,7 @@ set(GLSL_SRC
shaders/compositor/compositor_alpha_crop.glsl
shaders/compositor/compositor_bilateral_blur.glsl
+ shaders/compositor/compositor_blur.glsl
shaders/compositor/compositor_bokeh_image.glsl
shaders/compositor/compositor_box_mask.glsl
shaders/compositor/compositor_convert.glsl
@@ -604,6 +605,7 @@ set(SRC_SHADER_CREATE_INFOS
shaders/compositor/infos/compositor_alpha_crop_info.hh
shaders/compositor/infos/compositor_bilateral_blur_info.hh
+ shaders/compositor/infos/compositor_blur_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
diff --git a/source/blender/gpu/shaders/compositor/compositor_blur.glsl b/source/blender/gpu/shaders/compositor/compositor_blur.glsl
new file mode 100644
index 00000000000..4f981c84f59
--- /dev/null
+++ b/source/blender/gpu/shaders/compositor/compositor_blur.glsl
@@ -0,0 +1,55 @@
+#pragma BLENDER_REQUIRE(gpu_shader_common_math_utils.glsl)
+#pragma BLENDER_REQUIRE(gpu_shader_compositor_texture_utilities.glsl)
+
+vec4 load_input(ivec2 texel)
+{
+ vec4 color;
+ if (extend_bounds) {
+ /* If bounds are extended, then we treat the input as padded by a radius amount of pixels. So
+ * we load the input with an offset by the radius amount and fallback to a transparent color if
+ * it is out of bounds. */
+ color = texture_load(input_tx, texel - radius, vec4(0.0));
+ }
+ else {
+ color = texture_load(input_tx, texel);
+ }
+
+ return color;
+}
+
+/* Given the texel in the range [-radius, radius] in both axis, load the appropriate weight from
+ * the weights texture, where the texel (0, 0) is considered the center of weights texture. */
+vec4 load_weight(ivec2 texel)
+{
+ /* Add the radius to transform the texel into the range [0, radius * 2], then divide by the upper
+ * bound plus one to transform the texel into the normalized range [0, 1] needed to sample the
+ * weights sampler. Finally, also add 0.5 to sample at the center of the pixels. */
+ return texture(weights_tx, (texel + vec2(radius + 0.5)) / (radius * 2 + 1));
+}
+
+void main()
+{
+ ivec2 texel = ivec2(gl_GlobalInvocationID.xy);
+
+ /* The mask input is treated as a boolean. If it is zero, then no blurring happens for this
+ * pixel. Otherwise, the pixel is blurred normally and the mask value is irrelevant. */
+ float mask = texture_load(mask_tx, texel).x;
+ if (mask == 0.0) {
+ imageStore(output_img, texel, texture_load(input_tx, texel));
+ return;
+ }
+
+ /* Go over the window of the given radius and accumulate the colors multiplied by their
+ * respective weights as well as the weights themselves. */
+ vec4 accumulated_color = vec4(0.0);
+ vec4 accumulated_weight = vec4(0.0);
+ for (int y = -radius; y <= radius; y++) {
+ for (int x = -radius; x <= radius; x++) {
+ vec4 weight = load_weight(ivec2(x, y));
+ accumulated_color += load_input(texel + ivec2(x, y)) * weight;
+ accumulated_weight += weight;
+ }
+ }
+
+ imageStore(output_img, texel, safe_divide(accumulated_color, accumulated_weight));
+}
diff --git a/source/blender/gpu/shaders/compositor/infos/compositor_blur_info.hh b/source/blender/gpu/shaders/compositor/infos/compositor_blur_info.hh
new file mode 100644
index 00000000000..36b772aa486
--- /dev/null
+++ b/source/blender/gpu/shaders/compositor/infos/compositor_blur_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_blur)
+ .local_group_size(16, 16)
+ .push_constant(Type::INT, "radius")
+ .push_constant(Type::BOOL, "extend_bounds")
+ .sampler(0, ImageType::FLOAT_2D, "input_tx")
+ .sampler(1, ImageType::FLOAT_2D, "weights_tx")
+ .sampler(2, ImageType::FLOAT_2D, "mask_tx")
+ .image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img")
+ .compute_source("compositor_blur.glsl")
+ .do_static_compilation(true);
diff --git a/source/blender/nodes/composite/nodes/node_composite_bokehblur.cc b/source/blender/nodes/composite/nodes/node_composite_bokehblur.cc
index 538f00af12d..182169405de 100644
--- a/source/blender/nodes/composite/nodes/node_composite_bokehblur.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_bokehblur.cc
@@ -5,10 +5,16 @@
* \ingroup cmpnodes
*/
+#include "BLI_math_base.hh"
+#include "BLI_math_vec_types.hh"
+
#include "UI_interface.h"
#include "UI_resources.h"
+#include "GPU_texture.h"
+
#include "COM_node_operation.hh"
+#include "COM_utilities.hh"
#include "node_composite_util.hh"
@@ -18,10 +24,22 @@ namespace blender::nodes::node_composite_bokehblur_cc {
static void cmp_node_bokehblur_declare(NodeDeclarationBuilder &b)
{
- b.add_input<decl::Color>(N_("Image")).default_value({0.8f, 0.8f, 0.8f, 1.0f});
- b.add_input<decl::Color>(N_("Bokeh")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
- b.add_input<decl::Float>(N_("Size")).default_value(1.0f).min(0.0f).max(10.0f);
- b.add_input<decl::Float>(N_("Bounding box")).default_value(1.0f).min(0.0f).max(1.0f);
+ b.add_input<decl::Color>(N_("Image"))
+ .default_value({0.8f, 0.8f, 0.8f, 1.0f})
+ .compositor_domain_priority(0);
+ b.add_input<decl::Color>(N_("Bokeh"))
+ .default_value({1.0f, 1.0f, 1.0f, 1.0f})
+ .compositor_skip_realization();
+ b.add_input<decl::Float>(N_("Size"))
+ .default_value(1.0f)
+ .min(0.0f)
+ .max(10.0f)
+ .compositor_domain_priority(1);
+ b.add_input<decl::Float>(N_("Bounding box"))
+ .default_value(1.0f)
+ .min(0.0f)
+ .max(1.0f)
+ .compositor_domain_priority(2);
b.add_output<decl::Color>(N_("Image"));
}
@@ -47,7 +65,82 @@ class BokehBlurOperation : public NodeOperation {
void execute() override
{
- get_input("Image").pass_through(get_result("Image"));
+ if (is_identity()) {
+ get_input("Image").pass_through(get_result("Image"));
+ return;
+ }
+
+ GPUShader *shader = shader_manager().get("compositor_blur");
+ GPU_shader_bind(shader);
+
+ GPU_shader_uniform_1i(shader, "radius", compute_blur_radius());
+ GPU_shader_uniform_1b(shader, "extend_bounds", get_extend_bounds());
+
+ const Result &input_image = get_input("Image");
+ input_image.bind_as_texture(shader, "input_tx");
+
+ const Result &input_weights = get_input("Bokeh");
+ input_weights.bind_as_texture(shader, "weights_tx");
+
+ const Result &input_mask = get_input("Bounding box");
+ input_mask.bind_as_texture(shader, "mask_tx");
+
+ Domain domain = compute_domain();
+ if (get_extend_bounds()) {
+ /* Add a radius amount of pixels in both sides of the image, hence the multiply by 2. */
+ domain.size += int2(compute_blur_radius() * 2);
+ }
+
+ 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);
+
+ GPU_shader_unbind();
+ output_image.unbind_as_image();
+ input_image.unbind_as_texture();
+ input_weights.unbind_as_texture();
+ input_mask.unbind_as_texture();
+ }
+
+ int compute_blur_radius()
+ {
+ const int2 image_size = get_input("Image").domain().size;
+ const int max_size = math::max(image_size.x, image_size.y);
+
+ /* The [0, 10] range of the size is arbitrary and is merely in place to avoid very long
+ * computations of the bokeh blur. */
+ const float size = math::clamp(get_input("Size").get_float_value_default(1.0f), 0.0f, 10.0f);
+
+ /* The 100 divisor is arbitrary and was chosen using visual judgement. */
+ return size * (max_size / 100.0f);
+ }
+
+ bool is_identity()
+ {
+ const Result &input = get_input("Image");
+ if (input.is_single_value()) {
+ return true;
+ }
+
+ if (compute_blur_radius() == 0) {
+ return true;
+ }
+
+ /* This input is, in fact, a boolean mask. If it is zero, no blurring will take place.
+ * Otherwise, the blurring will take place ignoring the value of the input entirely. */
+ const Result &bounding_box = get_input("Bounding box");
+ if (bounding_box.is_single_value() && bounding_box.get_float_value() == 0.0) {
+ return true;
+ }
+
+ return false;
+ }
+
+ bool get_extend_bounds()
+ {
+ return bnode().custom1 & CMP_NODEFLAG_BLUR_EXTEND_BOUNDS;
}
};