Blender  V3.3
node_geo_image_texture.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2005 Blender Foundation. All rights reserved. */
3 
4 #include "node_geometry_util.hh"
5 
6 #include "BKE_image.h"
7 
8 #include "BLI_math_vec_types.hh"
9 #include "BLI_threads.h"
10 #include "BLI_timeit.hh"
11 
12 #include "IMB_colormanagement.h"
13 #include "IMB_imbuf.h"
14 #include "IMB_imbuf_types.h"
15 
16 #include "UI_interface.h"
17 #include "UI_resources.h"
18 
20 
22 
24 {
25  b.add_input<decl::Image>(N_("Image")).hide_label();
26  b.add_input<decl::Vector>(N_("Vector"))
27  .implicit_field()
28  .description(("Texture coordinates from 0 to 1"));
29  b.add_input<decl::Int>(N_("Frame")).min(0).max(MAXFRAMEF);
30  b.add_output<decl::Color>(N_("Color")).no_muted_links().dependent_field();
31  b.add_output<decl::Float>(N_("Alpha")).no_muted_links().dependent_field();
32 }
33 
34 static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
35 {
36  uiItemR(layout, ptr, "interpolation", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
37  uiItemR(layout, ptr, "extension", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
38 }
39 
41 {
42  NodeGeometryImageTexture *tex = MEM_cnew<NodeGeometryImageTexture>(__func__);
43  node->storage = tex;
44 }
45 
47  private:
48  const int interpolation_;
49  const int extension_;
50  Image &image_;
51  ImageUser image_user_;
52  void *image_lock_;
53  ImBuf *image_buffer_;
54 
55  public:
56  ImageFieldsFunction(const int interpolation,
57  const int extension,
58  Image &image,
59  ImageUser image_user)
60  : interpolation_(interpolation),
61  extension_(extension),
62  image_(image),
63  image_user_(image_user)
64  {
66  this->set_signature(&signature);
67 
68  image_buffer_ = BKE_image_acquire_ibuf(&image_, &image_user_, &image_lock_);
69  if (image_buffer_ == nullptr) {
70  throw std::runtime_error("cannot acquire image buffer");
71  }
72 
73  if (image_buffer_->rect_float == nullptr) {
75  if (!image_buffer_->rect_float) {
76  IMB_float_from_rect(image_buffer_);
77  }
79  }
80 
81  if (image_buffer_->rect_float == nullptr) {
82  BKE_image_release_ibuf(&image_, image_buffer_, image_lock_);
83  throw std::runtime_error("cannot get float buffer");
84  }
85  }
86 
88  {
89  BKE_image_release_ibuf(&image_, image_buffer_, image_lock_);
90  }
91 
93  {
94  fn::MFSignatureBuilder signature{"ImageFunction"};
95  signature.single_input<float3>("Vector");
96  signature.single_output<ColorGeometry4f>("Color");
97  signature.single_output<float>("Alpha");
98  return signature.build();
99  }
100 
101  static int wrap_periodic(int x, const int width)
102  {
103  x %= width;
104  if (x < 0) {
105  x += width;
106  }
107  return x;
108  }
109 
110  static int wrap_clamp(const int x, const int width)
111  {
112  return std::clamp(x, 0, width - 1);
113  }
114 
115  static float4 image_pixel_lookup(const ImBuf *ibuf, const int px, const int py)
116  {
117  if (px < 0 || py < 0 || px >= ibuf->x || py >= ibuf->y) {
118  return float4(0.0f, 0.0f, 0.0f, 0.0f);
119  }
120  return ((const float4 *)ibuf->rect_float)[px + py * ibuf->x];
121  }
122 
123  static float frac(const float x, int *ix)
124  {
125  const int i = (int)x - ((x < 0.0f) ? 1 : 0);
126  *ix = i;
127  return x - (float)i;
128  }
129 
131  const float px,
132  const float py,
133  const int extension)
134  {
135  const int width = ibuf->x;
136  const int height = ibuf->y;
137  int pix, piy, nix, niy;
138  const float tx = frac(px * (float)width - 0.5f, &pix);
139  const float ty = frac(py * (float)height - 0.5f, &piy);
140  int ppix, ppiy, nnix, nniy;
141 
142  switch (extension) {
144  pix = wrap_periodic(pix, width);
145  piy = wrap_periodic(piy, height);
146  ppix = wrap_periodic(pix - 1, width);
147  ppiy = wrap_periodic(piy - 1, height);
148  nix = wrap_periodic(pix + 1, width);
149  niy = wrap_periodic(piy + 1, height);
150  nnix = wrap_periodic(pix + 2, width);
151  nniy = wrap_periodic(piy + 2, height);
152  break;
153  }
155  ppix = pix - 1;
156  ppiy = piy - 1;
157  nix = pix + 1;
158  niy = piy + 1;
159  nnix = pix + 2;
160  nniy = piy + 2;
161  break;
162  }
164  ppix = wrap_clamp(pix - 1, width);
165  ppiy = wrap_clamp(piy - 1, height);
166  nix = wrap_clamp(pix + 1, width);
167  niy = wrap_clamp(piy + 1, height);
168  nnix = wrap_clamp(pix + 2, width);
169  nniy = wrap_clamp(piy + 2, height);
170  pix = wrap_clamp(pix, width);
171  piy = wrap_clamp(piy, height);
172  break;
173  }
174  default:
175  return float4(0.0f, 0.0f, 0.0f, 0.0f);
176  }
177 
178  const int xc[4] = {ppix, pix, nix, nnix};
179  const int yc[4] = {ppiy, piy, niy, nniy};
180  float u[4], v[4];
181 
182  u[0] = (((-1.0f / 6.0f) * tx + 0.5f) * tx - 0.5f) * tx + (1.0f / 6.0f);
183  u[1] = ((0.5f * tx - 1.0f) * tx) * tx + (2.0f / 3.0f);
184  u[2] = ((-0.5f * tx + 0.5f) * tx + 0.5f) * tx + (1.0f / 6.0f);
185  u[3] = (1.0f / 6.0f) * tx * tx * tx;
186 
187  v[0] = (((-1.0f / 6.0f) * ty + 0.5f) * ty - 0.5f) * ty + (1.0f / 6.0f);
188  v[1] = ((0.5f * ty - 1.0f) * ty) * ty + (2.0f / 3.0f);
189  v[2] = ((-0.5f * ty + 0.5f) * ty + 0.5f) * ty + (1.0f / 6.0f);
190  v[3] = (1.0f / 6.0f) * ty * ty * ty;
191 
192  return (v[0] * (u[0] * (image_pixel_lookup(ibuf, xc[0], yc[0])) +
193  u[1] * (image_pixel_lookup(ibuf, xc[1], yc[0])) +
194  u[2] * (image_pixel_lookup(ibuf, xc[2], yc[0])) +
195  u[3] * (image_pixel_lookup(ibuf, xc[3], yc[0])))) +
196  (v[1] * (u[0] * (image_pixel_lookup(ibuf, xc[0], yc[1])) +
197  u[1] * (image_pixel_lookup(ibuf, xc[1], yc[1])) +
198  u[2] * (image_pixel_lookup(ibuf, xc[2], yc[1])) +
199  u[3] * (image_pixel_lookup(ibuf, xc[3], yc[1])))) +
200  (v[2] * (u[0] * (image_pixel_lookup(ibuf, xc[0], yc[2])) +
201  u[1] * (image_pixel_lookup(ibuf, xc[1], yc[2])) +
202  u[2] * (image_pixel_lookup(ibuf, xc[2], yc[2])) +
203  u[3] * (image_pixel_lookup(ibuf, xc[3], yc[2])))) +
204  (v[3] * (u[0] * (image_pixel_lookup(ibuf, xc[0], yc[3])) +
205  u[1] * (image_pixel_lookup(ibuf, xc[1], yc[3])) +
206  u[2] * (image_pixel_lookup(ibuf, xc[2], yc[3])) +
207  u[3] * (image_pixel_lookup(ibuf, xc[3], yc[3]))));
208  }
209 
211  const float px,
212  const float py,
213  const int extension)
214  {
215  const int width = ibuf->x;
216  const int height = ibuf->y;
217  int pix, piy, nix, niy;
218  const float nfx = frac(px * (float)width - 0.5f, &pix);
219  const float nfy = frac(py * (float)height - 0.5f, &piy);
220 
221  switch (extension) {
223  nix = pix + 1;
224  niy = piy + 1;
225  break;
226  }
228  nix = wrap_clamp(pix + 1, width);
229  niy = wrap_clamp(piy + 1, height);
230  pix = wrap_clamp(pix, width);
231  piy = wrap_clamp(piy, height);
232  break;
233  }
234  default:
236  pix = wrap_periodic(pix, width);
237  piy = wrap_periodic(piy, height);
238  nix = wrap_periodic(pix + 1, width);
239  niy = wrap_periodic(piy + 1, height);
240  break;
241  }
242 
243  const float ptx = 1.0f - nfx;
244  const float pty = 1.0f - nfy;
245 
246  return image_pixel_lookup(ibuf, pix, piy) * ptx * pty +
247  image_pixel_lookup(ibuf, nix, piy) * nfx * pty +
248  image_pixel_lookup(ibuf, pix, niy) * ptx * nfy +
249  image_pixel_lookup(ibuf, nix, niy) * nfx * nfy;
250  }
251 
253  const float px,
254  const float py,
255  const int extension)
256  {
257  const int width = ibuf->x;
258  const int height = ibuf->y;
259  int ix, iy;
260  const float tx = frac(px * (float)width, &ix);
261  const float ty = frac(py * (float)height, &iy);
262 
263  switch (extension) {
265  ix = wrap_periodic(ix, width);
266  iy = wrap_periodic(iy, height);
267  return image_pixel_lookup(ibuf, ix, iy);
268  }
270  if (tx < 0.0f || ty < 0.0f || tx > 1.0f || ty > 1.0f) {
271  return float4(0.0f, 0.0f, 0.0f, 0.0f);
272  }
273  if (ix < 0 || iy < 0 || ix > width || iy > height) {
274  return float4(0.0f, 0.0f, 0.0f, 0.0f);
275  }
277  }
279  ix = wrap_clamp(ix, width);
280  iy = wrap_clamp(iy, height);
281  return image_pixel_lookup(ibuf, ix, iy);
282  }
283  default:
284  return float4(0.0f, 0.0f, 0.0f, 0.0f);
285  }
286  }
287 
289  {
290  const VArray<float3> &vectors = params.readonly_single_input<float3>(0, "Vector");
291  MutableSpan<ColorGeometry4f> r_color = params.uninitialized_single_output<ColorGeometry4f>(
292  1, "Color");
293  MutableSpan<float> r_alpha = params.uninitialized_single_output_if_required<float>(2, "Alpha");
294 
295  MutableSpan<float4> color_data{(float4 *)r_color.data(), r_color.size()};
296 
297  /* Sample image texture. */
298  switch (interpolation_) {
299  case SHD_INTERP_LINEAR:
300  for (const int64_t i : mask) {
301  const float3 p = vectors[i];
302  color_data[i] = image_linear_texture_lookup(image_buffer_, p.x, p.y, extension_);
303  }
304  break;
305  case SHD_INTERP_CLOSEST:
306  for (const int64_t i : mask) {
307  const float3 p = vectors[i];
308  color_data[i] = image_closest_texture_lookup(image_buffer_, p.x, p.y, extension_);
309  }
310  break;
311  case SHD_INTERP_CUBIC:
312  case SHD_INTERP_SMART:
313  for (const int64_t i : mask) {
314  const float3 p = vectors[i];
315  color_data[i] = image_cubic_texture_lookup(image_buffer_, p.x, p.y, extension_);
316  }
317  break;
318  }
319 
320  int alpha_mode = image_.alpha_mode;
322  alpha_mode = IMA_ALPHA_CHANNEL_PACKED;
323  }
324 
325  switch (alpha_mode) {
326  case IMA_ALPHA_STRAIGHT: {
327  /* #ColorGeometry expects premultiplied alpha, so convert from straight to that. */
328  for (int64_t i : mask) {
329  straight_to_premul_v4(color_data[i]);
330  }
331  break;
332  }
333  case IMA_ALPHA_PREMUL: {
334  /* Alpha is premultiplied already, nothing to do. */
335  break;
336  }
338  /* Color and alpha channels shouldn't interact with each other, nothing to do. */
339  break;
340  }
341  case IMA_ALPHA_IGNORE: {
342  /* The image should be treated as being opaque. */
343  for (int64_t i : mask) {
344  color_data[i].w = 1.0f;
345  }
346  break;
347  }
348  }
349 
350  if (!r_alpha.is_empty()) {
351  for (int64_t i : mask) {
352  r_alpha[i] = r_color[i].a;
353  }
354  }
355  }
356 };
357 
359 {
360  Image *image = params.get_input<Image *>("Image");
361  if (image == nullptr) {
362  params.set_default_remaining_outputs();
363  return;
364  }
365 
366  const NodeGeometryImageTexture &storage = node_storage(params.node());
367 
368  ImageUser image_user;
369  BKE_imageuser_default(&image_user);
370  image_user.cycl = false;
371  image_user.frames = INT_MAX;
372  image_user.sfra = 1;
373  image_user.framenr = BKE_image_is_animated(image) ? params.get_input<int>("Frame") : 0;
374 
375  std::unique_ptr<ImageFieldsFunction> image_fn;
376  try {
377  image_fn = std::make_unique<ImageFieldsFunction>(
378  storage.interpolation, storage.extension, *image, image_user);
379  }
380  catch (const std::runtime_error &) {
381  params.set_default_remaining_outputs();
382  return;
383  }
384 
385  Field<float3> vector_field = params.extract_input<Field<float3>>("Vector");
386 
387  auto image_op = std::make_shared<FieldOperation>(
388  FieldOperation(std::move(image_fn), {std::move(vector_field)}));
389 
390  params.set_output("Color", Field<ColorGeometry4f>(image_op, 0));
391  params.set_output("Alpha", Field<float>(image_op, 1));
392 }
393 
394 } // namespace blender::nodes::node_geo_image_texture_cc
395 
397 {
398  namespace file_ns = blender::nodes::node_geo_image_texture_cc;
399 
400  static bNodeType ntype;
401 
407  &ntype, "NodeGeometryImageTexture", node_free_standard_storage, node_copy_standard_storage);
410 
411  nodeRegisterType(&ntype);
412 }
typedef float(TangentPoint)[2]
void BKE_image_release_ibuf(struct Image *ima, struct ImBuf *ibuf, void *lock)
bool BKE_image_is_animated(struct Image *image)
struct ImBuf * BKE_image_acquire_ibuf(struct Image *ima, struct ImageUser *iuser, void **r_lock)
void BKE_imageuser_default(struct ImageUser *iuser)
#define NODE_STORAGE_FUNCS(StorageT)
Definition: BKE_node.h:1563
void node_type_init(struct bNodeType *ntype, void(*initfunc)(struct bNodeTree *ntree, struct bNode *node))
Definition: node.cc:4390
void node_type_size_preset(struct bNodeType *ntype, eNodeSizePreset size)
Definition: node.cc:4408
#define GEO_NODE_IMAGE_TEXTURE
Definition: BKE_node.h:1473
void node_type_storage(struct bNodeType *ntype, const char *storagename, void(*freefunc)(struct bNode *node), void(*copyfunc)(struct bNodeTree *dest_ntree, struct bNode *dest_node, const struct bNode *src_node))
Definition: node.cc:4426
#define NODE_CLASS_TEXTURE
Definition: BKE_node.h:355
void nodeRegisterType(struct bNodeType *ntype)
Definition: node.cc:1357
@ NODE_SIZE_LARGE
Definition: BKE_node.h:367
#define ATTR_FALLTHROUGH
MINLINE void straight_to_premul_v4(float color[4])
void BLI_thread_unlock(int type)
Definition: threads.cc:361
@ LOCK_IMAGE
Definition: BLI_threads.h:66
void BLI_thread_lock(int type)
Definition: threads.cc:356
#define UNUSED(x)
@ IMA_ALPHA_IGNORE
@ IMA_ALPHA_STRAIGHT
@ IMA_ALPHA_PREMUL
@ IMA_ALPHA_CHANNEL_PACKED
#define SHD_IMAGE_EXTENSION_CLIP
#define SHD_IMAGE_EXTENSION_EXTEND
#define SHD_INTERP_SMART
#define SHD_IMAGE_EXTENSION_REPEAT
#define SHD_INTERP_CLOSEST
#define SHD_INTERP_CUBIC
#define SHD_INTERP_LINEAR
#define MAXFRAMEF
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei height
_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 GLsizei width
bool IMB_colormanagement_space_name_is_data(const char *name)
void IMB_float_from_rect(struct ImBuf *ibuf)
Definition: divers.c:805
Contains defines and structs used throughout the imbuf module.
@ UI_ITEM_R_SPLIT_EMPTY_NAME
void uiItemR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int flag, const char *name, int icon)
ATTR_WARN_UNUSED_RESULT const BMVert * v
ColorManagedColorspaceSettings colorspace_settings
char alpha_mode
constexpr T * data() const
Definition: BLI_span.hh:548
void set_signature(const MFSignature *signature)
const MFSignature & signature() const
static float4 image_closest_texture_lookup(const ImBuf *ibuf, const float px, const float py, const int extension)
ImageFieldsFunction(const int interpolation, const int extension, Image &image, ImageUser image_user)
void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override
static float4 image_cubic_texture_lookup(const ImBuf *ibuf, const float px, const float py, const int extension)
static float4 image_linear_texture_lookup(const ImBuf *ibuf, const float px, const float py, const int extension)
static float4 image_pixel_lookup(const ImBuf *ibuf, const int px, const int py)
OperationNode * node
depth_tx normal_tx diffuse_light_tx specular_light_tx volume_light_tx environment_tx ambient_occlusion_tx aov_value_tx in_weight_img image(1, GPU_R32F, Qualifier::WRITE, ImageType::FLOAT_2D_ARRAY, "out_weight_img") .image(3
bNodeTree * ntree
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
ccl_device_inline float4 mask(const int4 &mask, const float4 &a)
Definition: math_float4.h:513
T clamp(const T &a, const T &min, const T &max)
static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_geo_exec(GeoNodeExecParams params)
static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
static void node_declare(NodeDeclarationBuilder &b)
vec_base< float, 4 > float4
static const pxr::TfToken b("b", pxr::TfToken::Immortal)
static void node_init(const struct bContext *C, bNodeTree *ntree, bNode *node)
Definition: node.cc:1082
void register_node_type_geo_image_texture()
void geo_node_type_base(bNodeType *ntype, int type, const char *name, short nclass)
void node_copy_standard_storage(bNodeTree *UNUSED(dest_ntree), bNode *dest_node, const bNode *src_node)
Definition: node_util.c:55
void node_free_standard_storage(bNode *node)
Definition: node_util.c:43
#define min(a, b)
Definition: sort.c:35
__int64 int64_t
Definition: stdint.h:89
float * rect_float
Defines a node type.
Definition: BKE_node.h:226
NodeGeometryExecFunction geometry_node_execute
Definition: BKE_node.h:316
void(* draw_buttons)(struct uiLayout *, struct bContext *C, struct PointerRNA *ptr)
Definition: BKE_node.h:244
NodeDeclareFunction declare
Definition: BKE_node.h:324
#define N_(msgid)
PointerRNA * ptr
Definition: wm_files.c:3480