Blender V4.3
COM_ScreenLensDistortionOperation.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
6
8
9#include "BLI_rand.h"
10#include "BLI_time.h"
11
12namespace blender::compositor {
13
15{
21 distortion_ = 0.0f;
22 dispersion_ = 0.0f;
23 distortion_const_ = false;
24 dispersion_const_ = false;
25 variables_ready_ = false;
26}
27
29{
30 distortion_ = distortion;
31 distortion_const_ = true;
32}
33
35{
36 dispersion_ = dispersion;
37 dispersion_const_ = true;
38}
39
41{
42 cx_ = 0.5f * float(get_width());
43 cy_ = 0.5f * float(get_height());
44
45 NodeOperation *distortion_op = get_input_operation(1);
46 NodeOperation *dispersion_op = get_input_operation(2);
47 if (!distortion_const_ && distortion_op->get_flags().is_constant_operation) {
48 distortion_ = static_cast<ConstantOperation *>(distortion_op)->get_constant_elem()[0];
49 }
50 if (!dispersion_const_ && distortion_op->get_flags().is_constant_operation) {
51 dispersion_ = static_cast<ConstantOperation *>(dispersion_op)->get_constant_elem()[0];
52 }
53 update_variables(distortion_, dispersion_);
54}
55
57{
58 SocketReader *input_reader = this->get_input_socket_reader(0);
59
61 rng_seed ^= uint(POINTER_AS_INT(input_reader));
62 rng_ = BLI_rng_new(rng_seed);
63}
64
65void ScreenLensDistortionOperation::get_uv(const float xy[2], float uv[2]) const
66{
67 uv[0] = sc_ * ((xy[0] + 0.5f) - cx_) / cx_;
68 uv[1] = sc_ * ((xy[1] + 0.5f) - cy_) / cy_;
69}
70
71void ScreenLensDistortionOperation::distort_uv(const float uv[2], float t, float xy[2]) const
72{
73 float d = 1.0f / (1.0f + sqrtf(t));
74 xy[0] = (uv[0] * d + 0.5f) * get_width() - 0.5f;
75 xy[1] = (uv[1] * d + 0.5f) * get_height() - 0.5f;
76}
77
78bool ScreenLensDistortionOperation::get_delta(float r_sq,
79 float k4,
80 const float uv[2],
81 float delta[2]) const
82{
83 float t = 1.0f - k4 * r_sq;
84 if (t >= 0.0f) {
85 distort_uv(uv, t, delta);
86 return true;
87 }
88
89 return false;
90}
91
92void ScreenLensDistortionOperation::accumulate(const MemoryBuffer *buffer,
93 int a,
94 int b,
95 float r_sq,
96 const float uv[2],
97 const float delta[3][2],
98 float sum[4],
99 int count[3]) const
100{
101 float color[4];
102
103 float dsf = len_v2v2(delta[a], delta[b]) + 1.0f;
104 int ds = jitter_ ? (dsf < 4.0f ? 2 : int(sqrtf(dsf))) : int(dsf);
105 float sd = 1.0f / float(ds);
106
107 float k4 = k4_[a];
108 float dk4 = dk4_[a];
109
110 for (float z = 0; z < ds; z++) {
111 float tz = (z + (jitter_ ? BLI_rng_get_float(rng_) : 0.5f)) * sd;
112 float t = 1.0f - (k4 + tz * dk4) * r_sq;
113
114 float xy[2];
115 distort_uv(uv, t, xy);
116 buffer->read_elem_bilinear(xy[0], xy[1], color);
117
118 sum[a] += (1.0f - tz) * color[a];
119 sum[b] += (tz)*color[b];
120 count[a]++;
121 count[b]++;
122 }
123}
124
129
130void ScreenLensDistortionOperation::determineUV(float result[6], float x, float y) const
131{
132 const float xy[2] = {x, y};
133 float uv[2];
134 get_uv(xy, uv);
135 float uv_dot = len_squared_v2(uv);
136
137 copy_v2_v2(result + 0, xy);
138 copy_v2_v2(result + 2, xy);
139 copy_v2_v2(result + 4, xy);
140 get_delta(uv_dot, k4_[0], uv, result + 0);
141 get_delta(uv_dot, k4_[1], uv, result + 2);
142 get_delta(uv_dot, k4_[2], uv, result + 4);
143}
144
145void ScreenLensDistortionOperation::update_variables(float distortion, float dispersion)
146{
147 k_[1] = max_ff(min_ff(distortion, 1.0f), -0.999f);
148 /* Smaller dispersion range for somewhat more control. */
149 float d = 0.25f * max_ff(min_ff(dispersion, 1.0f), 0.0f);
150 k_[0] = max_ff(min_ff((k_[1] + d), 1.0f), -0.999f);
151 k_[2] = max_ff(min_ff((k_[1] - d), 1.0f), -0.999f);
152 maxk_ = max_fff(k_[0], k_[1], k_[2]);
153 sc_ = (fit_ && (maxk_ > 0.0f)) ? (1.0f / (1.0f + 2.0f * maxk_)) : (1.0f / (1.0f + maxk_));
154 dk4_[0] = 4.0f * (k_[1] - k_[0]);
155 dk4_[1] = 4.0f * (k_[2] - k_[1]);
156 dk4_[2] = 0.0f; /* unused */
157
158 mul_v3_v3fl(k4_, k_, 4.0f);
159}
160
162{
164 /* Ensure screen space. */
165 BLI_rcti_translate(&canvas, -canvas.xmin, -canvas.ymin);
166 });
167
168 NodeOperation::determine_canvas(preferred_area, r_area);
169}
170
172 const rcti & /*output_area*/,
173 rcti &r_input_area)
174{
175 if (input_idx != 0) {
176 /* Dispersion and distortion inputs are used as constants only. */
178 }
179
180 /* XXX the original method of estimating the area-of-interest does not work
181 * it assumes a linear increase/decrease of mapped coordinates, which does not
182 * yield correct results for the area and leaves uninitialized buffer areas.
183 * So now just use the full image area, which may not be as efficient but works at least ...
184 */
186 r_input_area = image->get_canvas();
187}
188
190 const rcti &area,
192{
193 const MemoryBuffer *input_image = inputs[0];
194 if (input_image->is_a_single_elem()) {
195 copy_v4_v4(output->get_elem(0, 0), input_image->get_elem(0, 0));
196 return;
197 }
198 for (BuffersIterator<float> it = output->iterate_with({}, area); !it.is_end(); ++it) {
199 float xy[2] = {float(it.x), float(it.y)};
200 float uv[2];
201 get_uv(xy, uv);
202 const float uv_dot = len_squared_v2(uv);
203
204 float delta[3][2];
205 const bool valid_r = get_delta(uv_dot, k4_[0], uv, delta[0]);
206 const bool valid_g = get_delta(uv_dot, k4_[1], uv, delta[1]);
207 const bool valid_b = get_delta(uv_dot, k4_[2], uv, delta[2]);
208 if (!(valid_r && valid_g && valid_b)) {
209 zero_v4(it.out);
210 continue;
211 }
212
213 int count[3] = {0, 0, 0};
214 float sum[4] = {0, 0, 0, 0};
215 accumulate(input_image, 0, 1, uv_dot, uv, delta, sum, count);
216 accumulate(input_image, 1, 2, uv_dot, uv, delta, sum, count);
217
218 if (count[0]) {
219 it.out[0] = 2.0f * sum[0] / float(count[0]);
220 }
221 if (count[1]) {
222 it.out[1] = 2.0f * sum[1] / float(count[1]);
223 }
224 if (count[2]) {
225 it.out[2] = 2.0f * sum[2] / float(count[2]);
226 }
227
228 /* Set alpha. */
229 it.out[3] = 1.0f;
230 }
231}
232
233} // namespace blender::compositor
MINLINE float max_fff(float a, float b, float c)
MINLINE float max_ff(float a, float b)
MINLINE float min_ff(float a, float b)
MINLINE void copy_v4_v4(float r[4], const float a[4])
MINLINE float len_squared_v2(const float v[2]) ATTR_WARN_UNUSED_RESULT
MINLINE float len_v2v2(const float v1[2], const float v2[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void zero_v4(float r[4])
MINLINE void mul_v3_v3fl(float r[3], const float a[3], float f)
Random number functions.
struct RNG * BLI_rng_new(unsigned int seed)
Definition rand.cc:39
void BLI_rng_free(struct RNG *rng) ATTR_NONNULL(1)
Definition rand.cc:58
float BLI_rng_get_float(struct RNG *rng) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition rand.cc:93
void BLI_rcti_translate(struct rcti *rect, int x, int y)
Definition rct.c:560
unsigned int uint
Platform independent time functions.
long int BLI_time_now_seconds_i(void)
Definition time.c:75
#define POINTER_AS_INT(i)
SIMD_FORCE_INLINE const btScalar & z() const
Return the z value.
Definition btQuadWord.h:117
static T sum(const btAlignedObjectArray< T > &items)
a MemoryBuffer contains access to the data
NodeOperation contains calculation logic.
void add_output_socket(DataType datatype)
const NodeOperationFlags get_flags() const
SocketReader * get_input_socket_reader(unsigned int index)
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)
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.
void determine_canvas(const rcti &preferred_area, rcti &r_area) override
local_group_size(16, 16) .push_constant(Type b
#define sqrtf(x)
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
#define UINT_MAX
Definition hash_md5.cc:44
int count
constexpr rcti COM_CONSTANT_INPUT_AREA_OF_INTEREST
Definition COM_defines.h:90
typename BuffersIteratorBuilder< T >::Iterator BuffersIterator
int ymin
int xmin
int xy[2]
Definition wm_draw.cc:170