Blender V5.0
inverse_eval.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2024 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include <fmt/format.h>
6
11#include "NOD_partial_eval.hh"
13
15#include "BKE_context.hh"
16#include "BKE_library.hh"
17#include "BKE_modifier.hh"
18#include "BKE_node.hh"
20#include "BKE_node_runtime.hh"
23
24#include "BLI_map.hh"
25#include "BLI_math_euler.hh"
26#include "BLI_set.hh"
27#include "BLI_string.h"
28
29#include "DEG_depsgraph.hh"
30
31#include "ED_node.hh"
32
33#include "RNA_access.hh"
34#include "RNA_path.hh"
35
36#include "MOD_nodes.hh"
37
38#include "ANIM_keyframing.hh"
39
41
42using namespace value_elem;
43
44std::optional<SocketValueVariant> convert_single_socket_value(const bNodeSocket &old_socket,
45 const bNodeSocket &new_socket,
46 const SocketValueVariant &old_value)
47{
48 const eNodeSocketDatatype old_type = eNodeSocketDatatype(old_socket.type);
49 const eNodeSocketDatatype new_type = eNodeSocketDatatype(new_socket.type);
50 if (old_type == new_type) {
51 return old_value;
52 }
53 const CPPType *old_cpp_type = old_socket.typeinfo->base_cpp_type;
54 const CPPType *new_cpp_type = new_socket.typeinfo->base_cpp_type;
55 if (!old_cpp_type || !new_cpp_type) {
56 return std::nullopt;
57 }
59 if (type_conversions.is_convertible(*old_cpp_type, *new_cpp_type)) {
60 const void *old_value_ptr = old_value.get_single_ptr_raw();
61 SocketValueVariant new_value;
62 void *new_value_ptr = new_value.allocate_single(new_type);
63 type_conversions.convert_to_uninitialized(
64 *old_cpp_type, *new_cpp_type, old_value_ptr, new_value_ptr);
65 return new_value;
66 }
67 return std::nullopt;
68}
69
70static void evaluate_node_elem_upstream(const NodeInContext &ctx_node,
71 Vector<const bNodeSocket *> &r_modified_inputs,
73{
74 const bNode &node = *ctx_node.node;
75 const bke::bNodeType &ntype = *node.typeinfo;
76 if (!ntype.eval_inverse_elem) {
77 /* Node does not support inverse evaluation. */
78 return;
79 }
80 /* Build temporary map to be used by node evaluation function. */
81 Map<const bNodeSocket *, ElemVariant> elem_by_local_socket;
82 for (const bNodeSocket *output_socket : node.output_sockets()) {
83 if (const ElemVariant *elem = elem_by_socket.lookup_ptr({ctx_node.context, output_socket})) {
84 elem_by_local_socket.add(output_socket, *elem);
85 }
86 }
87 Vector<SocketElem> input_elems;
88 InverseElemEvalParams params{node, elem_by_local_socket, input_elems};
90 /* Write back changed socket values to the map. */
91 for (const SocketElem &input_elem : input_elems) {
92 if (input_elem.elem) {
93 elem_by_socket.add({ctx_node.context, input_elem.socket}, input_elem.elem);
94 r_modified_inputs.append(input_elem.socket);
95 }
96 }
97}
98
99static bool propagate_socket_elem(const SocketInContext &ctx_from,
100 const SocketInContext &ctx_to,
101 Map<SocketInContext, ElemVariant> &elem_by_socket)
102{
103 const ElemVariant *from_elem = elem_by_socket.lookup_ptr(ctx_from);
104 if (!from_elem) {
105 return false;
106 }
107 /* Perform implicit conversion if necessary. */
108 const std::optional<ElemVariant> to_elem = convert_socket_elem(
109 *ctx_from.socket, *ctx_to.socket, *from_elem);
110 if (!to_elem || !*to_elem) {
111 return false;
112 }
113 elem_by_socket.lookup_or_add(ctx_to, *to_elem).merge(*to_elem);
114 return true;
115}
116
117static void get_input_elems_to_propagate(const NodeInContext &ctx_node,
119 Map<SocketInContext, ElemVariant> &elem_by_socket)
120{
121 for (const bNodeSocket *socket : ctx_node.node->input_sockets()) {
122 if (elem_by_socket.contains({ctx_node.context, socket})) {
123 r_sockets.append(socket);
124 }
125 }
126}
127
129 const SocketElem &initial_socket_elem)
130{
131 BLI_assert(!tree.has_available_link_cycle());
132
133 tree.ensure_topology_cache();
134
135 bke::ComputeContextCache compute_context_cache;
137 elem_by_socket.add({nullptr, initial_socket_elem.socket}, initial_socket_elem.elem);
138
140 {{nullptr, initial_socket_elem.socket}},
141 compute_context_cache,
142 /* Evaluate node. */
143 [&](const NodeInContext &ctx_node, Vector<const bNodeSocket *> &r_modified_inputs) {
144 evaluate_node_elem_upstream(ctx_node, r_modified_inputs, elem_by_socket);
145 },
146 /* Propagate value. */
147 [&](const SocketInContext &ctx_from, const SocketInContext &ctx_to) {
148 return propagate_socket_elem(ctx_from, ctx_to, elem_by_socket);
149 },
150 /* Get input sockets to propagate. */
151 [&](const NodeInContext &ctx_node, Vector<const bNodeSocket *> &r_sockets) {
152 get_input_elems_to_propagate(ctx_node, r_sockets, elem_by_socket);
153 });
154
156
157 for (const SocketInContext &ctx_socket : upstream_eval_targets.sockets) {
158 if (ctx_socket.context) {
159 /* Context should be empty because we only handle top-level sockets here. */
160 continue;
161 }
162 const ElemVariant *elem = elem_by_socket.lookup_ptr(ctx_socket);
163 if (!elem || !*elem) {
164 continue;
165 }
166 targets.input_sockets.append({ctx_socket.socket, *elem});
167 }
168
169 for (const NodeInContext ctx_node : upstream_eval_targets.value_nodes) {
170 if (ctx_node.context) {
171 /* Context should be empty because we only handle top-level nodes here. */
172 continue;
173 }
174 const bNodeSocket &socket = ctx_node.node->output_socket(0);
175 const ElemVariant *elem = elem_by_socket.lookup_ptr({nullptr, &socket});
176 if (!elem || !*elem) {
177 continue;
178 }
179 targets.value_nodes.append({ctx_node.node, *elem});
180 }
181
182 for (const int group_input_index : tree.interface_inputs().index_range()) {
184 tree.interface_inputs()[group_input_index]->socket_typeinfo()->type);
185 std::optional<ElemVariant> elem = get_elem_variant_for_socket_type(type);
186 if (!elem) {
187 continue;
188 }
189 /* Combine the elems from each group input node. */
190 for (const bNode *node : tree.group_input_nodes()) {
191 const bNodeSocket &socket = node->output_socket(group_input_index);
192 if (const ElemVariant *socket_elem = elem_by_socket.lookup_ptr({nullptr, &socket})) {
193 elem->merge(*socket_elem);
194 }
195 }
196 if (!*elem) {
197 continue;
198 }
199 targets.group_inputs.append({group_input_index, *elem});
200 }
201
202 return targets;
203}
204
206 const NodeInContext &ctx_node,
207 const Map<SocketInContext, ElemVariant> &elem_by_socket_filter,
208 Map<SocketInContext, ElemVariant> &elem_by_socket,
209 Vector<const bNodeSocket *> &r_outputs_to_propagate)
210{
211 const bNode &node = *ctx_node.node;
212 const bke::bNodeType &ntype = *node.typeinfo;
213 if (!ntype.eval_elem) {
214 return;
215 }
216 /* Build temporary map used by the node evaluation. */
217 Map<const bNodeSocket *, ElemVariant> elem_by_local_socket;
218 for (const bNodeSocket *input_socket : node.input_sockets()) {
219 if (const ElemVariant *elem = elem_by_socket.lookup_ptr({ctx_node.context, input_socket})) {
220 elem_by_local_socket.add(input_socket, *elem);
221 }
222 }
223 Vector<SocketElem> output_elems;
224 ElemEvalParams params{node, elem_by_local_socket, output_elems};
225 ntype.eval_elem(params);
226 /* Filter and store the outputs generated by the node evaluation. */
227 for (const SocketElem &output_elem : output_elems) {
228 if (output_elem.elem) {
229 if (const ElemVariant *elem_filter = elem_by_socket_filter.lookup_ptr(
230 {ctx_node.context, output_elem.socket}))
231 {
232 ElemVariant new_elem = *elem_filter;
233 new_elem.intersect(output_elem.elem);
234 elem_by_socket.add({ctx_node.context, output_elem.socket}, new_elem);
235 if (new_elem) {
236 r_outputs_to_propagate.append(output_elem.socket);
237 }
238 }
239 }
240 }
241}
242
244 const SocketInContext &ctx_from,
245 const SocketInContext &ctx_to,
246 const Map<SocketInContext, ElemVariant> &elem_by_socket_filter,
247 Map<SocketInContext, ElemVariant> &elem_by_socket)
248{
249 const ElemVariant *from_elem = elem_by_socket.lookup_ptr(ctx_from);
250 if (!from_elem) {
251 return false;
252 }
253 const ElemVariant *to_elem_filter = elem_by_socket_filter.lookup_ptr(ctx_to);
254 if (!to_elem_filter) {
255 return false;
256 }
257 const std::optional<ElemVariant> converted_elem = convert_socket_elem(
258 *ctx_from.socket, *ctx_to.socket, *from_elem);
259 if (!converted_elem) {
260 return false;
261 }
262 if (ctx_to.socket->is_multi_input()) {
263 ElemVariant added_elem = *converted_elem;
264 added_elem.intersect(*to_elem_filter);
265 elem_by_socket.lookup_or_add(ctx_to, added_elem).merge(added_elem);
266 return true;
267 }
268 ElemVariant to_elem = *to_elem_filter;
269 to_elem.intersect(*converted_elem);
270 elem_by_socket.add(ctx_to, to_elem);
271 return true;
272}
273
275 const ComputeContext &initial_context,
276 const SocketElem &initial_socket_elem,
277 FunctionRef<void(const ComputeContext &context)> foreach_context_fn,
278 FunctionRef<void(const ComputeContext &context,
279 const bNodeSocket &socket,
280 const ElemVariant &elem)> foreach_socket_fn)
281{
282 BLI_assert(initial_socket_elem.socket->is_input());
283 if (!initial_socket_elem.elem) {
284 return;
285 }
286 bke::ComputeContextCache compute_context_cache;
287 Map<SocketInContext, ElemVariant> upstream_elem_by_socket;
288 upstream_elem_by_socket.add({&initial_context, initial_socket_elem.socket},
289 initial_socket_elem.elem);
290
291 /* In a first pass, propagate upstream to find the upstream targets. */
293 {{&initial_context, initial_socket_elem.socket}},
294 compute_context_cache,
295 /* Evaluate node. */
296 [&](const NodeInContext &ctx_node, Vector<const bNodeSocket *> &r_modified_inputs) {
297 evaluate_node_elem_upstream(ctx_node, r_modified_inputs, upstream_elem_by_socket);
298 },
299 /* Propagate value. */
300 [&](const SocketInContext &ctx_from, const SocketInContext &ctx_to) {
301 return propagate_socket_elem(ctx_from, ctx_to, upstream_elem_by_socket);
302 },
303 /* Get input sockets to propagate. */
304 [&](const NodeInContext &ctx_node, Vector<const bNodeSocket *> &r_sockets) {
305 get_input_elems_to_propagate(ctx_node, r_sockets, upstream_elem_by_socket);
306 });
307
308 /* The upstream propagation may also follow node paths that don't end up in upstream targets.
309 * That can happen if there is a node on the path that does not support inverse evaluation. In
310 * this case, parts of the evaluation path has to be discarded again. This is done using a second
311 * pass. Now we start the evaluation at the discovered upstream targets and propagate the changed
312 * socket elements downstream. We only care about the sockets that have already been used by
313 * upstream evaluation, therefor the downstream evaluation is filtered. */
314
315 /* Gather all upstream evaluation targets to start downstream evaluation there. */
316 Vector<SocketInContext> initial_downstream_evaluation_sockets;
317 initial_downstream_evaluation_sockets.extend(upstream_eval_targets.sockets.begin(),
318 upstream_eval_targets.sockets.end());
319 initial_downstream_evaluation_sockets.extend(upstream_eval_targets.group_inputs.begin(),
320 upstream_eval_targets.group_inputs.end());
321 for (const NodeInContext &ctx_node : upstream_eval_targets.value_nodes) {
322 initial_downstream_evaluation_sockets.append(
323 {ctx_node.context, &ctx_node.node->output_socket(0)});
324 }
325
326 Map<SocketInContext, ElemVariant> final_elem_by_socket;
327 for (const SocketInContext &ctx_socket : initial_downstream_evaluation_sockets) {
328 final_elem_by_socket.add(ctx_socket, upstream_elem_by_socket.lookup(ctx_socket));
329 }
330
332 initial_downstream_evaluation_sockets,
333 compute_context_cache,
334 /* Evaluate node. */
335 [&](const NodeInContext &ctx_node, Vector<const bNodeSocket *> &r_outputs_to_propagate) {
337 ctx_node, upstream_elem_by_socket, final_elem_by_socket, r_outputs_to_propagate);
338 },
339 /* Propagate value. */
340 [&](const SocketInContext &ctx_from, const SocketInContext &ctx_to) {
342 ctx_from, ctx_to, upstream_elem_by_socket, final_elem_by_socket);
343 });
344
345 if (foreach_context_fn) {
346 Set<ComputeContextHash> handled_hashes;
347 for (const SocketInContext &ctx_socket : final_elem_by_socket.keys()) {
348 if (handled_hashes.add(ctx_socket.context->hash())) {
349 foreach_context_fn(*ctx_socket.context);
350 }
351 }
352 }
353 if (foreach_socket_fn) {
354 for (auto &&item : final_elem_by_socket.items()) {
355 foreach_socket_fn(*item.key.context, *item.key.socket, item.value);
356 }
357 }
358}
359
360using RNAValueVariant = std::variant<float, int, bool>;
361
363 ID &id,
364 const StringRefNull rna_path,
365 const RNAValueVariant &value_variant)
366{
367 if (!ID_IS_EDITABLE(&id)) {
368 return false;
369 }
370
371 PointerRNA id_ptr = RNA_id_pointer_create(&id);
372 PointerRNA value_ptr;
373 PropertyRNA *prop;
374 int index;
375 if (!RNA_path_resolve_property_full(&id_ptr, rna_path.c_str(), &value_ptr, &prop, &index)) {
376 return false;
377 }
378
379 /* In the future, we could check if there is a driver on the property and propagate the change
380 * backwards through the driver. */
381
382 const PropertyType dst_type = RNA_property_type(prop);
383 const int array_len = RNA_property_array_length(&value_ptr, prop);
384
385 Scene *scene = CTX_data_scene(&C);
386 const bool only_when_keyed = blender::animrig::is_keying_flag(scene,
388
389 switch (dst_type) {
390 case PROP_FLOAT: {
391 float value = std::visit([](auto v) { return float(v); }, value_variant);
392 float soft_min, soft_max, step, precision;
393 RNA_property_float_ui_range(&value_ptr, prop, &soft_min, &soft_max, &step, &precision);
394 value = std::clamp(value, soft_min, soft_max);
395 if (array_len == 0) {
396 RNA_property_float_set(&value_ptr, prop, value);
397 RNA_property_update(&C, &value_ptr, prop);
399 &C, scene, &value_ptr, prop, 0, scene->r.cfra, only_when_keyed);
400 return true;
401 }
402 if (index >= 0 && index < array_len) {
403 RNA_property_float_set_index(&value_ptr, prop, index, value);
404 RNA_property_update(&C, &value_ptr, prop);
406 &C, scene, &value_ptr, prop, index, scene->r.cfra, only_when_keyed);
407 return true;
408 }
409 break;
410 }
411 case PROP_INT: {
412 int value = std::visit([](auto v) { return int(v); }, value_variant);
413 int soft_min, soft_max, step;
414 RNA_property_int_ui_range(&value_ptr, prop, &soft_min, &soft_max, &step);
415 value = std::clamp(value, soft_min, soft_max);
416 if (array_len == 0) {
417 RNA_property_int_set(&value_ptr, prop, value);
418 RNA_property_update(&C, &value_ptr, prop);
420 &C, scene, &value_ptr, prop, 0, scene->r.cfra, only_when_keyed);
421 return true;
422 }
423 if (index >= 0 && index < array_len) {
424 RNA_property_int_set_index(&value_ptr, prop, index, value);
425 RNA_property_update(&C, &value_ptr, prop);
427 &C, scene, &value_ptr, prop, index, scene->r.cfra, only_when_keyed);
428 return true;
429 }
430 break;
431 }
432 case PROP_BOOLEAN: {
433 const bool value = std::visit([](auto v) { return bool(v); }, value_variant);
434 if (array_len == 0) {
435 RNA_property_boolean_set(&value_ptr, prop, value);
436 RNA_property_update(&C, &value_ptr, prop);
438 &C, scene, &value_ptr, prop, 0, scene->r.cfra, only_when_keyed);
439 return true;
440 }
441 if (index >= 0 && index < array_len) {
442 RNA_property_boolean_set_index(&value_ptr, prop, index, value);
443 RNA_property_update(&C, &value_ptr, prop);
445 &C, scene, &value_ptr, prop, index, scene->r.cfra, only_when_keyed);
446 return true;
447 }
448 break;
449 }
450 default:
451 break;
452 };
453
454 return false;
455}
456
458 ID &id,
459 const StringRefNull rna_path,
460 const float3 &value)
461{
462 bool any_success = false;
463 for (const int i : IndexRange(3)) {
464 const std::string rna_path_for_index = fmt::format("{}[{}]", rna_path, i);
465 any_success |= set_rna_property(C, id, rna_path_for_index, value[i]);
466 }
467 return any_success;
468}
469
471 bNodeSocket &socket,
472 const SocketValueVariant &value_variant)
473{
474 bNode &node = socket.owner_node();
475 bNodeTree &tree = socket.owner_tree();
476
477 const std::string default_value_rna_path = fmt::format(
478 "nodes[\"{}\"].inputs[{}].default_value", BLI_str_escape(node.name), socket.index());
479
480 switch (socket.type) {
481 case SOCK_FLOAT: {
482 const float value = value_variant.get<float>();
483 return set_rna_property(C, tree.id, default_value_rna_path, value);
484 }
485 case SOCK_INT: {
486 const int value = value_variant.get<int>();
487 return set_rna_property(C, tree.id, default_value_rna_path, value);
488 }
489 case SOCK_BOOLEAN: {
490 const bool value = value_variant.get<bool>();
491 return set_rna_property(C, tree.id, default_value_rna_path, value);
492 }
493 case SOCK_VECTOR: {
494 const float3 value = value_variant.get<float3>();
495 return set_rna_property_float3(C, tree.id, default_value_rna_path, value);
496 }
497 case SOCK_ROTATION: {
498 const math::Quaternion rotation = value_variant.get<math::Quaternion>();
499 const float3 euler = float3(math::to_euler(rotation));
500 return set_rna_property_float3(C, tree.id, default_value_rna_path, euler);
501 }
502 }
503 return false;
504}
505
506static bool set_value_node_value(bContext &C, bNode &node, const SocketValueVariant &value_variant)
507{
508 bNodeTree &tree = node.owner_tree();
509
510 switch (node.type_legacy) {
511 case SH_NODE_VALUE: {
512 const float value = value_variant.get<float>();
513 const std::string rna_path = fmt::format("nodes[\"{}\"].outputs[0].default_value",
514 BLI_str_escape(node.name));
515 return set_rna_property(C, tree.id, rna_path, value);
516 }
517 case FN_NODE_INPUT_INT: {
518 const int value = value_variant.get<int>();
519 const std::string rna_path = fmt::format("nodes[\"{}\"].integer", BLI_str_escape(node.name));
520 return set_rna_property(C, tree.id, rna_path, value);
521 }
522 case FN_NODE_INPUT_BOOL: {
523 const bool value = value_variant.get<bool>();
524 const std::string rna_path = fmt::format("nodes[\"{}\"].boolean", BLI_str_escape(node.name));
525 return set_rna_property(C, tree.id, rna_path, value);
526 }
528 const float3 value = value_variant.get<float3>();
529 const std::string rna_path = fmt::format("nodes[\"{}\"].vector", BLI_str_escape(node.name));
530 return set_rna_property_float3(C, tree.id, rna_path, value);
531 }
533 const math::Quaternion rotation = value_variant.get<math::Quaternion>();
534 const float3 euler = float3(math::to_euler(rotation));
535 const std::string rna_path = fmt::format("nodes[\"{}\"].rotation_euler",
536 BLI_str_escape(node.name));
537 return set_rna_property_float3(C, tree.id, rna_path, euler);
538 }
539 }
540 return false;
541}
542
544 Object &object,
546 const bNodeTreeInterfaceSocket &interface_socket,
547 const SocketValueVariant &value_variant)
548{
550
551 const std::string main_prop_rna_path = fmt::format(
552 "modifiers[\"{}\"][\"{}\"]", BLI_str_escape(nmd.modifier.name), interface_socket.identifier);
553
554 switch (interface_socket.socket_typeinfo()->type) {
555 case SOCK_FLOAT: {
556 const float value = value_variant.get<float>();
557 return set_rna_property(C, object.id, main_prop_rna_path, value);
558 }
559 case SOCK_INT: {
560 const int value = value_variant.get<int>();
561 return set_rna_property(C, object.id, main_prop_rna_path, value);
562 }
563 case SOCK_BOOLEAN: {
564 const bool value = value_variant.get<bool>();
565 return set_rna_property(C, object.id, main_prop_rna_path, value);
566 }
567 case SOCK_VECTOR: {
568 const float3 value = value_variant.get<float3>();
569 return set_rna_property_float3(C, object.id, main_prop_rna_path, value);
570 }
571 case SOCK_ROTATION: {
572 const math::Quaternion rotation = value_variant.get<math::Quaternion>();
573 const float3 euler = float3(math::to_euler(rotation));
574 return set_rna_property_float3(C, object.id, main_prop_rna_path, euler);
575 }
576 default:
577 return false;
578 }
579}
580
581std::optional<SocketValueVariant> get_logged_socket_value(geo_eval_log::GeoTreeLog &tree_log,
582 const bNodeSocket &socket)
583{
584 switch (socket.type) {
585 case SOCK_FLOAT: {
586 if (const std::optional<float> value = tree_log.find_primitive_socket_value<float>(socket)) {
587 return SocketValueVariant{*value};
588 }
589 break;
590 }
591 case SOCK_INT: {
592 if (const std::optional<int> value = tree_log.find_primitive_socket_value<int>(socket)) {
593 return SocketValueVariant{*value};
594 }
595 break;
596 }
597 case SOCK_BOOLEAN: {
598 if (const std::optional<bool> value = tree_log.find_primitive_socket_value<bool>(socket)) {
599 return SocketValueVariant{*value};
600 }
601 break;
602 }
603 case SOCK_VECTOR: {
604 if (const std::optional<float3> value = tree_log.find_primitive_socket_value<float3>(socket))
605 {
606 return SocketValueVariant{*value};
607 }
608 break;
609 }
610 case SOCK_ROTATION: {
611 if (const std::optional<math::Quaternion> value =
613 {
614 return SocketValueVariant{*value};
615 }
616 break;
617 }
618 case SOCK_MATRIX: {
619 if (const std::optional<float4x4> value = tree_log.find_primitive_socket_value<float4x4>(
620 socket))
621 {
622 return SocketValueVariant{*value};
623 }
624 break;
625 }
626 }
627 return std::nullopt;
628}
629
631 const NodeInContext &ctx_node,
634 Vector<const bNodeSocket *> &r_modified_inputs)
635{
636 const bNode &node = *ctx_node.node;
637 const ComputeContext *context = ctx_node.context;
638 const bke::bNodeType &ntype = *node.typeinfo;
639 if (!ntype.eval_inverse) {
640 /* Node does not support inverse evaluation. */
641 return;
642 }
643 if (!context) {
644 /* We need a context here to access the tree log. */
645 return;
646 }
647 geo_eval_log::GeoTreeLog &tree_log = eval_log.get_tree_log(context->hash());
648 tree_log.ensure_socket_values();
649
650 /* Build a temporary map of old socket values for the node evaluation. */
652 for (const bNodeSocket *socket : node.input_sockets()) {
653 if (!socket->is_available()) {
654 continue;
655 }
656 /* Retrieve input socket values from the log. */
657 if (const std::optional<SocketValueVariant> value = get_logged_socket_value(tree_log, *socket))
658 {
659 old_socket_values.add(socket, *value);
660 }
661 }
662 for (const bNodeSocket *socket : node.output_sockets()) {
663 if (!socket->is_available()) {
664 continue;
665 }
666 /* First check if there is an updated socket value for an output socket. */
667 if (const SocketValueVariant *value = value_by_socket.lookup_ptr({context, socket})) {
668 old_socket_values.add(socket, *value);
669 }
670 /* If not, retrieve the output socket value from the log. */
671 else if (const std::optional<SocketValueVariant> value = get_logged_socket_value(tree_log,
672 *socket))
673 {
674 old_socket_values.add(socket, *value);
675 }
676 }
677
679 InverseEvalParams params{node, old_socket_values, updated_socket_values};
680 ntype.eval_inverse(params);
681 /* Write back new socket values. */
682 for (auto &&item : updated_socket_values.items()) {
683 const bNodeSocket &socket = *item.key;
684 value_by_socket.add({context, &socket}, std::move(item.value));
685 r_modified_inputs.append(&socket);
686 }
687}
688
690 Object &object,
693 const Span<SocketToUpdate> sockets_to_update)
694{
695 nmd.node_group->ensure_topology_cache();
696
697 bke::ComputeContextCache compute_context_cache;
699
700 Vector<SocketInContext> initial_sockets;
701
702 /* Gather starting values for the backpropagation. */
703 for (const SocketToUpdate &socket_to_update : sockets_to_update) {
704 if (socket_to_update.multi_input_link) {
705 BLI_assert(socket_to_update.multi_input_link->tosock == socket_to_update.socket);
706 const std::optional<SocketValueVariant> converted_value = convert_single_socket_value(
707 *socket_to_update.socket,
708 *socket_to_update.multi_input_link->fromsock,
709 socket_to_update.new_value);
710 if (!converted_value) {
711 continue;
712 }
713 value_by_socket.add({socket_to_update.context, socket_to_update.multi_input_link->fromsock},
714 *converted_value);
715 }
716 else {
717 value_by_socket.add({socket_to_update.context, socket_to_update.socket},
718 socket_to_update.new_value);
719 }
720 }
721
722 if (value_by_socket.is_empty()) {
723 return false;
724 }
725
726 for (const SocketInContext &ctx_socket : value_by_socket.keys()) {
727 initial_sockets.append(ctx_socket);
728 }
729
730 /* Actually backpropagate the socket values as far as possible in the node tree. */
732 initial_sockets,
733 compute_context_cache,
734 /* Evaluate node. */
735 [&](const NodeInContext &ctx_node, Vector<const bNodeSocket *> &r_modified_inputs) {
737 ctx_node, eval_log, value_by_socket, r_modified_inputs);
738 },
739 /* Propagate value. */
740 [&](const SocketInContext &ctx_from, const SocketInContext &ctx_to) {
741 const SocketValueVariant *from_value = value_by_socket.lookup_ptr(ctx_from);
742 if (!from_value) {
743 return false;
744 }
745 const std::optional<SocketValueVariant> converted_value = convert_single_socket_value(
746 *ctx_from.socket, *ctx_to.socket, *from_value);
747 if (!converted_value) {
748 return false;
749 }
750 value_by_socket.add(ctx_to, std::move(*converted_value));
751 return true;
752 },
753 /* Get input sockets to propagate. */
754 [&](const NodeInContext &ctx_node, Vector<const bNodeSocket *> &r_sockets) {
755 for (const bNodeSocket *socket : ctx_node.node->input_sockets()) {
756 if (value_by_socket.contains({ctx_node.context, socket})) {
757 r_sockets.append(socket);
758 }
759 }
760 });
761
762 bool any_success = false;
763 /* Set new values for sockets. */
764 for (const SocketInContext &ctx_socket : upstream_eval_targets.sockets) {
765 if (const SocketValueVariant *value = value_by_socket.lookup_ptr(ctx_socket)) {
766 bNodeSocket &socket_mutable = const_cast<bNodeSocket &>(*ctx_socket.socket);
767 any_success |= set_socket_value(C, socket_mutable, *value);
768 }
769 }
770 /* Set new values for value nodes. */
771 for (const NodeInContext &ctx_node : upstream_eval_targets.value_nodes) {
772 if (const SocketValueVariant *value = value_by_socket.lookup_ptr(
773 {ctx_node.context, &ctx_node.node->output_socket(0)}))
774 {
775 bNode &node_mutable = const_cast<bNode &>(*ctx_node.node);
776 any_success |= set_value_node_value(C, node_mutable, *value);
777 }
778 }
779 /* Set new values for modifier inputs. */
780 const bke::ModifierComputeContext modifier_context{nullptr, nmd};
781 for (const bNode *group_input_node : nmd.node_group->group_input_nodes()) {
782 for (const bNodeSocket *socket : group_input_node->output_sockets().drop_back(1)) {
783 if (const SocketValueVariant *value = value_by_socket.lookup_ptr(
784 {&modifier_context, socket}))
785 {
786 any_success |= set_modifier_value(
787 C, object, nmd, *nmd.node_group->interface_inputs()[socket->index()], *value);
788 }
789 }
790 }
791
792 return any_success;
793}
794
796 const bNode &node,
799 : socket_values_(socket_values), updated_socket_values_(updated_socket_values), node(node)
800{
801}
802
803} // namespace blender::nodes::inverse_eval
Functions to insert, delete or modify keyframes.
Scene * CTX_data_scene(const bContext *C)
#define FN_NODE_INPUT_VECTOR
#define SH_NODE_VALUE
#define FN_NODE_INPUT_INT
#define FN_NODE_INPUT_BOOL
#define FN_NODE_INPUT_ROTATION
#define BLI_assert(a)
Definition BLI_assert.h:46
size_t BLI_str_escape(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
void DEG_id_tag_update(ID *id, unsigned int flags)
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1074
#define ID_IS_EDITABLE(_id)
Definition DNA_ID.h:705
eNodeSocketDatatype
@ SOCK_INT
@ SOCK_VECTOR
@ SOCK_BOOLEAN
@ SOCK_MATRIX
@ SOCK_FLOAT
@ SOCK_ROTATION
@ AUTOKEY_FLAG_INSERTAVAILABLE
PropertyType
Definition RNA_types.hh:161
@ PROP_FLOAT
Definition RNA_types.hh:164
@ PROP_BOOLEAN
Definition RNA_types.hh:162
@ PROP_INT
Definition RNA_types.hh:163
#define C
Definition RandGen.cpp:29
ATTR_WARN_UNUSED_RESULT const BMVert * v
const Value * lookup_ptr(const Key &key) const
Definition BLI_map.hh:508
bool add(const Key &key, const Value &value)
Definition BLI_map.hh:295
const Value & lookup(const Key &key) const
Definition BLI_map.hh:545
KeyIterator keys() const &
Definition BLI_map.hh:875
bool is_empty() const
Definition BLI_map.hh:986
bool contains(const Key &key) const
Definition BLI_map.hh:353
ItemIterator items() const &
Definition BLI_map.hh:902
Value & lookup_or_add(const Key &key, const Value &value)
Definition BLI_map.hh:588
bool add(const Key &key)
Definition BLI_set.hh:248
constexpr const char * c_str() const
void append(const T &value)
void extend(Span< T > array)
void convert_to_uninitialized(const CPPType &from_type, const CPPType &to_type, const void *from_value, void *to_value) const
bool is_convertible(const CPPType &from_type, const CPPType &to_type) const
void * allocate_single(eNodeSocketDatatype socket_type)
GeoTreeLog & get_tree_log(const ComputeContextHash &compute_context_hash)
std::optional< T > find_primitive_socket_value(const bNodeSocket &query_socket)
InverseEvalParams(const bNode &node, const Map< const bNodeSocket *, bke::SocketValueVariant > &socket_values, Map< const bNodeSocket *, bke::SocketValueVariant > &updated_socket_values)
nullptr float
KDTree_3d * tree
VecBase< float, D > step(VecOp< float, D >, VecOp< float, D >) RET
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
bool autokeyframe_property(bContext *C, Scene *scene, PointerRNA *ptr, PropertyRNA *prop, int rnaindex, float cfra, bool only_if_property_keyed)
bool is_keying_flag(const Scene *scene, eKeying_Flag flag)
const DataTypeConversions & get_implicit_type_conversions()
QuaternionBase< float > Quaternion
Euler3Base< T > to_euler(const AxisAngleBase< T, AngleT > &axis_angle, EulerOrder order)
static void evaluate_node_elem_upstream(const NodeInContext &ctx_node, Vector< const bNodeSocket * > &r_modified_inputs, Map< SocketInContext, ElemVariant > &elem_by_socket)
LocalInverseEvalTargets find_local_inverse_eval_targets(const bNodeTree &tree, const SocketElem &initial_socket_elem)
static void backpropagate_socket_values_through_node(const NodeInContext &ctx_node, geo_eval_log::GeoNodesLog &eval_log, Map< SocketInContext, SocketValueVariant > &value_by_socket, Vector< const bNodeSocket * > &r_modified_inputs)
void foreach_element_on_inverse_eval_path(const ComputeContext &initial_context, const SocketElem &initial_socket_elem, FunctionRef< void(const ComputeContext &context)> foreach_context_fn, FunctionRef< void(const ComputeContext &context, const bNodeSocket &socket, const ElemVariant &elem)> foreach_socket_fn)
static bool set_socket_value(bContext &C, bNodeSocket &socket, const SocketValueVariant &value_variant)
static bool set_modifier_value(bContext &C, Object &object, NodesModifierData &nmd, const bNodeTreeInterfaceSocket &interface_socket, const SocketValueVariant &value_variant)
static bool propagate_value_elem_filtered(const SocketInContext &ctx_from, const SocketInContext &ctx_to, const Map< SocketInContext, ElemVariant > &elem_by_socket_filter, Map< SocketInContext, ElemVariant > &elem_by_socket)
std::optional< SocketValueVariant > get_logged_socket_value(geo_eval_log::GeoTreeLog &tree_log, const bNodeSocket &socket)
static void get_input_elems_to_propagate(const NodeInContext &ctx_node, Vector< const bNodeSocket * > &r_sockets, Map< SocketInContext, ElemVariant > &elem_by_socket)
static bool set_rna_property_float3(bContext &C, ID &id, const StringRefNull rna_path, const float3 &value)
static void evaluate_node_elem_downstream_filtered(const NodeInContext &ctx_node, const Map< SocketInContext, ElemVariant > &elem_by_socket_filter, Map< SocketInContext, ElemVariant > &elem_by_socket, Vector< const bNodeSocket * > &r_outputs_to_propagate)
bool backpropagate_socket_values(bContext &C, Object &object, NodesModifierData &nmd, geo_eval_log::GeoNodesLog &eval_log, const Span< SocketToUpdate > sockets_to_update)
std::optional< SocketValueVariant > convert_single_socket_value(const bNodeSocket &old_socket, const bNodeSocket &new_socket, const SocketValueVariant &old_value)
static bool set_value_node_value(bContext &C, bNode &node, const SocketValueVariant &value_variant)
static bool set_rna_property(bContext &C, ID &id, const StringRefNull rna_path, const RNAValueVariant &value_variant)
std::variant< float, int, bool > RNAValueVariant
static bool propagate_socket_elem(const SocketInContext &ctx_from, const SocketInContext &ctx_to, Map< SocketInContext, ElemVariant > &elem_by_socket)
UpstreamEvalTargets eval_upstream(const Span< SocketInContext > initial_sockets, bke::ComputeContextCache &compute_context_cache, FunctionRef< void(const NodeInContext &ctx_node, Vector< const bNodeSocket * > &r_modified_inputs)> evaluate_node_fn, FunctionRef< bool(const SocketInContext &ctx_from, const SocketInContext &ctx_to)> propagate_value_fn, FunctionRef< void(const NodeInContext &ctx_node, Vector< const bNodeSocket * > &r_sockets)> get_inputs_to_propagate_fn)
void eval_downstream(const Span< SocketInContext > initial_sockets, bke::ComputeContextCache &compute_context_cache, FunctionRef< void(const NodeInContext &ctx_node, Vector< const bNodeSocket * > &r_outputs_to_propagate)> evaluate_node_fn, FunctionRef< bool(const SocketInContext &ctx_from, const SocketInContext &ctx_to)> propagate_value_fn)
std::optional< ElemVariant > get_elem_variant_for_socket_type(const eNodeSocketDatatype type)
Definition value_elem.cc:9
std::optional< ElemVariant > convert_socket_elem(const bNodeSocket &old_socket, const bNodeSocket &new_socket, const ElemVariant &old_elem)
Definition value_elem.cc:29
MatBase< float, 4, 4 > float4x4
VecBase< float, 3 > float3
void RNA_property_boolean_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, bool value)
void RNA_property_int_set(PointerRNA *ptr, PropertyRNA *prop, int value)
void RNA_property_int_ui_range(PointerRNA *ptr, PropertyRNA *prop, int *softmin, int *softmax, int *step)
void RNA_property_float_ui_range(PointerRNA *ptr, PropertyRNA *prop, float *softmin, float *softmax, float *step, float *precision)
void RNA_property_float_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, float value)
PropertyType RNA_property_type(PropertyRNA *prop)
void RNA_property_update(bContext *C, PointerRNA *ptr, PropertyRNA *prop)
void RNA_property_int_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, int value)
void RNA_property_boolean_set(PointerRNA *ptr, PropertyRNA *prop, bool value)
int RNA_property_array_length(PointerRNA *ptr, PropertyRNA *prop)
void RNA_property_float_set(PointerRNA *ptr, PropertyRNA *prop, float value)
PointerRNA RNA_id_pointer_create(ID *id)
bool RNA_path_resolve_property_full(const PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index)
Definition rna_path.cc:572
Definition DNA_ID.h:414
struct bNodeTree * node_group
struct RenderData r
bNodeSocketTypeHandle * typeinfo
bNodeTypeHandle * typeinfo
char name[64]
int16_t type_legacy
Defines a node type.
Definition BKE_node.hh:238
NodeInverseElemEvalFunction eval_inverse_elem
Definition BKE_node.hh:403
NodeInverseEvalFunction eval_inverse
Definition BKE_node.hh:410
NodeElemEvalFunction eval_elem
Definition BKE_node.hh:397
void intersect(const ElemVariant &other)
i
Definition text_draw.cc:230