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{
20 flags_.can_be_constant = true;
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)
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Brightness Control the brightness and contrast of the input color Vector Map input vector components with curves Camera Retrieve information about the camera and how it relates to the current shading point s position Clamp a value between a minimum and a maximum Vector Perform vector math operation Invert Invert a color
#define output
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
input_tx image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "preview_img") .compute_source("compositor_compute_preview.glsl") .do_static_compilation(true)
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
NodeOperation SocketReader
typename BuffersIteratorBuilder< T >::Iterator BuffersIterator
static blender::bke::bNodeSocketTemplate inputs[]
int ymin
int xmin
int xy[2]
Definition wm_draw.cc:170