Blender V4.3
node_composite_lensdist.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.h"
11
12#include "RNA_access.hh"
13
14#include "UI_interface.hh"
15#include "UI_resources.hh"
16
17#include "GPU_shader.hh"
18#include "GPU_texture.hh"
19
20#include "COM_node_operation.hh"
21#include "COM_utilities.hh"
22
24
25/* Distortion can't be exactly -1.0 as it will cause infinite pincushion distortion. */
26#define MINIMUM_DISTORTION -0.999f
27/* Arbitrary scaling factor for the dispersion input in projector distortion mode. */
28#define PROJECTOR_DISPERSION_SCALE 5.0f
29/* Arbitrary scaling factor for the dispersion input in screen distortion mode. */
30#define SCREEN_DISPERSION_SCALE 4.0f
31/* Arbitrary scaling factor for the distortion input. */
32#define DISTORTION_SCALE 4.0f
33
35
37
39{
40 b.add_input<decl::Color>("Image")
41 .default_value({1.0f, 1.0f, 1.0f, 1.0f})
42 .compositor_domain_priority(0);
43 b.add_input<decl::Float>("Distortion")
44 .default_value(0.0f)
46 .max(1.0f)
48 b.add_input<decl::Float>("Dispersion")
49 .default_value(0.0f)
50 .min(0.0f)
51 .max(1.0f)
53 b.add_output<decl::Color>("Image");
54}
55
56static void node_composit_init_lensdist(bNodeTree * /*ntree*/, bNode *node)
57{
58 NodeLensDist *nld = MEM_cnew<NodeLensDist>(__func__);
59 nld->jit = nld->proj = nld->fit = 0;
60 node->storage = nld;
61}
62
64{
66
67 col = uiLayoutColumn(layout, false);
68 uiItemR(col, ptr, "use_projector", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
69
70 col = uiLayoutColumn(col, false);
71 uiLayoutSetActive(col, RNA_boolean_get(ptr, "use_projector") == false);
72 uiItemR(col, ptr, "use_jitter", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
73 uiItemR(col, ptr, "use_fit", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
74}
75
76using namespace blender::realtime_compositor;
77
79 public:
81
82 void execute() override
83 {
84 if (is_identity()) {
85 get_input("Image").pass_through(get_result("Image"));
86 return;
87 }
88
89 if (get_is_projector()) {
91 }
92 else {
94 }
95 }
96
98 {
99 GPUShader *shader = context().get_shader("compositor_projector_lens_distortion");
100 GPU_shader_bind(shader);
101
102 const Result &input_image = get_input("Image");
103 GPU_texture_filter_mode(input_image, true);
105 input_image.bind_as_texture(shader, "input_tx");
106
107 const Domain domain = compute_domain();
108
109 const float dispersion = (get_dispersion() * PROJECTOR_DISPERSION_SCALE) / domain.size.x;
110 GPU_shader_uniform_1f(shader, "dispersion", dispersion);
111
112 Result &output_image = get_result("Image");
113 output_image.allocate_texture(domain);
114 output_image.bind_as_image(shader, "output_img");
115
116 compute_dispatch_threads_at_least(shader, domain.size);
117
118 input_image.unbind_as_texture();
119 output_image.unbind_as_image();
121 }
122
124 {
126 GPU_shader_bind(shader);
127
128 const Result &input_image = get_input("Image");
129 GPU_texture_filter_mode(input_image, true);
131 input_image.bind_as_texture(shader, "input_tx");
132
133 const Domain domain = compute_domain();
134
135 const float3 chromatic_distortion = compute_chromatic_distortion();
136 GPU_shader_uniform_3fv(shader, "chromatic_distortion", chromatic_distortion);
137
138 GPU_shader_uniform_1f(shader, "scale", compute_scale());
139
140 Result &output_image = get_result("Image");
141 output_image.allocate_texture(domain);
142 output_image.bind_as_image(shader, "output_img");
143
144 compute_dispatch_threads_at_least(shader, domain.size);
145
146 input_image.unbind_as_texture();
147 output_image.unbind_as_image();
149 }
150
152 {
153 if (get_is_jitter()) {
154 return "compositor_screen_lens_distortion_jitter";
155 }
156 return "compositor_screen_lens_distortion";
157 }
158
160 {
161 const Result &input = get_input("Distortion");
162 return clamp_f(input.get_float_value_default(0.0f), MINIMUM_DISTORTION, 1.0f);
163 }
164
166 {
167 const Result &input = get_input("Dispersion");
168 return clamp_f(input.get_float_value_default(0.0f), 0.0f, 1.0f);
169 }
170
171 /* Get the distortion amount for each channel. The green channel has a distortion amount that
172 * matches that specified in the node inputs, while the red and blue channels have higher and
173 * lower distortion amounts respectively based on the dispersion value. */
175 {
176 const float green_distortion = get_distortion();
177 const float dispersion = get_dispersion() / SCREEN_DISPERSION_SCALE;
178 const float red_distortion = clamp_f(green_distortion + dispersion, MINIMUM_DISTORTION, 1.0f);
179 const float blue_distortion = clamp_f(green_distortion - dispersion, MINIMUM_DISTORTION, 1.0f);
180 return float3(red_distortion, green_distortion, blue_distortion) * DISTORTION_SCALE;
181 }
182
183 /* The distortion model will distort the image in such a way that the result will no longer
184 * fit the domain of the original image, so we scale the image to account for that. If get_is_fit
185 * is false, then the scaling factor will be such that the furthest pixels horizontally and
186 * vertically are at the boundary of the image. Otherwise, if get_is_fit is true, the scaling
187 * factor will be such that the furthest pixels diagonally are at the corner of the image. */
189 {
191 const float maximum_distortion = max_fff(distortion[0], distortion[1], distortion[2]);
192
193 if (get_is_fit() && (maximum_distortion > 0.0f)) {
194 return 1.0f / (1.0f + 2.0f * maximum_distortion);
195 }
196 return 1.0f / (1.0f + maximum_distortion);
197 }
198
200 {
201 return node_storage(bnode()).proj;
202 }
203
205 {
206 return node_storage(bnode()).jit;
207 }
208
210 {
211 return node_storage(bnode()).fit;
212 }
213
214 /* Returns true if the operation does nothing and the input can be passed through. */
216 {
217 /* The input is a single value and the operation does nothing. */
218 if (get_input("Image").is_single_value()) {
219 return true;
220 }
221
222 /* Projector have zero dispersion and does nothing. */
223 if (get_is_projector() && get_dispersion() == 0.0f) {
224 return true;
225 }
226
227 /* Both distortion and dispersion are zero and the operation does nothing. Jittering has an
228 * effect regardless, so its gets an exemption. */
229 if (!get_is_jitter() && get_distortion() == 0.0f && get_dispersion() == 0.0f) {
230 return true;
231 }
232
233 return false;
234 }
235};
236
238{
239 return new LensDistortionOperation(context, node);
240}
241
242} // namespace blender::nodes::node_composite_lensdist_cc
243
245{
247
248 static blender::bke::bNodeType ntype;
249
250 cmp_node_type_base(&ntype, CMP_NODE_LENSDIST, "Lens Distortion", NODE_CLASS_DISTORT);
251 ntype.declare = file_ns::cmp_node_lensdist_declare;
252 ntype.draw_buttons = file_ns::node_composit_buts_lensdist;
253 ntype.initfunc = file_ns::node_composit_init_lensdist;
256 ntype.get_compositor_operation = file_ns::get_compositor_operation;
257
259}
#define NODE_STORAGE_FUNCS(StorageT)
Definition BKE_node.hh:1799
#define NODE_CLASS_DISTORT
Definition BKE_node.hh:412
MINLINE float max_fff(float a, float b, float c)
MINLINE float clamp_f(float value, float min, float max)
void GPU_shader_uniform_1f(GPUShader *sh, const char *name, float value)
void GPU_shader_uniform_3fv(GPUShader *sh, const char *name, const float data[3])
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 uiLayoutSetActive(uiLayout *layout, bool active)
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
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
static void node_composit_buts_lensdist(uiLayout *layout, bContext *, PointerRNA *ptr)
static NodeOperation * get_compositor_operation(Context &context, DNode node)
static void cmp_node_lensdist_declare(NodeDeclarationBuilder &b)
static void node_composit_init_lensdist(bNodeTree *, bNode *node)
void compute_dispatch_threads_at_least(GPUShader *shader, int2 threads_range, int2 local_size=int2(16))
Definition utilities.cc:131
VecBase< float, 3 > float3
void register_node_type_cmp_lensdist()
#define DISTORTION_SCALE
#define SCREEN_DISPERSION_SCALE
#define MINIMUM_DISTORTION
#define PROJECTOR_DISPERSION_SCALE
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
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
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