Blender  V3.3
COM_MapUVOperation.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2011 Blender Foundation. */
3 
4 #include "COM_MapUVOperation.h"
5 
6 namespace blender::compositor {
7 
9 {
13  alpha_ = 0.0f;
14  flags_.complex = true;
15  set_canvas_input_index(UV_INPUT_INDEX);
16 
17  inputUVProgram_ = nullptr;
18  input_color_program_ = nullptr;
19 }
20 
22 {
23  NodeOperation *image_input = get_input_operation(IMAGE_INPUT_INDEX);
24  image_width_ = image_input->get_width();
25  image_height_ = image_input->get_height();
26 
27  NodeOperation *uv_input = get_input_operation(UV_INPUT_INDEX);
28  uv_width_ = uv_input->get_width();
29  uv_height_ = uv_input->get_height();
30 }
31 
33 {
34  input_color_program_ = this->get_input_socket_reader(0);
35  inputUVProgram_ = this->get_input_socket_reader(1);
37  uv_input_read_fn_ = [=](float x, float y, float *out) {
38  inputUVProgram_->read_sampled(out, x, y, PixelSampler::Bilinear);
39  };
40  }
41 }
42 
44  float x,
45  float y,
46  PixelSampler /*sampler*/)
47 {
48  float xy[2] = {x, y};
49  float uv[2], deriv[2][2], alpha;
50 
51  pixel_transform(xy, uv, deriv, alpha);
52  if (alpha == 0.0f) {
53  zero_v4(output);
54  return;
55  }
56 
57  /* EWA filtering */
58  input_color_program_->read_filtered(output, uv[0], uv[1], deriv[0], deriv[1]);
59 
60  /* UV to alpha threshold */
61  const float threshold = alpha_ * 0.05f;
62  /* XXX alpha threshold is used to fade out pixels on boundaries with invalid derivatives.
63  * this calculation is not very well defined, should be looked into if it becomes a problem ...
64  */
65  float du = len_v2(deriv[0]);
66  float dv = len_v2(deriv[1]);
67  float factor = 1.0f - threshold * (du / input_color_program_->get_width() +
68  dv / input_color_program_->get_height());
69  if (factor < 0.0f) {
70  alpha = 0.0f;
71  }
72  else {
73  alpha *= factor;
74  }
75 
76  /* "premul" */
77  if (alpha < 1.0f) {
78  mul_v4_fl(output, alpha);
79  }
80 }
81 
82 bool MapUVOperation::read_uv(float x, float y, float &r_u, float &r_v, float &r_alpha)
83 {
84  if (x < 0.0f || x >= uv_width_ || y < 0.0f || y >= uv_height_) {
85  r_u = 0.0f;
86  r_v = 0.0f;
87  r_alpha = 0.0f;
88  return false;
89  }
90 
91  float vector[3];
92  uv_input_read_fn_(x, y, vector);
93  r_u = vector[0] * image_width_;
94  r_v = vector[1] * image_height_;
95  r_alpha = vector[2];
96  return true;
97 }
98 
99 void MapUVOperation::pixel_transform(const float xy[2],
100  float r_uv[2],
101  float r_deriv[2][2],
102  float &r_alpha)
103 {
104  float uv[2], alpha; /* temporary variables for derivative estimation */
105  int num;
106 
107  read_uv(xy[0], xy[1], r_uv[0], r_uv[1], r_alpha);
108 
109  /* Estimate partial derivatives using 1-pixel offsets */
110  const float epsilon[2] = {1.0f, 1.0f};
111 
112  zero_v2(r_deriv[0]);
113  zero_v2(r_deriv[1]);
114 
115  num = 0;
116  if (read_uv(xy[0] + epsilon[0], xy[1], uv[0], uv[1], alpha)) {
117  r_deriv[0][0] += uv[0] - r_uv[0];
118  r_deriv[1][0] += uv[1] - r_uv[1];
119  num++;
120  }
121  if (read_uv(xy[0] - epsilon[0], xy[1], uv[0], uv[1], alpha)) {
122  r_deriv[0][0] += r_uv[0] - uv[0];
123  r_deriv[1][0] += r_uv[1] - uv[1];
124  num++;
125  }
126  if (num > 0) {
127  float numinv = 1.0f / (float)num;
128  r_deriv[0][0] *= numinv;
129  r_deriv[1][0] *= numinv;
130  }
131 
132  num = 0;
133  if (read_uv(xy[0], xy[1] + epsilon[1], uv[0], uv[1], alpha)) {
134  r_deriv[0][1] += uv[0] - r_uv[0];
135  r_deriv[1][1] += uv[1] - r_uv[1];
136  num++;
137  }
138  if (read_uv(xy[0], xy[1] - epsilon[1], uv[0], uv[1], alpha)) {
139  r_deriv[0][1] += r_uv[0] - uv[0];
140  r_deriv[1][1] += r_uv[1] - uv[1];
141  num++;
142  }
143  if (num > 0) {
144  float numinv = 1.0f / (float)num;
145  r_deriv[0][1] *= numinv;
146  r_deriv[1][1] *= numinv;
147  }
148 }
149 
151 {
152  inputUVProgram_ = nullptr;
153  input_color_program_ = nullptr;
154 }
155 
157  ReadBufferOperation *read_operation,
158  rcti *output)
159 {
160  rcti color_input;
161  rcti uv_input;
162  NodeOperation *operation = nullptr;
163 
164  /* the uv buffer only needs a 3x3 buffer. The image needs whole buffer */
165 
166  operation = get_input_operation(0);
167  color_input.xmax = operation->get_width();
168  color_input.xmin = 0;
169  color_input.ymax = operation->get_height();
170  color_input.ymin = 0;
171  if (operation->determine_depending_area_of_interest(&color_input, read_operation, output)) {
172  return true;
173  }
174 
175  operation = get_input_operation(1);
176  uv_input.xmax = input->xmax + 1;
177  uv_input.xmin = input->xmin - 1;
178  uv_input.ymax = input->ymax + 1;
179  uv_input.ymin = input->ymin - 1;
180  if (operation->determine_depending_area_of_interest(&uv_input, read_operation, output)) {
181  return true;
182  }
183 
184  return false;
185 }
186 
187 void MapUVOperation::get_area_of_interest(const int input_idx,
188  const rcti &output_area,
189  rcti &r_input_area)
190 {
191  switch (input_idx) {
192  case IMAGE_INPUT_INDEX: {
193  r_input_area = get_input_operation(IMAGE_INPUT_INDEX)->get_canvas();
194  break;
195  }
196  case UV_INPUT_INDEX: {
197  r_input_area = output_area;
199  break;
200  }
201  }
202 }
203 
205  const rcti &UNUSED(area),
207 {
208  const MemoryBuffer *uv_input = inputs[UV_INPUT_INDEX];
209  uv_input_read_fn_ = [=](float x, float y, float *out) {
210  uv_input->read_elem_bilinear(x, y, out);
211  };
212 }
213 
215  const rcti &area,
217 {
218  const MemoryBuffer *input_image = inputs[IMAGE_INPUT_INDEX];
219  for (BuffersIterator<float> it = output->iterate_with({}, area); !it.is_end(); ++it) {
220  float xy[2] = {(float)it.x, (float)it.y};
221  float uv[2];
222  float deriv[2][2];
223  float alpha;
224  pixel_transform(xy, uv, deriv, alpha);
225  if (alpha == 0.0f) {
226  zero_v4(it.out);
227  continue;
228  }
229 
230  /* EWA filtering. */
231  input_image->read_elem_filtered(uv[0], uv[1], deriv[0], deriv[1], it.out);
232 
233  /* UV to alpha threshold. */
234  const float threshold = alpha_ * 0.05f;
235  /* XXX alpha threshold is used to fade out pixels on boundaries with invalid derivatives.
236  * this calculation is not very well defined, should be looked into if it becomes a problem ...
237  */
238  const float du = len_v2(deriv[0]);
239  const float dv = len_v2(deriv[1]);
240  const float factor = 1.0f - threshold * (du / image_width_ + dv / image_height_);
241  if (factor < 0.0f) {
242  alpha = 0.0f;
243  }
244  else {
245  alpha *= factor;
246  }
247 
248  /* "premul" */
249  if (alpha < 1.0f) {
250  mul_v4_fl(it.out, alpha);
251  }
252  }
253 }
254 
255 } // namespace blender::compositor
typedef float(TangentPoint)[2]
MINLINE void mul_v4_fl(float r[4], float f)
MINLINE void zero_v4(float r[4])
MINLINE void zero_v2(float r[2])
MINLINE float len_v2(const float a[2]) ATTR_WARN_UNUSED_RESULT
#define UNUSED(x)
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint y
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_started(MemoryBuffer *output, const rcti &area, Span< MemoryBuffer * > inputs) override
void execute_pixel_sampled(float output[4], float x, float y, PixelSampler sampler) override
void pixel_transform(const float xy[2], float r_uv[2], float r_deriv[2][2], float &r_alpha)
bool determine_depending_area_of_interest(rcti *input, ReadBufferOperation *read_operation, rcti *output) override
a MemoryBuffer contains access to the data of a chunk
void read_elem_bilinear(float x, float y, float *out) const
void read_elem_filtered(float x, float y, float dx[2], float dy[2], float *out) const
NodeOperation contains calculation logic.
void add_output_socket(DataType datatype)
void read_filtered(float result[4], float x, float y, float dx[2], float dy[2])
SocketReader * get_input_socket_reader(unsigned int index)
NodeOperation * get_input_operation(int index)
virtual bool determine_depending_area_of_interest(rcti *input, ReadBufferOperation *read_operation, rcti *output)
void read_sampled(float result[4], float x, float y, PixelSampler sampler)
void add_input_socket(DataType datatype, ResizeMode resize_mode=ResizeMode::Center)
void set_canvas_input_index(unsigned int index)
set the index of the input socket that will determine the canvas of this operation
@ Vector
Vector data type.
ccl_gpu_kernel_postfix ccl_global float int int int int float threshold
ccl_global KernelShaderEvalInput ccl_global float * output
ccl_global KernelShaderEvalInput * input
static void area(int d1, int d2, int e1, int e2, float weights[2])
void expand_area_for_sampler(rcti &area, PixelSampler sampler)
Definition: COM_Enums.cc:8
typename BuffersIteratorBuilder< T >::Iterator BuffersIterator
static double epsilon
static const pxr::TfToken out("out", pxr::TfToken::Immortal)
static bNodeSocketTemplate inputs[]
int ymin
Definition: DNA_vec_types.h:64
int ymax
Definition: DNA_vec_types.h:64
int xmin
Definition: DNA_vec_types.h:63
int xmax
Definition: DNA_vec_types.h:63
int xy[2]
Definition: wm_draw.c:135