Blender V4.3
COM_GaussianBokehBlurOperation.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2011 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include <memory>
6
7#include "BLI_index_range.hh"
8#include "BLI_math_vector.hh"
9
11
12#include "RE_pipeline.h"
13
14namespace blender::compositor {
15
20
22{
24 const float width = this->get_width();
25 const float height = this->get_height();
26
27 if (!sizeavailable_) {
29 }
30
31 radxf_ = size_ * float(data_.sizex);
32 CLAMP(radxf_, 0.0f, width / 2.0f);
33
34 /* Vertical. */
35 radyf_ = size_ * float(data_.sizey);
36 CLAMP(radyf_, 0.0f, height / 2.0f);
37
38 radx_ = ceil(radxf_);
39 rady_ = ceil(radyf_);
40}
41
50
51void GaussianBokehBlurOperation::update_gauss()
52{
53 if (gausstab_ == nullptr) {
54 int ddwidth = 2 * radx_ + 1;
55 int ddheight = 2 * rady_ + 1;
56 int n = ddwidth * ddheight;
57 /* create a full filter image */
58 float *ddgauss = (float *)MEM_mallocN(sizeof(float) * n, __func__);
59 float *dgauss = ddgauss;
60 float sum = 0.0f;
61 float facx = (radxf_ > 0.0f ? 1.0f / radxf_ : 0.0f);
62 float facy = (radyf_ > 0.0f ? 1.0f / radyf_ : 0.0f);
63 for (int j = -rady_; j <= rady_; j++) {
64 for (int i = -radx_; i <= radx_; i++, dgauss++) {
65 float fj = float(j) * facy;
66 float fi = float(i) * facx;
67 float dist = sqrt(fj * fj + fi * fi);
68 *dgauss = RE_filter_value(data_.filtertype, dist);
69
70 sum += *dgauss;
71 }
72 }
73
74 if (sum > 0.0f) {
75 /* normalize */
76 float norm = 1.0f / sum;
77 for (int j = n - 1; j >= 0; j--) {
78 ddgauss[j] *= norm;
79 }
80 }
81 else {
82 int center = rady_ * ddwidth + radx_;
83 ddgauss[center] = 1.0f;
84 }
85
86 gausstab_ = ddgauss;
87 }
88}
89
91{
93
94 if (gausstab_) {
95 MEM_freeN(gausstab_);
96 gausstab_ = nullptr;
97 }
98}
99
101 const rcti &output_area,
102 rcti &r_input_area)
103{
104 if (input_idx != IMAGE_INPUT_INDEX) {
105 BlurBaseOperation::get_area_of_interest(input_idx, output_area, r_input_area);
106 return;
107 }
108
109 r_input_area.xmax = output_area.xmax + radx_;
110 r_input_area.xmin = output_area.xmin - radx_;
111 r_input_area.ymax = output_area.ymax + rady_;
112 r_input_area.ymin = output_area.ymin - rady_;
113}
114
116 const rcti &area,
118{
119 const MemoryBuffer *input = inputs[IMAGE_INPUT_INDEX];
120 BuffersIterator<float> it = output->iterate_with({}, area);
121 const rcti &input_rect = input->get_rect();
122 for (; !it.is_end(); ++it) {
123 const int x = it.x;
124 const int y = it.y;
125
126 const int ymin = max_ii(y - rady_, input_rect.ymin);
127 const int ymax = min_ii(y + rady_ + 1, input_rect.ymax);
128 const int xmin = max_ii(x - radx_, input_rect.xmin);
129 const int xmax = min_ii(x + radx_ + 1, input_rect.xmax);
130
131 float temp_color[4] = {0};
132 float multiplier_accum = 0;
133 const int elem_step = input->elem_stride;
134 const int add_const = (xmin - x + radx_);
135 const int mul_const = (radx_ * 2 + 1);
136 for (int ny = ymin; ny < ymax; ++ny) {
137 const float *color = input->get_elem(xmin, ny);
138 int gauss_index = ((ny - y) + rady_) * mul_const + add_const;
139 const int gauss_end = gauss_index + (xmax - xmin);
140 for (; gauss_index < gauss_end; gauss_index += 1, color += elem_step) {
141 const float multiplier = gausstab_[gauss_index];
142 madd_v4_v4fl(temp_color, color, multiplier);
143 multiplier_accum += multiplier;
144 }
145 }
146
147 mul_v4_v4fl(it.out, temp_color, 1.0f / multiplier_accum);
148 }
149}
150
151// reference image
158
160{
161 /* Setup variables for gausstab and area of interest. */
164 if (data_.relative) {
165 switch (data_.aspect) {
169 break;
173 break;
177 break;
178 }
179 }
180
181 /* Horizontal. */
182 filtersizex_ = float(data_.sizex);
183 int imgx = get_width() / 2;
184 if (filtersizex_ > imgx) {
185 filtersizex_ = imgx;
186 }
187 else if (filtersizex_ < 1) {
188 filtersizex_ = 1;
189 }
190 radx_ = float(filtersizex_);
191
192 /* Vertical. */
193 filtersizey_ = float(data_.sizey);
194 int imgy = get_height() / 2;
195 if (filtersizey_ > imgy) {
196 filtersizey_ = imgy;
197 }
198 else if (filtersizey_ < 1) {
199 filtersizey_ = 1;
200 }
201 rady_ = float(filtersizey_);
202}
203
210
211void GaussianBlurReferenceOperation::update_gauss()
212{
213 const int2 radius = int2(filtersizex_, filtersizey_);
214 const float2 scale = math::safe_divide(float2(1.0f), float2(radius));
215 const int2 size = radius + int2(1);
216
217 rcti weights_area;
218 BLI_rcti_init(&weights_area, 0, size.x, 0, size.y);
219 weights_ = std::make_unique<MemoryBuffer>(DataType::Value, weights_area, false);
220
221 float sum = 0.0f;
222
223 const float center_weight = RE_filter_value(data_.filtertype, 0.0f);
224 *weights_->get_elem(0, 0) = center_weight;
225 sum += center_weight;
226
227 for (const int x : IndexRange(size.x).drop_front(1)) {
228 const float weight = RE_filter_value(data_.filtertype, x * scale.x);
229 *weights_->get_elem(x, 0) = weight;
230 sum += weight * 2.0f;
231 }
232
233 for (const int y : IndexRange(size.y).drop_front(1)) {
234 const float weight = RE_filter_value(data_.filtertype, y * scale.y);
235 *weights_->get_elem(0, y) = weight;
236 sum += weight * 2.0f;
237 }
238
239 for (const int y : IndexRange(size.y).drop_front(1)) {
240 for (const int x : IndexRange(size.x).drop_front(1)) {
241 const float weight = RE_filter_value(data_.filtertype, math::length(float2(x, y) * scale));
242 *weights_->get_elem(x, y) = weight;
243 sum += weight * 4.0f;
244 }
245 }
246
247 for (const int y : IndexRange(size.y)) {
248 for (const int x : IndexRange(size.x)) {
249 *weights_->get_elem(x, y) /= sum;
250 }
251 }
252}
253
255 const rcti &output_area,
256 rcti &r_input_area)
257{
258 if (input_idx != IMAGE_INPUT_INDEX) {
259 BlurBaseOperation::get_area_of_interest(input_idx, output_area, r_input_area);
260 return;
261 }
262
263 const int add_x = data_.sizex + 2;
264 const int add_y = data_.sizey + 2;
265 r_input_area.xmax = output_area.xmax + add_x;
266 r_input_area.xmin = output_area.xmin - add_x;
267 r_input_area.ymax = output_area.ymax + add_y;
268 r_input_area.ymin = output_area.ymin - add_y;
269}
270
272 const rcti &area,
274{
275 const MemoryBuffer *size_input = inputs[SIZE_INPUT_INDEX];
276 const MemoryBuffer *image_input = inputs[IMAGE_INPUT_INDEX];
277
278 int2 weights_size = int2(weights_->get_width(), weights_->get_height());
279 int2 base_radius = weights_size - int2(1);
280
281 for (BuffersIterator<float> it = output->iterate_with({}, area); !it.is_end(); ++it) {
282 float4 accumulated_color = float4(0.0f);
283 float4 accumulated_weight = float4(0.0f);
284
285 int2 radius = int2(math::ceil(float2(base_radius) * *size_input->get_elem(it.x, it.y)));
286
287 float4 center_color = float4(image_input->get_elem_clamped(it.x, it.y));
288 float center_weight = *weights_->get_elem(0, 0);
289 accumulated_color += center_color * center_weight;
290 accumulated_weight += center_weight;
291
292 for (int x = 1; x <= radius.x; x++) {
293 float weight_coordinates = (x / float(radius.x)) * base_radius.x;
294 float weight;
295 weights_->read_elem_bilinear(weight_coordinates, 0.0f, &weight);
296 accumulated_color += float4(image_input->get_elem_clamped(it.x + x, it.y)) * weight;
297 accumulated_color += float4(image_input->get_elem_clamped(it.x - x, it.y)) * weight;
298 accumulated_weight += weight * 2.0f;
299 }
300
301 for (int y = 1; y <= radius.y; y++) {
302 float weight_coordinates = (y / float(radius.y)) * base_radius.y;
303 float weight;
304 weights_->read_elem_bilinear(0.0f, weight_coordinates, &weight);
305 accumulated_color += float4(image_input->get_elem_clamped(it.x, it.y + y)) * weight;
306 accumulated_color += float4(image_input->get_elem_clamped(it.x, it.y - y)) * weight;
307 accumulated_weight += weight * 2.0f;
308 }
309
310 for (int y = 1; y <= radius.y; y++) {
311 for (int x = 1; x <= radius.x; x++) {
312 float2 weight_coordinates = (float2(x, y) / float2(radius)) * float2(base_radius);
313 float weight;
314 weights_->read_elem_bilinear(weight_coordinates.x, weight_coordinates.y, &weight);
315 accumulated_color += float4(image_input->get_elem_clamped(it.x + x, it.y + y)) * weight;
316 accumulated_color += float4(image_input->get_elem_clamped(it.x - x, it.y + y)) * weight;
317 accumulated_color += float4(image_input->get_elem_clamped(it.x + x, it.y - y)) * weight;
318 accumulated_color += float4(image_input->get_elem_clamped(it.x - x, it.y - y)) * weight;
319 accumulated_weight += weight * 4.0f;
320 }
321 }
322
323 accumulated_color = math::safe_divide(accumulated_color, accumulated_weight);
324 copy_v4_v4(it.out, accumulated_color);
325 }
326}
327
328} // namespace blender::compositor
sqrt(x)+1/max(0
MINLINE int min_ii(int a, int b)
MINLINE int max_ii(int a, int b)
MINLINE void copy_v4_v4(float r[4], const float a[4])
MINLINE void mul_v4_v4fl(float r[4], const float a[4], float f)
MINLINE void madd_v4_v4fl(float r[4], const float a[4], float f)
void BLI_rcti_init(struct rcti *rect, int xmin, int xmax, int ymin, int ymax)
Definition rct.c:418
#define CLAMP(a, b, c)
@ CMP_NODE_BLUR_ASPECT_NONE
@ CMP_NODE_BLUR_ASPECT_X
@ CMP_NODE_BLUR_ASPECT_Y
static T sum(const btAlignedObjectArray< T > &items)
SIMD_FORCE_INLINE btScalar norm() const
Return the norm (length) of the vector.
Definition btVector3.h:263
virtual void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override
Get input operation area being read by this operation on rendering given output area.
void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override
Get input operation area being read by this operation on rendering given output area.
void update_memory_buffer_partial(MemoryBuffer *output, const rcti &area, Span< MemoryBuffer * > inputs) override
void update_memory_buffer_partial(MemoryBuffer *output, const rcti &area, Span< MemoryBuffer * > inputs) override
void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override
Get input operation area being read by this operation on rendering given output area.
a MemoryBuffer contains access to the data
const float * get_elem_clamped(int x, int y) const
BuffersIterator< float > iterate_with(Span< MemoryBuffer * > inputs)
draw_view in_light_buf[] float
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
DataType
possible data types for sockets
Definition COM_defines.h:21
float RE_filter_value(int type, float x)
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
ccl_device_inline float3 ceil(const float3 a)
typename BuffersIteratorBuilder< T >::Iterator BuffersIterator
T safe_divide(const T &a, const T &b)
T length(const VecBase< T, Size > &a)
T ceil(const T &a)
VecBase< float, 4 > float4
VecBase< int32_t, 2 > int2
VecBase< float, 2 > float2
int ymin
int ymax
int xmin
int xmax