Blender V5.0
node_shader_vector_math.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2005 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "node_shader_util.hh"
10#include "node_util.hh"
11
13#include "NOD_math_functions.hh"
14#include "NOD_multi_function.hh"
17
18#include "RNA_enum_types.hh"
19
21#include "UI_resources.hh"
22
24
26{
27 b.is_function_node();
28 b.add_input<decl::Vector>("Vector").min(-10000.0f).max(10000.0f);
29 b.add_input<decl::Vector>("Vector", "Vector_001").min(-10000.0f).max(10000.0f);
30 b.add_input<decl::Vector>("Vector", "Vector_002").min(-10000.0f).max(10000.0f);
31 b.add_input<decl::Float>("Scale").default_value(1.0f).min(-10000.0f).max(10000.0f);
32 b.add_output<decl::Vector>("Vector");
33 b.add_output<decl::Float>("Value");
34}
35
37{
38 layout->prop(ptr, "operation", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
39}
40
42 public:
43 std::string socket_name;
46 {
47 bNode &node = params.add_node("ShaderNodeVectorMath");
48 node.custom1 = mode;
49 params.update_and_connect_available_socket(node, socket_name);
50 }
51};
52
54{
55 if (!params.node_tree().typeinfo->validate_link(eNodeSocketDatatype(params.other_socket().type),
57 {
58 return;
59 }
60
61 const int weight = ELEM(params.other_socket().type, SOCK_VECTOR, SOCK_RGBA) ? 0 : -1;
62
63 for (const EnumPropertyItem *item = rna_enum_node_vec_math_items; item->identifier != nullptr;
64 item++)
65 {
66 if (item->name != nullptr && item->identifier[0] != '\0') {
67 if ((params.in_out() == SOCK_OUT) && ELEM(item->value,
71 {
72 params.add_item(CTX_IFACE_(BLT_I18NCONTEXT_ID_NODETREE, item->name),
73 SocketSearchOp{"Value", (NodeVectorMathOperation)item->value},
74 weight);
75 }
76 else {
77 params.add_item(CTX_IFACE_(BLT_I18NCONTEXT_ID_NODETREE, item->name),
78 SocketSearchOp{"Vector", (NodeVectorMathOperation)item->value},
79 weight);
80 }
81 }
82 }
83}
84
85static const char *gpu_shader_get_name(int mode)
86{
87 switch (mode) {
89 return "vector_math_add";
91 return "vector_math_subtract";
93 return "vector_math_multiply";
95 return "vector_math_divide";
96
98 return "vector_math_cross";
100 return "vector_math_project";
102 return "vector_math_reflect";
104 return "vector_math_dot";
105
107 return "vector_math_distance";
109 return "vector_math_length";
111 return "vector_math_scale";
113 return "vector_math_normalize";
114
116 return "vector_math_snap";
118 return "vector_math_floor";
120 return "vector_math_ceil";
122 return "vector_math_modulo";
124 return "vector_math_fraction";
126 return "vector_math_absolute";
128 return "vector_math_minimum";
130 return "vector_math_maximum";
132 return "vector_math_wrap";
134 return "vector_math_sine";
136 return "vector_math_cosine";
138 return "vector_math_tangent";
140 return "vector_math_refract";
142 return "vector_math_faceforward";
144 return "vector_math_multiply_add";
146 return "vector_math_power";
148 return "vector_math_sign";
149 }
150
151 return nullptr;
152}
153
155 bNode *node,
156 bNodeExecData * /*execdata*/,
159{
160 const char *name = gpu_shader_get_name(node->custom1);
161 if (name != nullptr) {
162 return GPU_stack_link(mat, node, name, in, out);
163 }
164
165 return 0;
166}
167
169{
170 bNodeSocket *sockA = (bNodeSocket *)BLI_findlink(&node->inputs, 0);
171 bNodeSocket *sockB = (bNodeSocket *)BLI_findlink(&node->inputs, 1);
172 bNodeSocket *sockC = (bNodeSocket *)BLI_findlink(&node->inputs, 2);
173 bNodeSocket *sockScale = bke::node_find_socket(*node, SOCK_IN, "Scale");
174
175 bNodeSocket *sockVector = bke::node_find_socket(*node, SOCK_OUT, "Vector");
176 bNodeSocket *sockValue = bke::node_find_socket(*node, SOCK_OUT, "Value");
177
179 *sockB,
180 !ELEM(node->custom1,
193 *sockC,
194 ELEM(node->custom1,
199 *ntree, *sockScale, ELEM(node->custom1, NODE_VECTOR_MATH_SCALE, NODE_VECTOR_MATH_REFRACT));
201 *sockVector,
202 !ELEM(node->custom1,
207 *sockValue,
208 ELEM(node->custom1,
212
213 /* Labels */
217 node_sock_label_clear(sockScale);
218 switch (node->custom1) {
220 node_sock_label(sockA, "Base");
221 node_sock_label(sockB, "Exponent");
222 break;
224 node_sock_label(sockB, "Multiplier");
225 node_sock_label(sockC, "Addend");
226 break;
228 node_sock_label(sockB, "Incident");
229 node_sock_label(sockC, "Reference");
230 break;
232 node_sock_label(sockB, "Max");
233 node_sock_label(sockC, "Min");
234 break;
236 node_sock_label(sockB, "Increment");
237 break;
239 node_sock_label(sockScale, "IOR");
240 break;
242 node_sock_label(sockScale, "Scale");
243 break;
244 }
245}
246
247static const mf::MultiFunction *get_multi_function(const bNode &node)
248{
250
251 const mf::MultiFunction *multi_fn = nullptr;
252
254 operation, [&](auto exec_preset, auto function, const FloatMathOperationInfo &info) {
255 static auto fn = mf::build::SI2_SO<float3, float3, float3>(
256 info.title_case_name.c_str(), function, exec_preset);
257 multi_fn = &fn;
258 });
259 if (multi_fn != nullptr) {
260 return multi_fn;
261 }
262
264 operation, [&](auto exec_preset, auto function, const FloatMathOperationInfo &info) {
265 static auto fn = mf::build::SI3_SO<float3, float3, float3, float3>(
266 info.title_case_name.c_str(), function, exec_preset);
267 multi_fn = &fn;
268 });
269 if (multi_fn != nullptr) {
270 return multi_fn;
271 }
272
274 operation, [&](auto exec_preset, auto function, const FloatMathOperationInfo &info) {
275 static auto fn = mf::build::SI3_SO<float3, float3, float, float3>(
276 info.title_case_name.c_str(), function, exec_preset);
277 multi_fn = &fn;
278 });
279 if (multi_fn != nullptr) {
280 return multi_fn;
281 }
282
284 operation, [&](auto exec_preset, auto function, const FloatMathOperationInfo &info) {
285 static auto fn = mf::build::SI2_SO<float3, float3, float>(
286 info.title_case_name.c_str(), function, exec_preset);
287 multi_fn = &fn;
288 });
289 if (multi_fn != nullptr) {
290 return multi_fn;
291 }
292
294 operation, [&](auto exec_preset, auto function, const FloatMathOperationInfo &info) {
295 static auto fn = mf::build::SI2_SO<float3, float, float3>(
296 info.title_case_name.c_str(), function, exec_preset);
297 multi_fn = &fn;
298 });
299 if (multi_fn != nullptr) {
300 return multi_fn;
301 }
302
304 operation, [&](auto exec_preset, auto function, const FloatMathOperationInfo &info) {
305 static auto fn = mf::build::SI1_SO<float3, float3>(
306 info.title_case_name.c_str(), function, exec_preset);
307 multi_fn = &fn;
308 });
309 if (multi_fn != nullptr) {
310 return multi_fn;
311 }
312
314 operation, [&](auto exec_preset, auto function, const FloatMathOperationInfo &info) {
315 static auto fn = mf::build::SI1_SO<float3, float>(
316 info.title_case_name.c_str(), function, exec_preset);
317 multi_fn = &fn;
318 });
319 if (multi_fn != nullptr) {
320 return multi_fn;
321 }
322
323 return nullptr;
324}
325
327{
328 const mf::MultiFunction *fn = get_multi_function(builder.node());
329 builder.set_matching_fn(fn);
330}
331
333{
334 using namespace value_elem;
336 switch (op) {
341 VectorElem output_elem;
342 output_elem.merge(params.get_input_elem<VectorElem>("Vector"));
343 output_elem.merge(params.get_input_elem<VectorElem>("Vector_001"));
344 params.set_output_elem("Vector", output_elem);
345 break;
346 }
348 VectorElem output_elem;
349 output_elem.merge(params.get_input_elem<VectorElem>("Vector"));
350 if (params.get_input_elem<FloatElem>("Scale")) {
351 output_elem = VectorElem::all();
352 }
353 params.set_output_elem("Vector", output_elem);
354 }
355 default:
356 break;
357 }
358}
359
361{
363 switch (op) {
369 params.set_input_elem("Vector", params.get_output_elem<value_elem::VectorElem>("Vector"));
370 break;
371 }
372 default:
373 break;
374 }
375}
376
378{
380 const StringRef first_input_id = "Vector";
381 const StringRef second_input_id = "Vector_001";
382 const StringRef scale_input_id = "Scale";
383 const StringRef output_vector_id = "Vector";
384 switch (op) {
386 params.set_input(first_input_id,
387 params.get_output<float3>(output_vector_id) -
388 params.get_input<float3>(second_input_id));
389 break;
390 }
392 params.set_input(first_input_id,
393 params.get_output<float3>(output_vector_id) +
394 params.get_input<float3>(second_input_id));
395 break;
396 }
398 params.set_input(first_input_id,
399 math::safe_divide(params.get_output<float3>(output_vector_id),
400 params.get_input<float3>(second_input_id)));
401 break;
402 }
404 params.set_input(first_input_id,
405 params.get_output<float3>(output_vector_id) *
406 params.get_input<float3>(second_input_id));
407 break;
408 }
410 params.set_input(first_input_id,
411 math::safe_divide(params.get_output<float3>(output_vector_id),
412 float3(params.get_input<float>(scale_input_id))));
413 break;
414 }
415 default: {
416 break;
417 }
418 }
419}
420
422#ifdef WITH_MATERIALX
423{
424 auto op = node_->custom1;
425 NodeItem res = empty();
426 const NodeItem null_vec = val(MaterialX::Vector3(0.0f));
427
428 /* Single operand operations */
429 NodeItem x = get_input_value(0, NodeItem::Type::Vector3);
430
431 switch (op) {
433 res = x.sin();
434 break;
436 res = x.cos();
437 break;
439 res = x.tan();
440 break;
442 res = x.abs();
443 break;
445 res = x.floor();
446 break;
448 res = x.ceil();
449 break;
451 res = x % val(1.0f);
452 break;
454 res = x.length();
455 break;
457 NodeItem length = x.length();
458 res = length.if_else(NodeItem::CompareOp::Eq, val(0.0f), null_vec, x / length);
459 break;
460 }
461
462 default: {
463 /* 2-operand operations */
464 NodeItem y = get_input_value(1, NodeItem::Type::Vector3);
465 NodeItem w = get_input_value(3, NodeItem::Type::Float);
466
467 switch (op) {
469 res = x + y;
470 break;
472 res = x - y;
473 break;
475 res = x * y;
476 break;
478 res = x / y;
479 break;
481 res = x.min(y);
482 break;
484 res = x.max(y);
485 break;
487 res = x % y;
488 break;
490 res = (x / y).floor() * y;
491 break;
493 res = create_node("crossproduct", NodeItem::Type::Vector3, {{"in1", x}, {"in2", y}});
494 break;
496 res = x.dotproduct(y);
497 break;
499 NodeItem len_sq = y.dotproduct(y);
500 res = len_sq.if_else(
501 NodeItem::CompareOp::NotEq, val(0.0f), (x.dotproduct(y) / len_sq) * y, null_vec);
502 break;
503 }
505 /* TODO: use <reflect> node in MaterialX 1.38.9 */
506 res = x - val(2.0f) * y.dotproduct(x) * y;
507 break;
509 res = (y - x).length();
510 break;
512 res = x * w;
513 break;
514
515 default: {
516 /* 3-operand operations */
517 NodeItem z = get_input_value(2, NodeItem::Type::Vector3);
518
519 switch (op) {
521 res = x * y + z;
522 break;
524 /* TODO: use <refract> node in MaterialX 1.38.9 */
525 NodeItem dot_yx = y.dotproduct(x);
526 NodeItem k = val(1.0f) - (w * w * (val(1.0f) - (dot_yx * dot_yx)));
527 NodeItem r = w * x - ((w * dot_yx + k.sqrt()) * y);
528 res = k.if_else(NodeItem::CompareOp::GreaterEq, val(0.0f), r, null_vec);
529 break;
530 }
532 res = z.dotproduct(y).if_else(NodeItem::CompareOp::GreaterEq, val(0.0f), -x, x);
533 break;
534 }
536 NodeItem range = (y - z);
537 NodeItem if_branch = x - (range * ((x - z) / range).floor());
538
539 res = create_node("combine3", NodeItem::Type::Vector3);
540 std::vector<std::string> inputs = {"in1", "in2", "in3"};
541
542 for (size_t i = 0; i < inputs.size(); ++i) {
543 res.set_input(
544 inputs[i],
545 range[i].if_else(NodeItem::CompareOp::NotEq, val(0.0f), if_branch[i], z[i]));
546 }
547 break;
548 }
549 default:
551 }
552 }
553 }
554 }
555 }
556
557 return res;
558}
559#endif
561
562} // namespace blender::nodes::node_shader_vector_math_cc
563
565{
567
568 static blender::bke::bNodeType ntype;
569
570 common_node_type_base(&ntype, "ShaderNodeVectorMath", SH_NODE_VECTOR_MATH);
571 ntype.ui_name = "Vector Math";
572 ntype.ui_description = "Perform vector math operation";
573 ntype.enum_name_legacy = "VECT_MATH";
575 ntype.declare = file_ns::sh_node_vector_math_declare;
576 ntype.draw_buttons = file_ns::node_shader_buts_vect_math;
578 ntype.gpu_fn = file_ns::gpu_shader_vector_math;
579 ntype.updatefunc = file_ns::node_shader_update_vector_math;
580 ntype.build_multi_function = file_ns::sh_node_vector_math_build_multi_function;
581 ntype.gather_link_search_ops = file_ns::sh_node_vector_math_gather_link_searches;
582 ntype.materialx_fn = file_ns::node_shader_materialx;
583 ntype.eval_elem = file_ns::node_eval_elem;
584 ntype.eval_inverse_elem = file_ns::node_eval_inverse_elem;
585 ntype.eval_inverse = file_ns::node_eval_inverse;
586
588}
#define NODE_CLASS_OP_VECTOR
Definition BKE_node.hh:450
#define SH_NODE_VECTOR_MATH
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
void * BLI_findlink(const ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:534
#define ELEM(...)
#define BLT_I18NCONTEXT_ID_NODETREE
#define CTX_IFACE_(context, msgid)
NodeVectorMathOperation
@ NODE_VECTOR_MATH_NORMALIZE
@ NODE_VECTOR_MATH_LENGTH
@ NODE_VECTOR_MATH_SIGN
@ 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_POWER
@ 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_MULTIPLY_ADD
@ NODE_VECTOR_MATH_MINIMUM
@ SOCK_OUT
@ SOCK_IN
eNodeSocketDatatype
@ SOCK_VECTOR
@ SOCK_RGBA
bool GPU_stack_link(GPUMaterial *mat, const bNode *node, const char *name, GPUNodeStack *in, GPUNodeStack *out,...)
@ UI_ITEM_R_SPLIT_EMPTY_NAME
SIMD_FORCE_INLINE const btScalar & z() const
Return the z value.
Definition btQuadWord.h:117
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
SIMD_FORCE_INLINE btScalar length() const
Return the length of the vector.
Definition btVector3.h:257
constexpr const char * c_str() const
void set_matching_fn(const mf::MultiFunction *fn)
#define in
#define out
#define floor
float length(VecOp< float, D >) RET
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
bNodeSocket * node_find_socket(bNode &node, eNodeSocketInOut in_out, StringRef identifier)
Definition node.cc:2532
void node_register_type(bNodeType &ntype)
Definition node.cc:2416
void node_set_socket_availability(bNodeTree &ntree, bNodeSocket &sock, bool is_available)
Definition node.cc:4739
T safe_divide(const T &a, const T &b)
static void sh_node_vector_math_build_multi_function(NodeMultiFunctionBuilder &builder)
static int gpu_shader_vector_math(GPUMaterial *mat, bNode *node, bNodeExecData *, GPUNodeStack *in, GPUNodeStack *out)
static void node_shader_buts_vect_math(uiLayout *layout, bContext *, PointerRNA *ptr)
static void sh_node_vector_math_gather_link_searches(GatherLinkSearchOpParams &params)
static void node_eval_elem(value_elem::ElemEvalParams &params)
static const mf::MultiFunction * get_multi_function(const bNode &node)
static void node_eval_inverse(inverse_eval::InverseEvalParams &params)
static void node_shader_update_vector_math(bNodeTree *ntree, bNode *node)
static void sh_node_vector_math_declare(NodeDeclarationBuilder &b)
static void node_eval_inverse_elem(value_elem::InverseElemEvalParams &params)
bool try_dispatch_float_math_fl3_fl3_to_fl3(const NodeVectorMathOperation operation, Callback &&callback)
bool try_dispatch_float_math_fl3_to_fl(const NodeVectorMathOperation operation, Callback &&callback)
bool try_dispatch_float_math_fl3_fl3_to_fl(const NodeVectorMathOperation operation, Callback &&callback)
bool try_dispatch_float_math_fl3_fl_to_fl3(const NodeVectorMathOperation operation, Callback &&callback)
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)
bool try_dispatch_float_math_fl3_fl3_fl3_to_fl3(const NodeVectorMathOperation operation, Callback &&callback)
VecBase< float, 3 > float3
#define NODE_SHADER_MATERIALX_BEGIN
#define NODE_SHADER_MATERIALX_END
void common_node_type_base(blender::bke::bNodeType *ntype, std::string idname, const std::optional< int16_t > legacy_type)
void register_node_type_sh_vect_math()
static blender::bke::bNodeSocketTemplate inputs[]
void node_sock_label_clear(bNodeSocket *sock)
Definition node_util.cc:78
void node_sock_label(bNodeSocket *sock, const char *name)
Definition node_util.cc:73
void node_vector_math_label(const bNodeTree *, const bNode *node, char *label, int label_maxncpy)
Definition node_util.cc:214
const char * name
const EnumPropertyItem rna_enum_node_vec_math_items[]
#define min(a, b)
Definition sort.cc:36
int16_t custom1
ListBase inputs
Defines a node type.
Definition BKE_node.hh:238
NodeInverseElemEvalFunction eval_inverse_elem
Definition BKE_node.hh:403
NodeMaterialXFunction materialx_fn
Definition BKE_node.hh:344
NodeInverseEvalFunction eval_inverse
Definition BKE_node.hh:410
std::string ui_description
Definition BKE_node.hh:244
void(* labelfunc)(const bNodeTree *ntree, const bNode *node, char *label, int label_maxncpy)
Definition BKE_node.hh:270
NodeGPUExecFunction gpu_fn
Definition BKE_node.hh:342
NodeElemEvalFunction eval_elem
Definition BKE_node.hh:397
NodeMultiFunctionBuildFunction build_multi_function
Definition BKE_node.hh:351
const char * enum_name_legacy
Definition BKE_node.hh:247
void(* draw_buttons)(uiLayout *, bContext *C, PointerRNA *ptr)
Definition BKE_node.hh:259
NodeGatherSocketLinkOperationsFunction gather_link_search_ops
Definition BKE_node.hh:378
NodeDeclareFunction declare
Definition BKE_node.hh:362
void(* updatefunc)(bNodeTree *ntree, bNode *node)
Definition BKE_node.hh:281
void prop(PointerRNA *ptr, PropertyRNA *prop, int index, int value, eUI_Item_Flag flag, std::optional< blender::StringRef > name_opt, int icon, std::optional< blender::StringRef > placeholder=std::nullopt)
i
Definition text_draw.cc:230
PointerRNA * ptr
Definition wm_files.cc:4238