Blender V4.3
node_composite_dilate.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_assert.h"
10#include "BLI_math_base.hh"
12
13#include "RNA_access.hh"
14
15#include "UI_interface.hh"
16#include "UI_resources.hh"
17
18#include "GPU_shader.hh"
19#include "GPU_state.hh"
20#include "GPU_texture.hh"
21
24#include "COM_algorithm_smaa.hh"
25#include "COM_node_operation.hh"
26#include "COM_utilities.hh"
27
29
30/* **************** Dilate/Erode ******************** */
31
33
35
37{
38 b.add_input<decl::Float>("Mask").default_value(0.0f).min(0.0f).max(1.0f);
39 b.add_output<decl::Float>("Mask");
40}
41
42static void node_composit_init_dilateerode(bNodeTree * /*ntree*/, bNode *node)
43{
44 NodeDilateErode *data = MEM_cnew<NodeDilateErode>(__func__);
45 data->falloff = PROP_SMOOTH;
46 node->storage = data;
47}
48
50{
51 uiItemR(layout, ptr, "mode", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
52 uiItemR(layout, ptr, "distance", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
53 switch (RNA_enum_get(ptr, "mode")) {
55 uiItemR(layout, ptr, "edge", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
56 break;
58 uiItemR(layout, ptr, "falloff", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
59 break;
60 }
61}
62
63using namespace blender::realtime_compositor;
64
66 public:
68
69 void execute() override
70 {
71 if (is_identity()) {
72 get_input("Mask").pass_through(get_result("Mask"));
73 return;
74 }
75
76 switch (get_method()) {
79 return;
82 return;
85 return;
88 return;
89 default:
91 return;
92 }
93 }
94
95 /* ----------------------------
96 * Step Morphological Operator.
97 * ---------------------------- */
98
100 {
101 Result horizontal_pass_result = execute_step_horizontal_pass();
102 execute_step_vertical_pass(horizontal_pass_result);
103 horizontal_pass_result.release();
104 }
105
107 {
109 GPU_shader_bind(shader);
110
111 /* Pass the absolute value of the distance. We have specialized shaders for each sign. */
112 GPU_shader_uniform_1i(shader, "radius", math::abs(get_distance()));
113
114 const Result &input_mask = get_input("Mask");
115 input_mask.bind_as_texture(shader, "input_tx");
116
117 /* We allocate an output image of a transposed size, that is, with a height equivalent to the
118 * width of the input and vice versa. This is done as a performance optimization. The shader
119 * will process the image horizontally and write it to the intermediate output transposed. Then
120 * the vertical pass will execute the same horizontal pass shader, but since its input is
121 * transposed, it will effectively do a vertical pass and write to the output transposed,
122 * effectively undoing the transposition in the horizontal pass. This is done to improve
123 * spatial cache locality in the shader and to avoid having two separate shaders for each of
124 * the passes. */
125 const Domain domain = compute_domain();
126 const int2 transposed_domain = int2(domain.size.y, domain.size.x);
127
128 Result horizontal_pass_result = context().create_result(ResultType::Color);
129 horizontal_pass_result.allocate_texture(transposed_domain);
130 horizontal_pass_result.bind_as_image(shader, "output_img");
131
132 compute_dispatch_threads_at_least(shader, domain.size);
133
135 input_mask.unbind_as_texture();
136 horizontal_pass_result.unbind_as_image();
137
138 return horizontal_pass_result;
139 }
140
141 void execute_step_vertical_pass(Result &horizontal_pass_result)
142 {
144 GPU_shader_bind(shader);
145
146 /* Pass the absolute value of the distance. We have specialized shaders for each sign. */
147 GPU_shader_uniform_1i(shader, "radius", math::abs(get_distance()));
148
149 horizontal_pass_result.bind_as_texture(shader, "input_tx");
150
151 const Domain domain = compute_domain();
152 Result &output_mask = get_result("Mask");
153 output_mask.allocate_texture(domain);
154 output_mask.bind_as_image(shader, "output_img");
155
156 /* Notice that the domain is transposed, see the note on the horizontal pass method for more
157 * information on the reasoning behind this. */
158 compute_dispatch_threads_at_least(shader, int2(domain.size.y, domain.size.x));
159
161 horizontal_pass_result.unbind_as_texture();
162 output_mask.unbind_as_image();
163 }
164
166 {
167 if (get_distance() > 0) {
168 return "compositor_morphological_step_dilate";
169 }
170 return "compositor_morphological_step_erode";
171 }
172
173 /* --------------------------------
174 * Distance Morphological Operator.
175 * -------------------------------- */
176
178 {
180 }
181
182 /* ------------------------------------------
183 * Distance Threshold Morphological Operator.
184 * ------------------------------------------ */
185
187 {
188 GPUShader *shader = context().get_shader("compositor_morphological_distance_threshold");
189 GPU_shader_bind(shader);
190
191 GPU_shader_uniform_1f(shader, "inset", get_inset());
193 GPU_shader_uniform_1i(shader, "distance", get_distance());
194
195 const Result &input_mask = get_input("Mask");
196 input_mask.bind_as_texture(shader, "input_tx");
197
198 const Domain domain = compute_domain();
199 Result output_mask = context().create_result(ResultType::Float);
200 output_mask.allocate_texture(domain);
201 output_mask.bind_as_image(shader, "output_img");
202
203 compute_dispatch_threads_at_least(shader, domain.size);
204
206 output_mask.unbind_as_image();
207 input_mask.unbind_as_texture();
208
209 /* For configurations where there is little user-specified inset, anti-alias the result for
210 * smoother edges. */
211 Result &output = get_result("Mask");
212 if (get_inset() < 2.0f) {
213 smaa(context(), output_mask, output);
214 output_mask.release();
215 }
216 else {
217 output.steal_data(output_mask);
218 }
219 }
220
221 /* See the discussion in the implementation for more information. */
226
227 /* ----------------------------------------
228 * Distance Feather Morphological Operator.
229 * ---------------------------------------- */
230
232 {
234 get_input("Mask"),
235 get_result("Mask"),
236 get_distance(),
237 node_storage(bnode()).falloff);
238 }
239
240 /* ---------------
241 * Common Methods.
242 * --------------- */
243
245 {
246 const Result &input = get_input("Mask");
247 if (input.is_single_value()) {
248 return true;
249 }
250
252 return false;
253 }
254
255 if (get_distance() == 0) {
256 return true;
257 }
258
259 return false;
260 }
261
263 {
264 return bnode().custom2;
265 }
266
267 float get_inset()
268 {
269 return bnode().custom3;
270 }
271
276};
277
279{
280 return new DilateErodeOperation(context, node);
281}
282
283} // namespace blender::nodes::node_composite_dilate_cc
284
286{
288
289 static blender::bke::bNodeType ntype;
290
291 cmp_node_type_base(&ntype, CMP_NODE_DILATEERODE, "Dilate/Erode", NODE_CLASS_OP_FILTER);
292 ntype.draw_buttons = file_ns::node_composit_buts_dilateerode;
293 ntype.declare = file_ns::cmp_node_dilate_declare;
294 ntype.initfunc = file_ns::node_composit_init_dilateerode;
296 &ntype, "NodeDilateErode", node_free_standard_storage, node_copy_standard_storage);
297 ntype.get_compositor_operation = file_ns::get_compositor_operation;
298
300}
#define NODE_STORAGE_FUNCS(StorageT)
Definition BKE_node.hh:1799
#define NODE_CLASS_OP_FILTER
Definition BKE_node.hh:408
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
CMPNodeDilateErodeMethod
@ CMP_NODE_DILATE_ERODE_STEP
@ CMP_NODE_DILATE_ERODE_DISTANCE_FEATHER
@ CMP_NODE_DILATE_ERODE_DISTANCE_THRESHOLD
@ CMP_NODE_DILATE_ERODE_DISTANCE
@ PROP_SMOOTH
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_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)
Result create_result(ResultType type, 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
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_type_storage(bNodeType *ntype, const char *storagename, void(*freefunc)(bNode *node), void(*copyfunc)(bNodeTree *dest_ntree, bNode *dest_node, const bNode *src_node))
Definition node.cc:4632
void node_register_type(bNodeType *ntype)
Definition node.cc:1708
T ceil(const T &a)
T abs(const T &a)
static void cmp_node_dilate_declare(NodeDeclarationBuilder &b)
static void node_composit_init_dilateerode(bNodeTree *, bNode *node)
static void node_composit_buts_dilateerode(uiLayout *layout, bContext *, PointerRNA *ptr)
static NodeOperation * get_compositor_operation(Context &context, DNode node)
void morphological_distance(Context &context, Result &input, Result &output, int distance)
void smaa(Context &context, Result &input, Result &output, float threshold=0.1f, float local_contrast_adaptation_factor=2.0f, int corner_rounding=25)
Definition smaa.cc:160
void compute_dispatch_threads_at_least(GPUShader *shader, int2 threads_range, int2 local_size=int2(16))
Definition utilities.cc:131
void morphological_distance_feather(Context &context, Result &input, Result &output, int distance, int falloff_type=PROP_SMOOTH)
VecBase< int32_t, 2 > int2
void register_node_type_cmp_dilateerode()
void cmp_node_type_base(blender::bke::bNodeType *ntype, int type, const char *name, short nclass)
void node_free_standard_storage(bNode *node)
Definition node_util.cc:46
void node_copy_standard_storage(bNodeTree *, bNode *dest_node, const bNode *src_node)
Definition node_util.cc:58
int RNA_enum_get(PointerRNA *ptr, const char *name)
int16_t custom1
float custom3
int16_t custom2
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