Blender V4.3
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
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
20#include "UI_interface.hh"
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 uiItemR(layout, 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(
56 static_cast<eNodeSocketDatatype>(params.other_socket().type), SOCK_VECTOR))
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";
145 }
146
147 return nullptr;
148}
149
151 bNode *node,
152 bNodeExecData * /*execdata*/,
153 GPUNodeStack *in,
154 GPUNodeStack *out)
155{
156 const char *name = gpu_shader_get_name(node->custom1);
157 if (name != nullptr) {
158 return GPU_stack_link(mat, node, name, in, out);
159 }
160
161 return 0;
162}
163
165{
166 bNodeSocket *sockB = (bNodeSocket *)BLI_findlink(&node->inputs, 1);
167 bNodeSocket *sockC = (bNodeSocket *)BLI_findlink(&node->inputs, 2);
168 bNodeSocket *sockScale = bke::node_find_socket(node, SOCK_IN, "Scale");
169
170 bNodeSocket *sockVector = bke::node_find_socket(node, SOCK_OUT, "Vector");
171 bNodeSocket *sockValue = bke::node_find_socket(node, SOCK_OUT, "Value");
172
174 sockB,
175 !ELEM(node->custom1,
187 sockC,
188 ELEM(node->custom1,
193 ntree, sockScale, ELEM(node->custom1, NODE_VECTOR_MATH_SCALE, NODE_VECTOR_MATH_REFRACT));
195 sockVector,
196 !ELEM(node->custom1,
201 sockValue,
202 ELEM(node->custom1,
206
207 /* Labels */
210 node_sock_label_clear(sockScale);
211 switch (node->custom1) {
213 node_sock_label(sockB, "Multiplier");
214 node_sock_label(sockC, "Addend");
215 break;
217 node_sock_label(sockB, "Incident");
218 node_sock_label(sockC, "Reference");
219 break;
221 node_sock_label(sockB, "Max");
222 node_sock_label(sockC, "Min");
223 break;
225 node_sock_label(sockB, "Increment");
226 break;
228 node_sock_label(sockScale, "IOR");
229 break;
231 node_sock_label(sockScale, "Scale");
232 break;
233 }
234}
235
237{
238 NodeVectorMathOperation operation = NodeVectorMathOperation(node.custom1);
239
240 const mf::MultiFunction *multi_fn = nullptr;
241
243 operation, [&](auto exec_preset, auto function, const FloatMathOperationInfo &info) {
244 static auto fn = mf::build::SI2_SO<float3, float3, float3>(
245 info.title_case_name.c_str(), function, exec_preset);
246 multi_fn = &fn;
247 });
248 if (multi_fn != nullptr) {
249 return multi_fn;
250 }
251
253 operation, [&](auto exec_preset, auto function, const FloatMathOperationInfo &info) {
254 static auto fn = mf::build::SI3_SO<float3, float3, float3, float3>(
255 info.title_case_name.c_str(), function, exec_preset);
256 multi_fn = &fn;
257 });
258 if (multi_fn != nullptr) {
259 return multi_fn;
260 }
261
263 operation, [&](auto exec_preset, auto function, const FloatMathOperationInfo &info) {
264 static auto fn = mf::build::SI3_SO<float3, float3, float, float3>(
265 info.title_case_name.c_str(), function, exec_preset);
266 multi_fn = &fn;
267 });
268 if (multi_fn != nullptr) {
269 return multi_fn;
270 }
271
273 operation, [&](auto exec_preset, auto function, const FloatMathOperationInfo &info) {
274 static auto fn = mf::build::SI2_SO<float3, float3, float>(
275 info.title_case_name.c_str(), function, exec_preset);
276 multi_fn = &fn;
277 });
278 if (multi_fn != nullptr) {
279 return multi_fn;
280 }
281
283 operation, [&](auto exec_preset, auto function, const FloatMathOperationInfo &info) {
284 static auto fn = mf::build::SI2_SO<float3, float, float3>(
285 info.title_case_name.c_str(), function, exec_preset);
286 multi_fn = &fn;
287 });
288 if (multi_fn != nullptr) {
289 return multi_fn;
290 }
291
293 operation, [&](auto exec_preset, auto function, const FloatMathOperationInfo &info) {
294 static auto fn = mf::build::SI1_SO<float3, float3>(
295 info.title_case_name.c_str(), function, exec_preset);
296 multi_fn = &fn;
297 });
298 if (multi_fn != nullptr) {
299 return multi_fn;
300 }
301
303 operation, [&](auto exec_preset, auto function, const FloatMathOperationInfo &info) {
304 static auto fn = mf::build::SI1_SO<float3, float>(
305 info.title_case_name.c_str(), function, exec_preset);
306 multi_fn = &fn;
307 });
308 if (multi_fn != nullptr) {
309 return multi_fn;
310 }
311
312 return nullptr;
313}
314
316{
317 const mf::MultiFunction *fn = get_multi_function(builder.node());
318 builder.set_matching_fn(fn);
319}
320
322{
323 using namespace value_elem;
325 switch (op) {
330 VectorElem output_elem;
331 output_elem.merge(params.get_input_elem<VectorElem>("Vector"));
332 output_elem.merge(params.get_input_elem<VectorElem>("Vector_001"));
333 params.set_output_elem("Vector", output_elem);
334 break;
335 }
337 VectorElem output_elem;
338 output_elem.merge(params.get_input_elem<VectorElem>("Vector"));
339 if (params.get_input_elem<FloatElem>("Scale")) {
340 output_elem = VectorElem::all();
341 }
342 params.set_output_elem("Vector", output_elem);
343 }
344 default:
345 break;
346 }
347}
348
350{
352 switch (op) {
358 params.set_input_elem("Vector", params.get_output_elem<value_elem::VectorElem>("Vector"));
359 break;
360 }
361 default:
362 break;
363 }
364}
365
367{
369 const StringRef first_input_id = "Vector";
370 const StringRef second_input_id = "Vector_001";
371 const StringRef scale_input_id = "Scale";
372 const StringRef output_vector_id = "Vector";
373 switch (op) {
375 params.set_input(first_input_id,
376 params.get_output<float3>(output_vector_id) -
377 params.get_input<float3>(second_input_id));
378 break;
379 }
381 params.set_input(first_input_id,
382 params.get_output<float3>(output_vector_id) +
383 params.get_input<float3>(second_input_id));
384 break;
385 }
387 params.set_input(first_input_id,
388 math::safe_divide(params.get_output<float3>(output_vector_id),
389 params.get_input<float3>(second_input_id)));
390 break;
391 }
393 params.set_input(first_input_id,
394 params.get_output<float3>(output_vector_id) *
395 params.get_input<float3>(second_input_id));
396 break;
397 }
399 params.set_input(first_input_id,
400 math::safe_divide(params.get_output<float3>(output_vector_id),
401 float3(params.get_input<float>(scale_input_id))));
402 break;
403 }
404 default: {
405 break;
406 }
407 }
408}
409
411#ifdef WITH_MATERIALX
412{
413 auto op = node_->custom1;
414 NodeItem res = empty();
415 const NodeItem null_vec = val(MaterialX::Vector3(0.0f));
416
417 /* Single operand operations */
418 NodeItem x = get_input_value(0, NodeItem::Type::Vector3);
419
420 switch (op) {
422 res = x.sin();
423 break;
425 res = x.cos();
426 break;
428 res = x.tan();
429 break;
431 res = x.abs();
432 break;
434 res = x.floor();
435 break;
437 res = x.ceil();
438 break;
440 res = x % val(1.0f);
441 break;
443 res = x.length();
444 break;
446 NodeItem length = x.length();
447 res = length.if_else(NodeItem::CompareOp::Eq, val(0.0f), null_vec, x / length);
448 break;
449 }
450
451 default: {
452 /* 2-operand operations */
453 NodeItem y = get_input_value(1, NodeItem::Type::Vector3);
454 NodeItem w = get_input_value(3, NodeItem::Type::Float);
455
456 switch (op) {
458 res = x + y;
459 break;
461 res = x - y;
462 break;
464 res = x * y;
465 break;
467 res = x / y;
468 break;
470 res = x.min(y);
471 break;
473 res = x.max(y);
474 break;
476 res = x % y;
477 break;
479 res = (x / y).floor() * y;
480 break;
482 res = create_node("crossproduct", NodeItem::Type::Vector3, {{"in1", x}, {"in2", y}});
483 break;
485 res = x.dotproduct(y);
486 break;
488 NodeItem len_sq = y.dotproduct(y);
489 res = len_sq.if_else(
490 NodeItem::CompareOp::NotEq, val(0.0f), (x.dotproduct(y) / len_sq) * y, null_vec);
491 break;
492 }
494 /* TODO: use <reflect> node in MaterialX 1.38.9 */
495 res = x - val(2.0f) * y.dotproduct(x) * y;
496 break;
498 res = (y - x).length();
499 break;
501 res = x * w;
502 break;
503
504 default: {
505 /* 3-operand operations */
506 NodeItem z = get_input_value(2, NodeItem::Type::Vector3);
507
508 switch (op) {
510 res = x * y + z;
511 break;
513 /* TODO: use <refract> node in MaterialX 1.38.9 */
514 NodeItem dot_yx = y.dotproduct(x);
515 NodeItem k = val(1.0f) - (w * w * (val(1.0f) - (dot_yx * dot_yx)));
516 NodeItem r = w * x - ((w * dot_yx + k.sqrt()) * y);
517 res = k.if_else(NodeItem::CompareOp::GreaterEq, val(0.0f), r, null_vec);
518 break;
519 }
521 res = z.dotproduct(y).if_else(NodeItem::CompareOp::GreaterEq, val(0.0f), -x, x);
522 break;
523 }
525 NodeItem range = (y - z);
526 NodeItem if_branch = x - (range * ((x - z) / range).floor());
527
528 res = create_node("combine3", NodeItem::Type::Vector3);
529 std::vector<std::string> inputs = {"in1", "in2", "in3"};
530
531 for (size_t i = 0; i < inputs.size(); ++i) {
532 res.set_input(
533 inputs[i],
534 range[i].if_else(NodeItem::CompareOp::NotEq, val(0.0f), if_branch[i], z[i]));
535 }
536 break;
537 }
538 default:
540 }
541 }
542 }
543 }
544 }
545
546 return res;
547}
548#endif
550
551} // namespace blender::nodes::node_shader_vector_math_cc
552
554{
556
557 static blender::bke::bNodeType ntype;
558
560 ntype.declare = file_ns::sh_node_vector_math_declare;
561 ntype.draw_buttons = file_ns::node_shader_buts_vect_math;
563 ntype.gpu_fn = file_ns::gpu_shader_vector_math;
564 ntype.updatefunc = file_ns::node_shader_update_vector_math;
565 ntype.build_multi_function = file_ns::sh_node_vector_math_build_multi_function;
566 ntype.gather_link_search_ops = file_ns::sh_node_vector_math_gather_link_searches;
567 ntype.materialx_fn = file_ns::node_shader_materialx;
568 ntype.eval_elem = file_ns::node_eval_elem;
569 ntype.eval_inverse_elem = file_ns::node_eval_inverse_elem;
570 ntype.eval_inverse = file_ns::node_eval_inverse;
571
573}
#define SH_NODE_VECTOR_MATH
Definition BKE_node.hh:905
#define NODE_CLASS_OP_VECTOR
Definition BKE_node.hh:407
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
void * BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
#define ELEM(...)
#define BLT_I18NCONTEXT_ID_NODETREE
#define CTX_IFACE_(context, msgid)
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_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,...)
void uiItemR(uiLayout *layout, PointerRNA *ptr, const char *propname, eUI_Item_Flag flag, const char *name, int icon)
@ 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)
local_group_size(16, 16) .push_constant(Type b
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
ccl_device_inline float2 floor(const float2 a)
void node_set_socket_availability(bNodeTree *ntree, bNodeSocket *sock, bool is_available)
Definition node.cc:3911
void node_register_type(bNodeType *ntype)
Definition node.cc:1708
bNodeSocket * node_find_socket(bNode *node, eNodeSocketInOut in_out, StringRef identifier)
Definition node.cc:1829
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)
#define NODE_SHADER_MATERIALX_BEGIN
#define NODE_SHADER_MATERIALX_END
void sh_fn_node_type_base(blender::bke::bNodeType *ntype, int type, const char *name, short nclass)
void register_node_type_sh_vect_math()
void node_sock_label_clear(bNodeSocket *sock)
Definition node_util.cc:82
void node_sock_label(bNodeSocket *sock, const char *name)
Definition node_util.cc:77
void node_vector_math_label(const bNodeTree *, const bNode *node, char *label, int label_maxncpy)
Definition node_util.cc:216
const EnumPropertyItem rna_enum_node_vec_math_items[]
#define min(a, b)
Definition sort.c:32
const char * identifier
Definition RNA_types.hh:506
Defines a node type.
Definition BKE_node.hh:218
NodeInverseElemEvalFunction eval_inverse_elem
Definition BKE_node.hh:378
NodeMaterialXFunction materialx_fn
Definition BKE_node.hh:320
NodeInverseEvalFunction eval_inverse
Definition BKE_node.hh:385
void(* labelfunc)(const bNodeTree *ntree, const bNode *node, char *label, int label_maxncpy)
Definition BKE_node.hh:249
NodeGPUExecFunction gpu_fn
Definition BKE_node.hh:318
NodeElemEvalFunction eval_elem
Definition BKE_node.hh:372
NodeMultiFunctionBuildFunction build_multi_function
Definition BKE_node.hh:336
void(* draw_buttons)(uiLayout *, bContext *C, PointerRNA *ptr)
Definition BKE_node.hh:238
NodeGatherSocketLinkOperationsFunction gather_link_search_ops
Definition BKE_node.hh:363
NodeDeclareFunction declare
Definition BKE_node.hh:347
void(* updatefunc)(bNodeTree *ntree, bNode *node)
Definition BKE_node.hh:257
PointerRNA * ptr
Definition wm_files.cc:4126