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