Blender V4.3
node_composite_directionalblur.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"
10#include "BLI_math_matrix.hh"
11
12#include "UI_interface.hh"
13#include "UI_resources.hh"
14
15#include "GPU_shader.hh"
16
17#include "COM_node_operation.hh"
18#include "COM_utilities.hh"
19
21
23
25
27{
28 b.add_input<decl::Color>("Image")
29 .default_value({1.0f, 1.0f, 1.0f, 1.0f})
30 .compositor_domain_priority(0);
31 b.add_output<decl::Color>("Image");
32}
33
34static void node_composit_init_dblur(bNodeTree * /*ntree*/, bNode *node)
35{
36 NodeDBlurData *ndbd = MEM_cnew<NodeDBlurData>(__func__);
37 node->storage = ndbd;
38 ndbd->iter = 1;
39 ndbd->center_x = 0.5;
40 ndbd->center_y = 0.5;
41}
42
44{
46
47 uiItemR(layout, ptr, "iterations", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
48
49 col = uiLayoutColumn(layout, true);
50 uiItemL(col, IFACE_("Center:"), ICON_NONE);
51 uiItemR(col, ptr, "center_x", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("X"), ICON_NONE);
52 uiItemR(col, ptr, "center_y", UI_ITEM_R_SPLIT_EMPTY_NAME, IFACE_("Y"), ICON_NONE);
53
54 uiItemS(layout);
55
56 col = uiLayoutColumn(layout, true);
57 uiItemR(col, ptr, "distance", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
58 uiItemR(col, ptr, "angle", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
59
60 uiItemS(layout);
61
62 uiItemR(layout, ptr, "spin", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
63 uiItemR(layout, ptr, "zoom", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
64}
65
66using namespace blender::realtime_compositor;
67
69 public:
71
72 void execute() override
73 {
74 if (is_identity()) {
75 get_input("Image").pass_through(get_result("Image"));
76 return;
77 }
78
79 GPUShader *shader = context().get_shader("compositor_directional_blur");
80 GPU_shader_bind(shader);
81
82 /* The number of iterations does not cover the original image, that is, the image with no
83 * transformation. So add an extra iteration for the original image and put that into
84 * consideration in the shader. */
85 GPU_shader_uniform_1i(shader, "iterations", get_iterations() + 1);
86 GPU_shader_uniform_2fv(shader, "origin", get_origin());
87 GPU_shader_uniform_2fv(shader, "translation", get_translation());
88 GPU_shader_uniform_1f(shader, "rotation_sin", math::sin(get_rotation()));
89 GPU_shader_uniform_1f(shader, "rotation_cos", math::cos(get_rotation()));
90 GPU_shader_uniform_1f(shader, "scale", get_scale());
91
92 const Result &input_image = get_input("Image");
93 GPU_texture_filter_mode(input_image, true);
95 input_image.bind_as_texture(shader, "input_tx");
96
97 const Domain domain = compute_domain();
98 Result &output_image = get_result("Image");
99 output_image.allocate_texture(domain);
100 output_image.bind_as_image(shader, "output_img");
101
102 compute_dispatch_threads_at_least(shader, domain.size);
103
105 output_image.unbind_as_image();
106 input_image.unbind_as_texture();
107 }
108
109 /* Get the amount of translation relative to the image size that will be applied on each
110 * iteration. The translation is in the negative x direction rotated in the clock-wise direction,
111 * hence the negative sign for the rotation and translation vector. */
113 {
114 const float2 input_size = float2(get_input("Image").domain().size);
115 const float diagonal_length = math::length(input_size);
116 const float translation_amount = diagonal_length * node_storage(bnode()).distance;
118 math::AngleRadian(-node_storage(bnode()).angle));
119 const float2 translation = rotation * float2(-translation_amount / get_iterations(), 0.0f);
120 return translation;
121 }
122
123 /* Get the amount of rotation that will be applied on each iteration. */
125 {
126 return node_storage(bnode()).spin / get_iterations();
127 }
128
129 /* Get the amount of scale that will be applied on each iteration. The scale is identity when the
130 * user supplies 0, so we add 1. */
131 float get_scale()
132 {
133 return node_storage(bnode()).zoom / get_iterations();
134 }
135
137 {
138 const float2 input_size = float2(get_input("Image").domain().size);
139 return float2(node_storage(bnode()).center_x, node_storage(bnode()).center_y) * input_size;
140 }
141
142 /* The actual number of iterations is 2 to the power of the user supplied iterations. The power
143 * is implemented using a bit shift. But also make sure it doesn't exceed the upper limit which
144 * is the number of diagonal pixels. */
146 {
147 const int iterations = 2 << (node_storage(bnode()).iter - 1);
148 const int upper_limit = math::ceil(math::length(float2(get_input("Image").domain().size)));
149 return math::min(iterations, upper_limit);
150 }
151
152 /* Returns true if the operation does nothing and the input can be passed through. */
154 {
155 const Result &input = get_input("Image");
156 /* Single value inputs can't be blurred and are returned as is. */
157 if (input.is_single_value()) {
158 return true;
159 }
160
161 /* If any of the following options are non-zero, then the operation is not an identity. */
162 if (node_storage(bnode()).distance != 0.0f) {
163 return false;
164 }
165
166 if (node_storage(bnode()).spin != 0.0f) {
167 return false;
168 }
169
170 if (node_storage(bnode()).zoom != 0.0f) {
171 return false;
172 }
173
174 return true;
175 }
176};
177
179{
180 return new DirectionalBlurOperation(context, node);
181}
182
183} // namespace blender::nodes::node_composite_directionalblur_cc
184
186{
188
189 static blender::bke::bNodeType ntype;
190
191 cmp_node_type_base(&ntype, CMP_NODE_DBLUR, "Directional Blur", NODE_CLASS_OP_FILTER);
192 ntype.declare = file_ns::cmp_node_directional_blur_declare;
193 ntype.draw_buttons = file_ns::node_composit_buts_dblur;
194 ntype.initfunc = file_ns::node_composit_init_dblur;
197 ntype.get_compositor_operation = file_ns::get_compositor_operation;
198
200}
#define NODE_STORAGE_FUNCS(StorageT)
Definition BKE_node.hh:1799
#define NODE_CLASS_OP_FILTER
Definition BKE_node.hh:408
#define IFACE_(msgid)
void GPU_shader_uniform_2fv(GPUShader *sh, const char *name, const float data[2])
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 GPU_texture_extend_mode(GPUTexture *texture, GPUSamplerExtendMode extend_mode)
@ GPU_SAMPLER_EXTEND_MODE_CLAMP_TO_BORDER
void GPU_texture_filter_mode(GPUTexture *texture, bool use_filter)
void uiItemL(uiLayout *layout, const char *name, int icon)
void uiItemS(uiLayout *layout)
uiLayout * uiLayoutColumn(uiLayout *layout, bool align)
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
static SpinLock spin
Definition cachefile.cc:154
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
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
uint col
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 cos(const AngleRadianBase< T > &a)
T length(const VecBase< T, Size > &a)
T min(const T &a, const T &b)
T ceil(const T &a)
T sin(const AngleRadianBase< T > &a)
MatT from_rotation(const RotationT &rotation)
static void node_composit_buts_dblur(uiLayout *layout, bContext *, PointerRNA *ptr)
static void cmp_node_directional_blur_declare(NodeDeclarationBuilder &b)
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
VecBase< float, 2 > float2
void register_node_type_cmp_dblur()
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
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