Blender V4.3
COM_BokehBlurOperation.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 "BLI_math_vector.h"
6#include "BLI_math_vector.hh"
7
10
11namespace blender::compositor {
12
13constexpr int IMAGE_INPUT_INDEX = 0;
14constexpr int BOKEH_INPUT_INDEX = 1;
15constexpr int BOUNDING_BOX_INPUT_INDEX = 2;
16constexpr int SIZE_INPUT_INDEX = 3;
17
19{
25
27
28 size_ = 1.0f;
29 sizeavailable_ = false;
30
31 extend_bounds_ = false;
32}
33
35{
36 update_size();
37}
38
39void BokehBlurOperation::update_size()
40{
41 if (sizeavailable_) {
42 return;
43 }
44
46 if (size_input->get_flags().is_constant_operation) {
47 size_ = *static_cast<ConstantOperation *>(size_input)->get_constant_elem();
48 CLAMP(size_, 0.0f, 10.0f);
49 } /* Else use default. */
50 sizeavailable_ = true;
51}
52
53void BokehBlurOperation::determine_canvas(const rcti &preferred_area, rcti &r_area)
54{
55 if (!extend_bounds_) {
56 NodeOperation::determine_canvas(preferred_area, r_area);
57 return;
58 }
59
61 const float max_dim = std::max(BLI_rcti_size_x(&canvas), BLI_rcti_size_y(&canvas));
62 /* Rounding to even prevents image jiggling in backdrop while switching size values. */
63 float add_size = round_to_even(2 * size_ * max_dim / 100.0f);
64 canvas.xmax += add_size;
65 canvas.ymax += add_size;
66 });
67 NodeOperation::determine_canvas(preferred_area, r_area);
68}
69
71 const rcti &output_area,
72 rcti &r_input_area)
73{
74 switch (input_idx) {
75 case IMAGE_INPUT_INDEX: {
76 const float max_dim = std::max(this->get_width(), this->get_height());
77 const float add_size = size_ * max_dim / 100.0f;
78 r_input_area.xmin = output_area.xmin - add_size;
79 r_input_area.xmax = output_area.xmax + add_size;
80 r_input_area.ymin = output_area.ymin - add_size;
81 r_input_area.ymax = output_area.ymax + add_size;
82 break;
83 }
84 case BOKEH_INPUT_INDEX: {
86 r_input_area = bokeh_input->get_canvas();
87 break;
88 }
90 r_input_area = output_area;
91 break;
92 case SIZE_INPUT_INDEX: {
94 break;
95 }
96 }
97}
98
100 const rcti &area,
102{
103 const float max_dim = std::max(this->get_width(), this->get_height());
104 const int radius = size_ * max_dim / 100.0f;
105
106 const MemoryBuffer *image_input = inputs[IMAGE_INPUT_INDEX];
107 const MemoryBuffer *bokeh_input = inputs[BOKEH_INPUT_INDEX];
108 const int2 bokeh_size = int2(bokeh_input->get_width(), bokeh_input->get_height());
109 MemoryBuffer *bounding_input = inputs[BOUNDING_BOX_INPUT_INDEX];
110 BuffersIterator<float> it = output->iterate_with({bounding_input}, area);
111 for (; !it.is_end(); ++it) {
112 const int x = it.x;
113 const int y = it.y;
114 const float bounding_box = *it.in(0);
115 if (bounding_box <= 0.0f) {
116 image_input->read_elem(x, y, it.out);
117 continue;
118 }
119
120 float4 accumulated_color = float4(0.0f);
121 float4 accumulated_weight = float4(0.0f);
122 for (int yi = -radius; yi <= radius; ++yi) {
123 for (int xi = -radius; xi <= radius; ++xi) {
124 const float2 normalized_texel = (float2(xi, yi) + radius + 0.5f) / (radius * 2.0f + 1.0f);
125 const float2 weight_texel = (1.0f - normalized_texel) * float2(bokeh_size - 1);
126 const float4 weight = bokeh_input->get_elem(int(weight_texel.x), int(weight_texel.y));
127 const float4 color = float4(image_input->get_elem_clamped(x + xi, y + yi)) * weight;
128 accumulated_color += color;
129 accumulated_weight += weight;
130 }
131 }
132
133 const float4 final_color = math::safe_divide(accumulated_color, accumulated_weight);
134 copy_v4_v4(it.out, final_color);
135 }
136}
137
138} // namespace blender::compositor
MINLINE float round_to_even(float f)
MINLINE void copy_v4_v4(float r[4], const float a[4])
BLI_INLINE int BLI_rcti_size_y(const struct rcti *rct)
Definition BLI_rect.h:193
BLI_INLINE int BLI_rcti_size_x(const struct rcti *rct)
Definition BLI_rect.h:189
#define CLAMP(a, b, c)
void update_memory_buffer_partial(MemoryBuffer *output, const rcti &area, Span< MemoryBuffer * > inputs) override
void determine_canvas(const rcti &preferred_area, rcti &r_area) 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
const int get_width() const
get the width of this MemoryBuffer
const int get_height() const
get the height of this MemoryBuffer
void read_elem(int x, int y, float *out) const
BuffersIterator< float > iterate_with(Span< MemoryBuffer * > inputs)
NodeOperation contains calculation logic.
void add_output_socket(DataType datatype)
NodeOperation * get_input_operation(int index)
void set_determined_canvas_modifier(std::function< void(rcti &canvas)> fn)
void add_input_socket(DataType datatype, ResizeMode resize_mode=ResizeMode::Center)
virtual void determine_canvas(const rcti &preferred_area, rcti &r_area)
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
constexpr int BOUNDING_BOX_INPUT_INDEX
constexpr rcti COM_CONSTANT_INPUT_AREA_OF_INTEREST
Definition COM_defines.h:90
typename BuffersIteratorBuilder< T >::Iterator BuffersIterator
T safe_divide(const T &a, const T &b)
VecBase< float, 4 > float4
VecBase< int32_t, 2 > int2
VecBase< float, 2 > float2
int ymin
int ymax
int xmin
int xmax