Blender  V2.93
node_geo_attribute_vector_math.cc
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
17 #include "BLI_math_base_safe.h"
18 
19 #include "UI_interface.h"
20 #include "UI_resources.h"
21 
22 #include "NOD_math_functions.hh"
23 
24 #include "node_geometry_util.hh"
25 
27  {SOCK_GEOMETRY, N_("Geometry")},
28  {SOCK_STRING, N_("A")},
29  {SOCK_VECTOR, N_("A"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX},
30  {SOCK_STRING, N_("B")},
31  {SOCK_VECTOR, N_("B"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX},
32  {SOCK_FLOAT, N_("B"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX},
33  {SOCK_STRING, N_("C")},
34  {SOCK_VECTOR, N_("C"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX},
35  {SOCK_FLOAT, N_("C"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX},
36  {SOCK_STRING, N_("Result")},
37  {-1, ""},
38 };
39 
41  {SOCK_GEOMETRY, N_("Geometry")},
42  {-1, ""},
43 };
44 
45 static bool operation_use_input_b(const NodeVectorMathOperation operation)
46 {
47  return !ELEM(operation,
57 }
58 
59 static bool operation_use_input_c(const NodeVectorMathOperation operation)
60 {
61  return ELEM(
63 }
64 
66  bContext *UNUSED(C),
67  PointerRNA *ptr)
68 {
69  bNode *node = (bNode *)ptr->data;
70  const NodeAttributeVectorMath &node_storage = *(NodeAttributeVectorMath *)node->storage;
71  const NodeVectorMathOperation operation = (const NodeVectorMathOperation)node_storage.operation;
72 
73  uiItemR(layout, ptr, "operation", 0, "", ICON_NONE);
74 
75  uiLayoutSetPropSep(layout, true);
76  uiLayoutSetPropDecorate(layout, false);
77  uiItemR(layout, ptr, "input_type_a", 0, IFACE_("A"), ICON_NONE);
78  if (operation_use_input_b(operation)) {
79  uiItemR(layout, ptr, "input_type_b", 0, IFACE_("B"), ICON_NONE);
80  }
81  if (operation_use_input_c(operation)) {
82  uiItemR(layout, ptr, "input_type_c", 0, IFACE_("C"), ICON_NONE);
83  }
84 }
85 
87 {
88  if (operation == NODE_VECTOR_MATH_SCALE) {
89  return CD_PROP_FLOAT;
90  }
91  return CD_PROP_FLOAT3;
92 }
93 
95 {
96  if (operation == NODE_VECTOR_MATH_REFRACT) {
97  return CD_PROP_FLOAT;
98  }
99  return CD_PROP_FLOAT3;
100 }
101 
103 {
105  sizeof(NodeAttributeVectorMath), __func__);
106 
107  data->operation = NODE_VECTOR_MATH_ADD;
110  node->storage = data;
111 }
112 
114 {
115  switch (operation) {
139  return CD_PROP_FLOAT3;
143  return CD_PROP_FLOAT;
144  }
145 
146  BLI_assert(false);
147  return CD_PROP_FLOAT3;
148 }
149 
150 namespace blender::nodes {
151 
153 {
154  const NodeAttributeVectorMath *node_storage = (NodeAttributeVectorMath *)node->storage;
155  const NodeVectorMathOperation operation = (const NodeVectorMathOperation)node_storage->operation;
156 
158  *node, "A", (GeometryNodeAttributeInputMode)node_storage->input_type_a);
160  *node,
161  "B",
163  operation_use_input_b(operation));
165  *node,
166  "C",
168  operation_use_input_c(operation));
169 }
170 
172  const Float3ReadAttribute &input_b,
174  const NodeVectorMathOperation operation)
175 {
176  const int size = input_a.size();
177 
178  Span<float3> span_a = input_a.get_span();
179  Span<float3> span_b = input_b.get_span();
180  MutableSpan<float3> span_result = result.get_span_for_write_only();
181 
183  operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) {
184  for (const int i : IndexRange(size)) {
185  const float3 a = span_a[i];
186  const float3 b = span_b[i];
187  const float3 out = math_function(a, b);
188  span_result[i] = out;
189  }
190  });
191 
192  result.apply_span();
193 
194  /* The operation is not supported by this node currently. */
195  BLI_assert(success);
196  UNUSED_VARS_NDEBUG(success);
197 }
198 
200  const Float3ReadAttribute &input_b,
201  const Float3ReadAttribute &input_c,
203  const NodeVectorMathOperation operation)
204 {
205  const int size = input_a.size();
206 
207  Span<float3> span_a = input_a.get_span();
208  Span<float3> span_b = input_b.get_span();
209  Span<float3> span_c = input_c.get_span();
210  MutableSpan<float3> span_result = result.get_span_for_write_only();
211 
213  operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) {
214  for (const int i : IndexRange(size)) {
215  const float3 a = span_a[i];
216  const float3 b = span_b[i];
217  const float3 c = span_c[i];
218  const float3 out = math_function(a, b, c);
219  span_result[i] = out;
220  }
221  });
222 
223  result.apply_span();
224 
225  /* The operation is not supported by this node currently. */
226  BLI_assert(success);
227  UNUSED_VARS_NDEBUG(success);
228 }
229 
231  const Float3ReadAttribute &input_b,
232  const FloatReadAttribute &input_c,
234  const NodeVectorMathOperation operation)
235 {
236  const int size = input_a.size();
237 
238  Span<float3> span_a = input_a.get_span();
239  Span<float3> span_b = input_b.get_span();
240  Span<float> span_c = input_c.get_span();
241  MutableSpan<float3> span_result = result.get_span_for_write_only();
242 
244  operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) {
245  for (const int i : IndexRange(size)) {
246  const float3 a = span_a[i];
247  const float3 b = span_b[i];
248  const float c = span_c[i];
249  const float3 out = math_function(a, b, c);
250  span_result[i] = out;
251  }
252  });
253 
254  result.apply_span();
255 
256  /* The operation is not supported by this node currently. */
257  BLI_assert(success);
258  UNUSED_VARS_NDEBUG(success);
259 }
260 
262  const Float3ReadAttribute &input_b,
264  const NodeVectorMathOperation operation)
265 {
266  const int size = input_a.size();
267 
268  Span<float3> span_a = input_a.get_span();
269  Span<float3> span_b = input_b.get_span();
270  MutableSpan<float> span_result = result.get_span_for_write_only();
271 
273  operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) {
274  for (const int i : IndexRange(size)) {
275  const float3 a = span_a[i];
276  const float3 b = span_b[i];
277  const float out = math_function(a, b);
278  span_result[i] = out;
279  }
280  });
281 
282  result.apply_span();
283 
284  /* The operation is not supported by this node currently. */
285  BLI_assert(success);
286  UNUSED_VARS_NDEBUG(success);
287 }
288 
290  const FloatReadAttribute &input_b,
292  const NodeVectorMathOperation operation)
293 {
294  const int size = input_a.size();
295 
296  Span<float3> span_a = input_a.get_span();
297  Span<float> span_b = input_b.get_span();
298  MutableSpan<float3> span_result = result.get_span_for_write_only();
299 
301  operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) {
302  for (const int i : IndexRange(size)) {
303  const float3 a = span_a[i];
304  const float b = span_b[i];
305  const float3 out = math_function(a, b);
306  span_result[i] = out;
307  }
308  });
309 
310  result.apply_span();
311 
312  /* The operation is not supported by this node currently. */
313  BLI_assert(success);
314  UNUSED_VARS_NDEBUG(success);
315 }
316 
319  const NodeVectorMathOperation operation)
320 {
321  const int size = input_a.size();
322 
323  Span<float3> span_a = input_a.get_span();
324  MutableSpan<float3> span_result = result.get_span_for_write_only();
325 
326  bool success = try_dispatch_float_math_fl3_to_fl3(
327  operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) {
328  for (const int i : IndexRange(size)) {
329  const float3 in = span_a[i];
330  const float3 out = math_function(in);
331  span_result[i] = out;
332  }
333  });
334 
335  result.apply_span();
336 
337  /* The operation is not supported by this node currently. */
338  BLI_assert(success);
339  UNUSED_VARS_NDEBUG(success);
340 }
341 
344  const NodeVectorMathOperation operation)
345 {
346  const int size = input_a.size();
347 
348  Span<float3> span_a = input_a.get_span();
349  MutableSpan<float> span_result = result.get_span_for_write_only();
350 
351  bool success = try_dispatch_float_math_fl3_to_fl(
352  operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) {
353  for (const int i : IndexRange(size)) {
354  const float3 in = span_a[i];
355  const float out = math_function(in);
356  span_result[i] = out;
357  }
358  });
359 
360  result.apply_span();
361 
362  /* The operation is not supported by this node currently. */
363  BLI_assert(success);
364  UNUSED_VARS_NDEBUG(success);
365 }
366 
368  const GeoNodeExecParams &params,
369  const NodeVectorMathOperation operation,
370  StringRef result_name)
371 {
372  /* Use the domain of the result attribute if it already exists. */
373  ReadAttributePtr result_attribute = component.attribute_try_get_for_read(result_name);
374  if (result_attribute) {
375  return result_attribute->domain();
376  }
377 
378  /* Otherwise use the highest priority domain from existing input attributes, or the default. */
380  if (operation_use_input_b(operation)) {
381  if (operation_use_input_c(operation)) {
382  return params.get_highest_priority_input_domain({"A", "B", "C"}, component, default_domain);
383  }
384  return params.get_highest_priority_input_domain({"A", "B"}, component, default_domain);
385  }
386  return params.get_highest_priority_input_domain({"A"}, component, default_domain);
387 }
388 
390  const GeoNodeExecParams &params)
391 {
392  const bNode &node = params.node();
393  const NodeAttributeVectorMath *node_storage = (const NodeAttributeVectorMath *)node.storage;
394  const NodeVectorMathOperation operation = (NodeVectorMathOperation)node_storage->operation;
395  const std::string result_name = params.get_input<std::string>("Result");
396 
397  /* The number and type of the input attribute depend on the operation. */
398  const CustomDataType read_type_a = CD_PROP_FLOAT3;
399  const bool use_input_b = operation_use_input_b(operation);
400  const CustomDataType read_type_b = operation_get_read_type_b(operation);
401  const bool use_input_c = operation_use_input_c(operation);
402  const CustomDataType read_type_c = operation_get_read_type_c(operation);
403 
404  /* The result domain is always point for now. */
405  const CustomDataType result_type = operation_get_result_type(operation);
406  const AttributeDomain result_domain = get_result_domain(
407  component, params, operation, result_name);
408 
409  ReadAttributePtr attribute_a = params.get_input_attribute(
410  "A", component, result_domain, read_type_a, nullptr);
411  if (!attribute_a) {
412  return;
413  }
414  ReadAttributePtr attribute_b;
415  ReadAttributePtr attribute_c;
416  if (use_input_b) {
417  attribute_b = params.get_input_attribute("B", component, result_domain, read_type_b, nullptr);
418  if (!attribute_b) {
419  return;
420  }
421  }
422  if (use_input_c) {
423  attribute_c = params.get_input_attribute("C", component, result_domain, read_type_c, nullptr);
424  if (!attribute_c) {
425  return;
426  }
427  }
428 
429  /* Get result attribute first, in case it has to overwrite one of the existing attributes. */
430  OutputAttributePtr attribute_result = component.attribute_try_get_for_output(
431  result_name, result_domain, result_type);
432  if (!attribute_result) {
433  return;
434  }
435 
436  switch (operation) {
448  do_math_operation_fl3_fl3_to_fl3(*attribute_a, *attribute_b, *attribute_result, operation);
449  break;
452  do_math_operation_fl3_fl3_to_fl(*attribute_a, *attribute_b, *attribute_result, operation);
453  break;
455  do_math_operation_fl3_to_fl(*attribute_a, *attribute_result, operation);
456  break;
458  do_math_operation_fl3_fl_to_fl3(*attribute_a, *attribute_b, *attribute_result, operation);
459  break;
468  do_math_operation_fl3_to_fl3(*attribute_a, *attribute_result, operation);
469  break;
473  *attribute_a, *attribute_b, *attribute_c, *attribute_result, operation);
474  break;
477  *attribute_a, *attribute_b, *attribute_c, *attribute_result, operation);
478  break;
479  }
480  attribute_result.save();
481 }
482 
484 {
485  GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
486 
487  geometry_set = geometry_set_realize_instances(geometry_set);
488 
489  if (geometry_set.has<MeshComponent>()) {
491  }
492  if (geometry_set.has<PointCloudComponent>()) {
494  params);
495  }
496 
497  params.set_output("Geometry", geometry_set);
498 }
499 
500 } // namespace blender::nodes
501 
503 {
504  static bNodeType ntype;
505 
507  &ntype, GEO_NODE_ATTRIBUTE_VECTOR_MATH, "Attribute Vector Math", NODE_CLASS_ATTRIBUTE, 0);
515  &ntype, "NodeAttributeVectorMath", node_free_standard_storage, node_copy_standard_storage);
516  nodeRegisterType(&ntype);
517 }
AttributeDomain
Definition: BKE_attribute.h:41
@ ATTR_DOMAIN_POINT
Definition: BKE_attribute.h:43
void node_type_socket_templates(struct bNodeType *ntype, struct bNodeSocketTemplate *inputs, struct bNodeSocketTemplate *outputs)
Definition: node.cc:4527
void node_type_update(struct bNodeType *ntype, void(*updatefunc)(struct bNodeTree *ntree, struct bNode *node))
Definition: node.cc:4623
void node_type_init(struct bNodeType *ntype, void(*initfunc)(struct bNodeTree *ntree, struct bNode *node))
Definition: node.cc:4559
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:4599
#define NODE_CLASS_ATTRIBUTE
Definition: BKE_node.h:360
void nodeRegisterType(struct bNodeType *ntype)
Definition: node.cc:1298
#define BLI_assert(a)
Definition: BLI_assert.h:58
#define UNUSED_VARS_NDEBUG(...)
#define UNUSED(x)
#define ELEM(...)
#define IFACE_(msgid)
#define N_(msgid)
static uint8 component(Color32 c, uint i)
Definition: ColorBlock.cpp:126
CustomDataType
@ CD_PROP_FLOAT
@ CD_PROP_FLOAT3
NodeVectorMathOperation
@ NODE_VECTOR_MATH_NORMALIZE
@ NODE_VECTOR_MATH_LENGTH
@ NODE_VECTOR_MATH_CROSS_PRODUCT
@ NODE_VECTOR_MATH_CEIL
@ NODE_VECTOR_MATH_MODULO
@ NODE_VECTOR_MATH_ADD
@ NODE_VECTOR_MATH_COSINE
@ NODE_VECTOR_MATH_REFLECT
@ NODE_VECTOR_MATH_WRAP
@ NODE_VECTOR_MATH_REFRACT
@ NODE_VECTOR_MATH_DOT_PRODUCT
@ NODE_VECTOR_MATH_ABSOLUTE
@ NODE_VECTOR_MATH_DIVIDE
@ NODE_VECTOR_MATH_TANGENT
@ NODE_VECTOR_MATH_DISTANCE
@ NODE_VECTOR_MATH_FLOOR
@ NODE_VECTOR_MATH_SNAP
@ NODE_VECTOR_MATH_SINE
@ NODE_VECTOR_MATH_FRACTION
@ NODE_VECTOR_MATH_PROJECT
@ NODE_VECTOR_MATH_MULTIPLY
@ NODE_VECTOR_MATH_SCALE
@ NODE_VECTOR_MATH_MAXIMUM
@ NODE_VECTOR_MATH_FACEFORWARD
@ NODE_VECTOR_MATH_SUBTRACT
@ NODE_VECTOR_MATH_MINIMUM
@ SOCK_VECTOR
@ SOCK_FLOAT
@ SOCK_GEOMETRY
@ SOCK_STRING
GeometryNodeAttributeInputMode
@ GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE
Group RGB to Bright Vector Camera Vector Combine Material Light Line Style Layer Add Ambient Diffuse Glossy Refraction Transparent Toon Principled Hair Volume Principled Light Particle Volume Image Sky Noise Wave Voronoi Brick Texture Vector Combine Vertex Separate Vector White RGB Map Separate Set Z Dilate Combine Combine Color Channel Split ID Combine Luminance Directional Alpha Distance Hue Movie Ellipse Bokeh View Corner Anti Mix RGB Hue Separate TEX_NODE_PROC TEX_NODE_PROC TEX_NODE_PROC TEX_NODE_PROC TEX_NODE_PROC Boolean Random Edge Subdivision Point Object Attribute Attribute Attribute Color Attribute GEO_NODE_ATTRIBUTE_VECTOR_MATH
#define C
Definition: RandGen.cpp:39
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
void uiItemR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int flag, const char *name, int icon)
void uiLayoutSetPropDecorate(uiLayout *layout, bool is_sep)
static std::string default_domain
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
OperationNode * node
void * tree
bNodeTree * ntree
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
static unsigned c
Definition: RandGen.cpp:97
static unsigned a[3]
Definition: RandGen.cpp:92
TypedWriteAttribute< float3 > Float3WriteAttribute
TypedReadAttribute< float > FloatReadAttribute
TypedReadAttribute< float3 > Float3ReadAttribute
GeometrySet geometry_set_realize_instances(const GeometrySet &geometry_set)
TypedWriteAttribute< float > FloatWriteAttribute
std::unique_ptr< ReadAttribute > ReadAttributePtr
static void do_math_operation_fl3_fl3_to_fl3(const Float3ReadAttribute &input_a, const Float3ReadAttribute &input_b, Float3WriteAttribute result, const NodeVectorMathOperation operation)
bool try_dispatch_float_math_fl3_fl3_to_fl3(const NodeVectorMathOperation operation, Callback &&callback)
static void do_math_operation_fl3_to_fl(const Float3ReadAttribute &input_a, FloatWriteAttribute result, const NodeVectorMathOperation operation)
static void geo_node_attribute_vector_math_exec(GeoNodeExecParams params)
bool try_dispatch_float_math_fl3_to_fl(const NodeVectorMathOperation operation, Callback &&callback)
static void attribute_vector_math_calc(GeometryComponent &component, const GeoNodeExecParams &params)
static void do_math_operation_fl3_to_fl3(const Float3ReadAttribute &input_a, Float3WriteAttribute result, const NodeVectorMathOperation operation)
void update_attribute_input_socket_availabilities(bNode &node, const StringRef name, const GeometryNodeAttributeInputMode mode, const bool name_is_available)
bool try_dispatch_float_math_fl3_fl3_to_fl(const NodeVectorMathOperation operation, Callback &&callback)
static void do_math_operation_fl3_fl3_to_fl(const Float3ReadAttribute &input_a, const Float3ReadAttribute &input_b, FloatWriteAttribute result, const NodeVectorMathOperation operation)
bool try_dispatch_float_math_fl3_fl_to_fl3(const NodeVectorMathOperation operation, Callback &&callback)
static AttributeDomain get_result_domain(const GeometryComponent &component, StringRef source_name, StringRef result_name)
bool try_dispatch_float_math_fl3_fl3_fl_to_fl3(const NodeVectorMathOperation operation, Callback &&callback)
bool try_dispatch_float_math_fl3_to_fl3(const NodeVectorMathOperation operation, Callback &&callback)
static void do_math_operation_fl3_fl3_fl_to_fl3(const Float3ReadAttribute &input_a, const Float3ReadAttribute &input_b, const FloatReadAttribute &input_c, Float3WriteAttribute result, const NodeVectorMathOperation operation)
bool try_dispatch_float_math_fl3_fl3_fl3_to_fl3(const NodeVectorMathOperation operation, Callback &&callback)
static void geo_node_attribute_vector_math_update(bNodeTree *UNUSED(ntree), bNode *node)
static void do_math_operation_fl3_fl3_fl3_to_fl3(const Float3ReadAttribute &input_a, const Float3ReadAttribute &input_b, const Float3ReadAttribute &input_c, Float3WriteAttribute result, const NodeVectorMathOperation operation)
static void do_math_operation_fl3_fl_to_fl3(const Float3ReadAttribute &input_a, const FloatReadAttribute &input_b, Float3WriteAttribute result, const NodeVectorMathOperation operation)
static bNodeSocketTemplate geo_node_attribute_vector_math_out[]
static CustomDataType operation_get_read_type_b(const NodeVectorMathOperation operation)
static bool operation_use_input_c(const NodeVectorMathOperation operation)
static bNodeSocketTemplate geo_node_attribute_vector_math_in[]
static void geo_node_attribute_vector_math_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void geo_node_attribute_vector_math_init(bNodeTree *UNUSED(tree), bNode *node)
static bool operation_use_input_b(const NodeVectorMathOperation operation)
static CustomDataType operation_get_result_type(const NodeVectorMathOperation operation)
void register_node_type_geo_attribute_vector_math()
static CustomDataType operation_get_read_type_c(const NodeVectorMathOperation operation)
void geo_node_type_base(bNodeType *ntype, int type, const char *name, short nclass, short flag)
void node_copy_standard_storage(bNodeTree *UNUSED(dest_ntree), bNode *dest_node, const bNode *src_node)
Definition: node_util.c:67
void node_free_standard_storage(bNode *node)
Definition: node_util.c:55
GeometryComponent & get_component_for_write(GeometryComponentType component_type)
bool has(const GeometryComponentType component_type) const
void * data
Definition: RNA_types.h:52
Compact definition of a node socket.
Definition: BKE_node.h:95
Defines a node type.
Definition: BKE_node.h:221
NodeGeometryExecFunction geometry_node_execute
Definition: BKE_node.h:327
void(* draw_buttons)(struct uiLayout *, struct bContext *C, struct PointerRNA *ptr)
Definition: BKE_node.h:253
PointerRNA * ptr
Definition: wm_files.c:3157