Blender V4.3
node_composite_bokehblur.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2006 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include "BLI_math_base.hh"
11
12#include "UI_interface.hh"
13#include "UI_resources.hh"
14
15#include "GPU_texture.hh"
16
18#include "COM_node_operation.hh"
19#include "COM_utilities.hh"
20
22
23/* **************** BLUR ******************** */
24
26
28{
29 b.add_input<decl::Color>("Image")
30 .default_value({0.8f, 0.8f, 0.8f, 1.0f})
31 .compositor_domain_priority(0);
32 b.add_input<decl::Color>("Bokeh")
33 .default_value({1.0f, 1.0f, 1.0f, 1.0f})
34 .compositor_realization_options(CompositorInputRealizationOptions::None);
35 b.add_input<decl::Float>("Size")
36 .default_value(1.0f)
37 .min(0.0f)
38 .max(10.0f)
40 b.add_input<decl::Float>("Bounding box")
41 .default_value(1.0f)
42 .min(0.0f)
43 .max(1.0f)
45 b.add_output<decl::Color>("Image");
46}
47
48static void node_composit_init_bokehblur(bNodeTree * /*ntree*/, bNode *node)
49{
50 node->custom3 = 4.0f;
51 node->custom4 = 16.0f;
52}
53
55{
56 uiItemR(layout, ptr, "use_variable_size", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
57 // uiItemR(layout, ptr, "f_stop", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); /* UNUSED */
58 uiItemR(layout, ptr, "blur_max", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
59 uiItemR(layout, ptr, "use_extended_bounds", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
60}
61
62using namespace blender::realtime_compositor;
63
65 public:
67
68 void execute() override
69 {
70 if (is_identity()) {
71 get_input("Image").pass_through(get_result("Image"));
72 return;
73 }
74
75 if (get_input("Size").is_single_value() || !get_variable_size()) {
77 }
78 else {
80 }
81 }
82
84 {
85 GPUShader *shader = context().get_shader("compositor_bokeh_blur");
86 GPU_shader_bind(shader);
87
88 GPU_shader_uniform_1i(shader, "radius", int(compute_blur_radius()));
89 GPU_shader_uniform_1b(shader, "extend_bounds", get_extend_bounds());
90
91 const Result &input_image = get_input("Image");
92 input_image.bind_as_texture(shader, "input_tx");
93
94 const Result &input_weights = get_input("Bokeh");
95 input_weights.bind_as_texture(shader, "weights_tx");
96
97 const Result &input_mask = get_input("Bounding box");
98 input_mask.bind_as_texture(shader, "mask_tx");
99
100 Domain domain = compute_domain();
101 if (get_extend_bounds()) {
102 /* Add a radius amount of pixels in both sides of the image, hence the multiply by 2. */
103 domain.size += int2(int(compute_blur_radius()) * 2);
104 }
105
106 Result &output_image = get_result("Image");
107 output_image.allocate_texture(domain);
108 output_image.bind_as_image(shader, "output_img");
109
110 compute_dispatch_threads_at_least(shader, domain.size);
111
113 output_image.unbind_as_image();
114 input_image.unbind_as_texture();
115 input_weights.unbind_as_texture();
116 input_mask.unbind_as_texture();
117 }
118
120 {
121 const int search_radius = compute_variable_size_search_radius();
122
123 GPUShader *shader = context().get_shader("compositor_bokeh_blur_variable_size");
124 GPU_shader_bind(shader);
125
126 GPU_shader_uniform_1f(shader, "base_size", compute_blur_radius());
127 GPU_shader_uniform_1i(shader, "search_radius", search_radius);
128
129 const Result &input_image = get_input("Image");
130 input_image.bind_as_texture(shader, "input_tx");
131
132 const Result &input_weights = get_input("Bokeh");
133 input_weights.bind_as_texture(shader, "weights_tx");
134
135 const Result &input_size = get_input("Size");
136 input_size.bind_as_texture(shader, "size_tx");
137
138 const Result &input_mask = get_input("Bounding box");
139 input_mask.bind_as_texture(shader, "mask_tx");
140
141 const Domain domain = compute_domain();
142 Result &output_image = get_result("Image");
143 output_image.allocate_texture(domain);
144 output_image.bind_as_image(shader, "output_img");
145
146 compute_dispatch_threads_at_least(shader, domain.size);
147
149 output_image.unbind_as_image();
150 input_image.unbind_as_texture();
151 input_weights.unbind_as_texture();
152 input_size.unbind_as_texture();
153 input_mask.unbind_as_texture();
154 }
155
157 {
158 const Result &input_size = get_input("Size");
159 const float maximum_size = maximum_float(context(), input_size);
160
161 const float base_size = compute_blur_radius();
162 return math::clamp(int(maximum_size * base_size), 0, get_max_size());
163 }
164
166 {
167 const int2 image_size = get_input("Image").domain().size;
168 const int max_size = math::max(image_size.x, image_size.y);
169
170 /* The [0, 10] range of the size is arbitrary and is merely in place to avoid very long
171 * computations of the bokeh blur. */
172 const float size = math::clamp(get_input("Size").get_float_value_default(1.0f), 0.0f, 10.0f);
173
174 /* The 100 divisor is arbitrary and was chosen using visual judgment. */
175 return size * (max_size / 100.0f);
176 }
177
179 {
180 const Result &input = get_input("Image");
181 if (input.is_single_value()) {
182 return true;
183 }
184
185 if (compute_blur_radius() == 0.0f) {
186 return true;
187 }
188
189 /* This input is, in fact, a boolean mask. If it is zero, no blurring will take place.
190 * Otherwise, the blurring will take place ignoring the value of the input entirely. */
191 const Result &bounding_box = get_input("Bounding box");
192 if (bounding_box.is_single_value() && bounding_box.get_float_value() == 0.0) {
193 return true;
194 }
195
196 return false;
197 }
198
203
208
210 {
211 return int(bnode().custom4);
212 }
213};
214
216{
217 return new BokehBlurOperation(context, node);
218}
219
220} // namespace blender::nodes::node_composite_bokehblur_cc
221
223{
225
226 static blender::bke::bNodeType ntype;
227
228 cmp_node_type_base(&ntype, CMP_NODE_BOKEHBLUR, "Bokeh Blur", NODE_CLASS_OP_FILTER);
229 ntype.declare = file_ns::cmp_node_bokehblur_declare;
230 ntype.draw_buttons = file_ns::node_composit_buts_bokehblur;
231 ntype.initfunc = file_ns::node_composit_init_bokehblur;
232 ntype.get_compositor_operation = file_ns::get_compositor_operation;
233
235}
#define NODE_CLASS_OP_FILTER
Definition BKE_node.hh:408
@ CMP_NODEFLAG_BLUR_VARIABLE_SIZE
@ CMP_NODEFLAG_BLUR_EXTEND_BOUNDS
void GPU_shader_uniform_1i(GPUShader *sh, const char *name, int value)
void GPU_shader_uniform_1f(GPUShader *sh, const char *name, float value)
void GPU_shader_bind(GPUShader *shader)
void GPU_shader_uniform_1b(GPUShader *sh, const char *name, bool value)
void GPU_shader_unbind()
void uiItemR(uiLayout *layout, PointerRNA *ptr, const char *propname, eUI_Item_Flag flag, const char *name, int icon)
@ UI_ITEM_R_SPLIT_EMPTY_NAME
struct GPUShader GPUShader
GPUShader * get_shader(const char *info_name, ResultPrecision precision)
NodeOperation(Context &context, DNode node)
Result & get_input(StringRef identifier) const
Definition operation.cc:144
Result & get_result(StringRef identifier)
Definition operation.cc:46
void bind_as_image(GPUShader *shader, const char *image_name, bool read=false) const
Definition result.cc:264
void pass_through(Result &target)
Definition result.cc:289
const Domain & domain() const
Definition result.cc:712
void allocate_texture(Domain domain, bool from_pool=true)
Definition result.cc:204
void bind_as_texture(GPUShader *shader, const char *texture_name) const
Definition result.cc:253
local_group_size(16, 16) .push_constant(Type b
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
void node_register_type(bNodeType *ntype)
Definition node.cc:1708
T clamp(const T &a, const T &min, const T &max)
T max(const T &a, const T &b)
static void node_composit_init_bokehblur(bNodeTree *, bNode *node)
static void cmp_node_bokehblur_declare(NodeDeclarationBuilder &b)
static void node_composit_buts_bokehblur(uiLayout *layout, bContext *, PointerRNA *ptr)
static NodeOperation * get_compositor_operation(Context &context, DNode node)
void compute_dispatch_threads_at_least(GPUShader *shader, int2 threads_range, int2 local_size=int2(16))
Definition utilities.cc:131
float maximum_float(Context &context, GPUTexture *texture)
VecBase< int32_t, 2 > int2
void register_node_type_cmp_bokehblur()
void cmp_node_type_base(blender::bke::bNodeType *ntype, int type, const char *name, short nclass)
int16_t custom1
Defines a node type.
Definition BKE_node.hh:218
NodeGetCompositorOperationFunction get_compositor_operation
Definition BKE_node.hh:324
void(* initfunc)(bNodeTree *ntree, bNode *node)
Definition BKE_node.hh:267
void(* draw_buttons)(uiLayout *, bContext *C, PointerRNA *ptr)
Definition BKE_node.hh:238
NodeDeclareFunction declare
Definition BKE_node.hh:347
PointerRNA * ptr
Definition wm_files.cc:4126