Blender V4.5
node_geo_simulation.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include "BLI_string.h"
6#include "BLI_string_utf8.h"
7
11#include "BKE_context.hh"
12#include "BKE_curves.hh"
13#include "BKE_instances.hh"
14#include "BKE_modifier.hh"
16#include "BKE_screen.hh"
17
19
20#include "UI_interface.hh"
21
22#include "NOD_common.hh"
23#include "NOD_geo_bake.hh"
24#include "NOD_geo_simulation.hh"
26#include "NOD_socket.hh"
31
32#include "DNA_mesh_types.h"
34
35#include "ED_node.hh"
36
37#include "RNA_access.hh"
38#include "RNA_prototypes.hh"
39
40#include "BLT_translation.hh"
41
42#include "GEO_mix_geometries.hh"
43
44#include "WM_api.hh"
45
46#include "BLO_read_write.hh"
47
48#include "node_geometry_util.hh"
49
51
53{
54 const bke::bNodeSocketType *typeinfo = bke::node_socket_type_find_static(socket_type);
55 BLI_assert(typeinfo);
57 return *typeinfo->geometry_nodes_cpp_type;
58}
59
64
66 const Span<NodeSimulationItem> node_simulation_items)
67{
69 const int items_num = node_simulation_items.size();
70 config.domains.resize(items_num);
71 config.names.resize(items_num);
72 config.types.resize(items_num);
73 config.geometries_by_attribute.resize(items_num);
74
75 int last_geometry_index = -1;
76 for (const int item_i : node_simulation_items.index_range()) {
77 const NodeSimulationItem &item = node_simulation_items[item_i];
78 config.types[item_i] = eNodeSocketDatatype(item.socket_type);
79 config.names[item_i] = item.name;
80 config.domains[item_i] = AttrDomain(item.attribute_domain);
81 if (item.socket_type == SOCK_GEOMETRY) {
82 last_geometry_index = item_i;
83 }
84 else if (last_geometry_index != -1) {
85 config.geometries_by_attribute[item_i].append(last_geometry_index);
86 }
87 }
88 return config;
89}
90
91static std::shared_ptr<AttributeFieldInput> make_attribute_field(
92 const Object &self_object,
93 const ComputeContext &compute_context,
94 const bNode &node,
95 const NodeSimulationItem &item,
96 const CPPType &type)
97{
98 std::string attribute_name = bke::hash_to_anonymous_attribute_name(
99 self_object.id.name, compute_context.hash(), node.identifier, item.identifier);
100 std::string socket_inspection_name = make_anonymous_attribute_socket_inspection_string(
101 node.label_or_name(), item.name);
102 return std::make_shared<AttributeFieldInput>(
103 std::move(attribute_name), type, std::move(socket_inspection_name));
104}
105
106static void move_simulation_state_to_values(const Span<NodeSimulationItem> node_simulation_items,
107 bke::bake::BakeState zone_state,
108 const Object &self_object,
109 const ComputeContext &compute_context,
110 const bNode &node,
111 bke::bake::BakeDataBlockMap *data_block_map,
112 Span<void *> r_output_values)
113{
114 const bke::bake::BakeSocketConfig config = make_bake_socket_config(node_simulation_items);
116 for (const NodeSimulationItem &item : node_simulation_items) {
117 std::unique_ptr<bke::bake::BakeItem> *bake_item = zone_state.items_by_id.lookup_ptr(
118 item.identifier);
119 bake_items.append(bake_item ? bake_item->get() : nullptr);
120 }
121
123 bake_items,
124 config,
125 data_block_map,
126 [&](const int i, const CPPType &type) {
128 self_object, compute_context, node, node_simulation_items[i], type);
129 },
130 r_output_values);
131}
132
133static void copy_simulation_state_to_values(const Span<NodeSimulationItem> node_simulation_items,
134 const bke::bake::BakeStateRef &zone_state,
135 const Object &self_object,
136 const ComputeContext &compute_context,
137 const bNode &node,
138 bke::bake::BakeDataBlockMap *data_block_map,
139 Span<void *> r_output_values)
140{
141 const bke::bake::BakeSocketConfig config = make_bake_socket_config(node_simulation_items);
143 for (const NodeSimulationItem &item : node_simulation_items) {
144 const bke::bake::BakeItem *const *bake_item = zone_state.items_by_id.lookup_ptr(
145 item.identifier);
146 bake_items.append(bake_item ? *bake_item : nullptr);
147 }
148
150 bake_items,
151 config,
152 data_block_map,
153 [&](const int i, const CPPType &type) {
155 self_object, compute_context, node, node_simulation_items[i], type);
156 },
157 r_output_values);
158}
159
161 const Span<NodeSimulationItem> node_simulation_items,
162 const Span<void *> input_values,
163 bke::bake::BakeDataBlockMap *data_block_map)
164{
165 const bke::bake::BakeSocketConfig config = make_bake_socket_config(node_simulation_items);
166
168 bke::bake::move_socket_values_to_bake_items(input_values, config, data_block_map);
169
170 bke::bake::BakeState bake_state;
171 for (const int i : node_simulation_items.index_range()) {
172 const NodeSimulationItem &item = node_simulation_items[i];
173 std::unique_ptr<bke::bake::BakeItem> &bake_item = bake_items[i];
174 if (bake_item) {
175 bake_state.items_by_id.add_new(item.identifier, std::move(bake_item));
176 }
177 }
178 return bake_state;
179}
180
182 uiLayout *layout,
183 bNodeTree &ntree,
184 bNode &output_node)
185{
186 if (uiLayout *panel = layout->panel(
187 C, "simulation_state_items", false, IFACE_("Simulation State")))
188 {
190 C, panel, ntree, output_node);
191 auto &storage = *static_cast<NodeGeometrySimulationOutput *>(output_node.storage);
193 ntree, output_node, [&](PointerRNA *item_ptr) {
194 NodeSimulationItem &active_item = storage.items[storage.active_index];
195 uiLayoutSetPropSep(panel, true);
196 uiLayoutSetPropDecorate(panel, false);
197 panel->prop(item_ptr, "socket_type", UI_ITEM_NONE, std::nullopt, ICON_NONE);
199 panel->prop(item_ptr, "attribute_domain", UI_ITEM_NONE, std::nullopt, ICON_NONE);
200 }
201 });
202 }
203}
204
206static void node_layout_ex(uiLayout *layout, bContext *C, PointerRNA *current_node_ptr)
207{
208 bNodeTree &ntree = *reinterpret_cast<bNodeTree *>(current_node_ptr->owner_id);
209 bNode *current_node = static_cast<bNode *>(current_node_ptr->data);
210
211 const bke::bNodeTreeZones *zones = ntree.zones();
212 if (!zones) {
213 return;
214 }
215 const bke::bNodeTreeZone *zone = zones->get_zone_by_node(current_node->identifier);
216 if (!zone) {
217 return;
218 }
219 if (!zone->output_node_id) {
220 return;
221 }
222 bNode &output_node = const_cast<bNode &>(*zone->output_node());
223
224 BakeDrawContext ctx;
225 if (!get_bake_draw_context(C, output_node, ctx)) {
226 return;
227 }
229
230 draw_simulation_state(C, layout, ntree, output_node);
231
232 uiLayoutSetPropSep(layout, true);
233 uiLayoutSetPropDecorate(layout, false);
234
236
237 {
238 uiLayout *col = &layout->column(false);
239 draw_bake_button_row(ctx, col, true);
240 if (const std::optional<std::string> bake_state_str = get_bake_state_string(ctx)) {
241 uiLayout *row = &col->row(true);
242 row->label(*bake_state_str, ICON_NONE);
243 }
244 }
245 draw_common_bake_settings(C, ctx, layout);
246 draw_data_blocks(C, layout, ctx.bake_rna);
247}
248
249namespace sim_input_node {
250
252
254 const bNode &node_;
255 int32_t output_node_id_;
256 Span<NodeSimulationItem> simulation_items_;
257
258 public:
260 const bNode &node,
261 GeometryNodesLazyFunctionGraphInfo &own_lf_graph_info)
262 : node_(node)
263 {
264 debug_name_ = "Simulation Input";
265 output_node_id_ = node_storage(node).output_node_id;
266 const bNode &output_node = *node_tree.node_by_id(output_node_id_);
267 const NodeGeometrySimulationOutput &storage = *static_cast<NodeGeometrySimulationOutput *>(
268 output_node.storage);
269 simulation_items_ = {storage.items, storage.items_num};
270
271 MutableSpan<int> lf_index_by_bsocket = own_lf_graph_info.mapping.lf_index_by_bsocket;
272 lf_index_by_bsocket[node.output_socket(0).index_in_tree()] = outputs_.append_and_get_index_as(
273 "Delta Time", CPPType::get<SocketValueVariant>());
274
275 for (const int i : simulation_items_.index_range()) {
276 const NodeSimulationItem &item = simulation_items_[i];
277 const bNodeSocket &input_bsocket = node.input_socket(i);
278 const bNodeSocket &output_bsocket = node.output_socket(i + 1);
279
280 const CPPType &type = get_simulation_item_cpp_type(item);
281
282 lf_index_by_bsocket[input_bsocket.index_in_tree()] = inputs_.append_and_get_index_as(
283 item.name, type, lf::ValueUsage::Maybe);
284 lf_index_by_bsocket[output_bsocket.index_in_tree()] = outputs_.append_and_get_index_as(
285 item.name, type);
286 }
287 }
288
289 void execute_impl(lf::Params &params, const lf::Context &context) const final
290 {
291 const GeoNodesUserData &user_data = *static_cast<const GeoNodesUserData *>(context.user_data);
292 if (!user_data.call_data->simulation_params) {
294 return;
295 }
296 if (!user_data.call_data->self_object()) {
297 /* Self object is currently required for creating anonymous attribute names. */
299 return;
300 }
301 std::optional<FoundNestedNodeID> found_id = find_nested_node_id(user_data, output_node_id_);
302 if (!found_id) {
304 return;
305 }
306 if (found_id->is_in_loop || found_id->is_in_closure) {
308 return;
309 }
310 SimulationZoneBehavior *zone_behavior = user_data.call_data->simulation_params->get(
311 found_id->id);
312 if (!zone_behavior) {
314 return;
315 }
316 sim_input::Behavior &input_behavior = zone_behavior->input;
317 float delta_time = 0.0f;
318 if (auto *info = std::get_if<sim_input::OutputCopy>(&input_behavior)) {
319 delta_time = info->delta_time;
321 params, user_data, zone_behavior->data_block_map, info->state);
322 }
323 else if (auto *info = std::get_if<sim_input::OutputMove>(&input_behavior)) {
324 delta_time = info->delta_time;
326 params, user_data, zone_behavior->data_block_map, std::move(info->state));
327 }
328 else if (std::get_if<sim_input::PassThrough>(&input_behavior)) {
329 delta_time = 0.0f;
330 this->pass_through(params, user_data, zone_behavior->data_block_map);
331 }
332 else {
334 }
335 if (!params.output_was_set(0)) {
336 params.set_output(0, SocketValueVariant(delta_time));
337 }
338 }
339
344
346 const GeoNodesUserData &user_data,
347 bke::bake::BakeDataBlockMap *data_block_map,
348 const bke::bake::BakeStateRef &zone_state) const
349 {
350 Array<void *> outputs(simulation_items_.size());
351 for (const int i : simulation_items_.index_range()) {
352 outputs[i] = params.get_output_data_ptr(i + 1);
353 }
354 copy_simulation_state_to_values(simulation_items_,
355 zone_state,
356 *user_data.call_data->self_object(),
357 *user_data.compute_context,
358 node_,
359 data_block_map,
360 outputs);
361 for (const int i : simulation_items_.index_range()) {
362 params.output_set(i + 1);
363 }
364 }
365
367 const GeoNodesUserData &user_data,
368 bke::bake::BakeDataBlockMap *data_block_map,
369 bke::bake::BakeState zone_state) const
370 {
371 Array<void *> outputs(simulation_items_.size());
372 for (const int i : simulation_items_.index_range()) {
373 outputs[i] = params.get_output_data_ptr(i + 1);
374 }
375 move_simulation_state_to_values(simulation_items_,
376 std::move(zone_state),
377 *user_data.call_data->self_object(),
378 *user_data.compute_context,
379 node_,
380 data_block_map,
381 outputs);
382 for (const int i : simulation_items_.index_range()) {
383 params.output_set(i + 1);
384 }
385 }
386
388 const GeoNodesUserData &user_data,
389 bke::bake::BakeDataBlockMap *data_block_map) const
390 {
391 Array<void *> input_values(inputs_.size());
392 for (const int i : inputs_.index_range()) {
393 input_values[i] = params.try_get_input_data_ptr_or_request(i);
394 }
395 if (input_values.as_span().contains(nullptr)) {
396 /* Wait for inputs to be computed. */
397 return;
398 }
399 /* Instead of outputting the initial values directly, convert them to a simulation state and
400 * then back. This ensures that some geometry processing happens on the data consistently (e.g.
401 * removing anonymous attributes). */
403 simulation_items_, input_values, data_block_map);
404 this->output_simulation_state_move(params, user_data, data_block_map, std::move(bake_state));
405 }
406};
407
409{
410 b.use_custom_socket_order();
411 b.allow_any_socket_order();
412 b.add_output<decl::Float>("Delta Time");
413
414 const bNode *node = b.node_or_null();
415 const bNodeTree *node_tree = b.tree_or_null();
416 if (ELEM(nullptr, node, node_tree)) {
417 return;
418 }
419
420 const bNode *output_node = node_tree->node_by_id(node_storage(*node).output_node_id);
421 if (!output_node) {
422 return;
423 }
424 const auto &output_storage = *static_cast<const NodeGeometrySimulationOutput *>(
425 output_node->storage);
426
427 for (const int i : IndexRange(output_storage.items_num)) {
428 const NodeSimulationItem &item = output_storage.items[i];
429 const eNodeSocketDatatype socket_type = eNodeSocketDatatype(item.socket_type);
430 if (socket_type == SOCK_GEOMETRY && i > 0) {
431 b.add_separator();
432 }
433 const StringRef name = item.name;
434 const std::string identifier = SimulationItemsAccessor::socket_identifier_for_item(item);
435 auto &input_decl = b.add_input(socket_type, name, identifier)
436 .socket_name_ptr(
437 &node_tree->id, SimulationItemsAccessor::item_srna, &item, "name");
438 auto &output_decl = b.add_output(socket_type, name, identifier).align_with_previous();
439 if (socket_type_supports_fields(socket_type)) {
440 /* If it's below a geometry input it may be a field evaluated on that geometry. */
441 input_decl.supports_field().structure_type(StructureType::Dynamic);
442 output_decl.dependent_field({input_decl.index()});
443 }
444 }
445 b.add_input<decl::Extend>("", "__extend__").structure_type(StructureType::Dynamic);
446 b.add_output<decl::Extend>("", "__extend__")
447 .structure_type(StructureType::Dynamic)
448 .align_with_previous();
449}
450
451static void node_init(bNodeTree * /*tree*/, bNode *node)
452{
454 /* Needs to be initialized for the node to work. */
455 data->output_node_id = 0;
456 node->storage = data;
457}
458
459static void node_label(const bNodeTree * /*ntree*/,
460 const bNode * /*node*/,
461 char *label,
462 const int label_maxncpy)
463{
464 BLI_strncpy_utf8(label, IFACE_("Simulation"), label_maxncpy);
465}
466
467static bool node_insert_link(bNodeTree *ntree, bNode *node, bNodeLink *link)
468{
469 bNode *output_node = ntree->node_by_id(node_storage(*node).output_node_id);
470 if (!output_node) {
471 return true;
472 }
474 *ntree, *node, *output_node, *link);
475}
476
477static void node_register()
478{
479 static blender::bke::bNodeType ntype;
480 geo_node_type_base(&ntype, "GeometryNodeSimulationInput", GEO_NODE_SIMULATION_INPUT);
481 ntype.ui_name = "Simulation Input";
482 ntype.ui_description = "Input data for the simulation zone";
483 ntype.enum_name_legacy = "SIMULATION_INPUT";
485 ntype.initfunc = node_init;
486 ntype.declare = node_declare;
487 ntype.labelfunc = node_label;
489 ntype.gather_link_search_ops = nullptr;
490 ntype.no_muting = true;
493 "NodeGeometrySimulationInput",
497}
499
500} // namespace sim_input_node
501
503
505
507 const bNode &node_;
508 Span<NodeSimulationItem> simulation_items_;
509 int skip_input_index_;
515 int skip_inputs_offset_;
520 int solve_inputs_offset_;
521
522 public:
524 GeometryNodesLazyFunctionGraphInfo &own_lf_graph_info)
525 : node_(node)
526 {
527 debug_name_ = "Simulation Output";
528 const NodeGeometrySimulationOutput &storage = node_storage(node);
529 simulation_items_ = {storage.items, storage.items_num};
530
531 MutableSpan<int> lf_index_by_bsocket = own_lf_graph_info.mapping.lf_index_by_bsocket;
532
533 const bNodeSocket &skip_bsocket = node.input_socket(0);
534 skip_input_index_ = inputs_.append_and_get_index_as(
535 "Skip", *skip_bsocket.typeinfo->geometry_nodes_cpp_type, lf::ValueUsage::Maybe);
536 lf_index_by_bsocket[skip_bsocket.index_in_tree()] = skip_input_index_;
537
538 skip_inputs_offset_ = inputs_.size();
539
540 /* Add the skip inputs that are linked to the simulation input node. */
541 for (const int i : simulation_items_.index_range()) {
542 const NodeSimulationItem &item = simulation_items_[i];
543 const CPPType &type = get_simulation_item_cpp_type(item);
544 inputs_.append_as(item.name, type, lf::ValueUsage::Maybe);
545 }
546
547 solve_inputs_offset_ = inputs_.size();
548
549 /* Add the solve inputs that correspond to the simulation state inputs in the UI. */
550 for (const int i : simulation_items_.index_range()) {
551 const NodeSimulationItem &item = simulation_items_[i];
552 const bNodeSocket &input_bsocket = node.input_socket(i + 1);
553 const bNodeSocket &output_bsocket = node.output_socket(i);
554
555 const CPPType &type = get_simulation_item_cpp_type(item);
556
557 lf_index_by_bsocket[input_bsocket.index_in_tree()] = inputs_.append_and_get_index_as(
558 item.name, type, lf::ValueUsage::Maybe);
559 lf_index_by_bsocket[output_bsocket.index_in_tree()] = outputs_.append_and_get_index_as(
560 item.name, type);
561 }
562 }
563
564 void execute_impl(lf::Params &params, const lf::Context &context) const final
565 {
566 GeoNodesUserData &user_data = *static_cast<GeoNodesUserData *>(context.user_data);
567 GeoNodesLocalUserData &local_user_data = *static_cast<GeoNodesLocalUserData *>(
568 context.local_user_data);
569 if (!user_data.call_data->self_object()) {
570 /* The self object is currently required for generating anonymous attribute names. */
572 return;
573 }
574 if (!user_data.call_data->simulation_params) {
575 if (geo_eval_log::GeoTreeLogger *tree_logger = local_user_data.try_get_tree_logger(
576 user_data))
577 {
578 tree_logger->node_warnings.append(
579 *tree_logger->allocator,
580 {node_.identifier,
581 {NodeWarningType::Error, TIP_("Simulation zone is not supported")}});
582 }
584 return;
585 }
586 std::optional<FoundNestedNodeID> found_id = find_nested_node_id(user_data, node_.identifier);
587 if (!found_id) {
589 return;
590 }
591 if (found_id->is_in_loop || found_id->is_in_closure) {
592 if (geo_eval_log::GeoTreeLogger *tree_logger = local_user_data.try_get_tree_logger(
593 user_data))
594 {
595 const StringRefNull message = U.experimental.use_bundle_and_closure_nodes ?
596 TIP_("Simulation must not be in a loop or closure") :
597 TIP_("Simulation must not be in a loop");
598 tree_logger->node_warnings.append(*tree_logger->allocator,
599 {node_.identifier, {NodeWarningType::Error, message}});
600 }
602 return;
603 }
604 SimulationZoneBehavior *zone_behavior = user_data.call_data->simulation_params->get(
605 found_id->id);
606 if (!zone_behavior) {
607 this->set_default_outputs(params);
608 return;
609 }
610 sim_output::Behavior &output_behavior = zone_behavior->output;
611 if (auto *info = std::get_if<sim_output::ReadSingle>(&output_behavior)) {
612 this->output_cached_state(params, user_data, zone_behavior->data_block_map, info->state);
613 }
614 else if (auto *info = std::get_if<sim_output::ReadInterpolated>(&output_behavior)) {
615 this->output_mixed_cached_state(params,
616 zone_behavior->data_block_map,
617 *user_data.call_data->self_object(),
618 *user_data.compute_context,
619 info->prev_state,
620 info->next_state,
621 info->mix_factor);
622 }
623 else if (std::get_if<sim_output::PassThrough>(&output_behavior)) {
624 this->pass_through(params, user_data, zone_behavior->data_block_map);
625 }
626 else if (auto *info = std::get_if<sim_output::StoreNewState>(&output_behavior)) {
627 this->store_new_state(params, user_data, zone_behavior->data_block_map, *info);
628 }
629 else {
631 }
632 }
633
638
640 GeoNodesUserData &user_data,
641 bke::bake::BakeDataBlockMap *data_block_map,
642 const bke::bake::BakeStateRef &state) const
643 {
644 Array<void *> output_values(simulation_items_.size());
645 for (const int i : simulation_items_.index_range()) {
646 output_values[i] = params.get_output_data_ptr(i);
647 }
648 copy_simulation_state_to_values(simulation_items_,
649 state,
650 *user_data.call_data->self_object(),
651 *user_data.compute_context,
652 node_,
653 data_block_map,
654 output_values);
655 for (const int i : simulation_items_.index_range()) {
656 params.output_set(i);
657 }
658 }
659
661 bke::bake::BakeDataBlockMap *data_block_map,
662 const Object &self_object,
663 const ComputeContext &compute_context,
664 const bke::bake::BakeStateRef &prev_state,
666 const float mix_factor) const
667 {
668 Array<void *> output_values(simulation_items_.size());
669 for (const int i : simulation_items_.index_range()) {
670 output_values[i] = params.get_output_data_ptr(i);
671 }
672 copy_simulation_state_to_values(simulation_items_,
673 prev_state,
674 self_object,
675 compute_context,
676 node_,
677 data_block_map,
678 output_values);
679
680 Array<void *> next_values(simulation_items_.size());
681 LinearAllocator<> allocator;
682 for (const int i : simulation_items_.index_range()) {
683 const CPPType &type = *outputs_[i].type;
684 next_values[i] = allocator.allocate(type);
685 }
686 copy_simulation_state_to_values(simulation_items_,
688 self_object,
689 compute_context,
690 node_,
691 data_block_map,
692 next_values);
693
694 for (const int i : simulation_items_.index_range()) {
695 mix_baked_data_item(eNodeSocketDatatype(simulation_items_[i].socket_type),
696 output_values[i],
697 next_values[i],
698 mix_factor);
699 }
700
701 for (const int i : simulation_items_.index_range()) {
702 const CPPType &type = *outputs_[i].type;
703 type.destruct(next_values[i]);
704 }
705
706 for (const int i : simulation_items_.index_range()) {
707 params.output_set(i);
708 }
709 }
710
712 GeoNodesUserData &user_data,
713 bke::bake::BakeDataBlockMap *data_block_map) const
714 {
715 std::optional<bke::bake::BakeState> bake_state = this->get_bake_state_from_inputs(
716 params, data_block_map, true);
717 if (!bake_state) {
718 /* Wait for inputs to be computed. */
719 return;
720 }
721
722 Array<void *> output_values(simulation_items_.size());
723 for (const int i : simulation_items_.index_range()) {
724 output_values[i] = params.get_output_data_ptr(i);
725 }
726 move_simulation_state_to_values(simulation_items_,
727 std::move(*bake_state),
728 *user_data.call_data->self_object(),
729 *user_data.compute_context,
730 node_,
731 data_block_map,
732 output_values);
733 for (const int i : simulation_items_.index_range()) {
734 params.output_set(i);
735 }
736 }
737
739 GeoNodesUserData &user_data,
740 bke::bake::BakeDataBlockMap *data_block_map,
741 const sim_output::StoreNewState &info) const
742 {
743 const SocketValueVariant *skip_variant =
744 params.try_get_input_data_ptr_or_request<SocketValueVariant>(skip_input_index_);
745 if (skip_variant == nullptr) {
746 /* Wait for skip input to be computed. */
747 return;
748 }
749 const bool skip = skip_variant->get<bool>();
750
751 /* Instead of outputting the values directly, convert them to a bake state and then back.
752 * This ensures that some geometry processing happens on the data consistently (e.g. removing
753 * anonymous attributes). */
754 std::optional<bke::bake::BakeState> bake_state = this->get_bake_state_from_inputs(
755 params, data_block_map, skip);
756 if (!bake_state) {
757 /* Wait for inputs to be computed. */
758 return;
759 }
760 this->output_cached_state(params, user_data, data_block_map, *bake_state);
761 info.store_fn(std::move(*bake_state));
762 }
763
764 std::optional<bke::bake::BakeState> get_bake_state_from_inputs(
765 lf::Params &params, bke::bake::BakeDataBlockMap *data_block_map, const bool skip) const
766 {
767 /* Choose which set of input parameters to use. The others are ignored. */
768 const int params_offset = skip ? skip_inputs_offset_ : solve_inputs_offset_;
769 Array<void *> input_values(simulation_items_.size());
770 for (const int i : simulation_items_.index_range()) {
771 input_values[i] = params.try_get_input_data_ptr_or_request(i + params_offset);
772 }
773 if (input_values.as_span().contains(nullptr)) {
774 /* Wait for inputs to be computed. */
775 return std::nullopt;
776 }
777
778 return move_values_to_simulation_state(simulation_items_, input_values, data_block_map);
779 }
780};
781
783{
784 b.use_custom_socket_order();
785 b.allow_any_socket_order();
786 b.add_input<decl::Bool>("Skip").hide_value().description(
787 "Forward the output of the simulation input node directly to the output node and ignore "
788 "the nodes in the simulation zone");
789
790 const bNodeTree *tree = b.tree_or_null();
791 const bNode *node = b.node_or_null();
792 if (node == nullptr) {
793 return;
794 }
795
796 const NodeGeometrySimulationOutput &storage = node_storage(*node);
797
798 for (const int i : IndexRange(storage.items_num)) {
799 const NodeSimulationItem &item = storage.items[i];
800 const eNodeSocketDatatype socket_type = eNodeSocketDatatype(item.socket_type);
801 if (socket_type == SOCK_GEOMETRY && i > 0) {
802 b.add_separator();
803 }
804 const StringRef name = item.name;
805 const std::string identifier = SimulationItemsAccessor::socket_identifier_for_item(item);
806 auto &input_decl = b.add_input(socket_type, name, identifier)
807 .socket_name_ptr(
808 &tree->id, SimulationItemsAccessor::item_srna, &item, "name");
809 auto &output_decl = b.add_output(socket_type, name, identifier).align_with_previous();
810 if (socket_type_supports_fields(socket_type)) {
811 /* If it's below a geometry input it may be a field evaluated on that geometry. */
812 input_decl.supports_field().structure_type(StructureType::Dynamic);
813 output_decl.dependent_field({input_decl.index()});
814 }
815 }
816 b.add_input<decl::Extend>("", "__extend__").structure_type(StructureType::Dynamic);
817 b.add_output<decl::Extend>("", "__extend__")
818 .structure_type(StructureType::Dynamic)
819 .align_with_previous();
820}
821
822static void node_init(bNodeTree * /*tree*/, bNode *node)
823{
825
826 data->next_identifier = 0;
827
828 data->items = MEM_calloc_arrayN<NodeSimulationItem>(1, __func__);
829 data->items[0].name = BLI_strdup(DATA_("Geometry"));
830 data->items[0].socket_type = SOCK_GEOMETRY;
831 data->items[0].identifier = data->next_identifier++;
832 data->items_num = 1;
833
834 node->storage = data;
835}
836
842
843static void node_copy_storage(bNodeTree * /*dst_tree*/, bNode *dst_node, const bNode *src_node)
844{
845 const NodeGeometrySimulationOutput &src_storage = node_storage(*src_node);
846 auto *dst_storage = MEM_dupallocN<NodeGeometrySimulationOutput>(__func__, src_storage);
847 dst_node->storage = dst_storage;
848
850}
851
856
857static bool node_insert_link(bNodeTree *ntree, bNode *node, bNodeLink *link)
858{
860 *ntree, *node, *node, *link);
861}
862
864{
865 BakeDrawContext ctx;
866 if (!get_bake_draw_context(&params.C, params.node, ctx)) {
867 return;
868 }
871 row.text = TIP_("Can't bake in zone");
872 row.icon = ICON_ERROR;
873 params.rows.append(std::move(row));
874 }
875 if (ctx.is_baked) {
877 row.text = get_baked_string(ctx);
878 params.rows.append(std::move(row));
879 }
880}
881
883{
884 const bNodeSocket &other_socket = params.other_socket();
886 return;
887 }
888 params.add_item_full_name(IFACE_("Simulation"), [](LinkSearchOpParams &params) {
889 bNode &input_node = params.add_node("GeometryNodeSimulationInput");
890 bNode &output_node = params.add_node("GeometryNodeSimulationOutput");
891 output_node.location[0] = 300;
892
893 auto &input_storage = *static_cast<NodeGeometrySimulationInput *>(input_node.storage);
894 input_storage.output_node_id = output_node.identifier;
895
898 output_node, eNodeSocketDatatype(params.socket.type), params.socket.name);
899 update_node_declaration_and_sockets(params.node_tree, input_node);
900 update_node_declaration_and_sockets(params.node_tree, output_node);
901 if (params.socket.in_out == SOCK_IN) {
902 params.connect_available_socket(output_node, params.socket.name);
903 }
904 else {
905 params.connect_available_socket(input_node, params.socket.name);
906 }
907 params.node_tree.ensure_topology_cache();
908 bke::node_add_link(params.node_tree,
909 input_node,
910 input_node.output_socket(1),
911 output_node,
912 output_node.input_socket(1));
913 });
914}
915
916static void node_blend_write(const bNodeTree & /*tree*/, const bNode &node, BlendWriter &writer)
917{
919}
920
921static void node_blend_read(bNodeTree & /*tree*/, bNode &node, BlendDataReader &reader)
922{
924}
925
926static void node_register()
927{
928 static blender::bke::bNodeType ntype;
929
930 geo_node_type_base(&ntype, "GeometryNodeSimulationOutput", GEO_NODE_SIMULATION_OUTPUT);
931 ntype.ui_name = "Simulation Output";
932 ntype.ui_description = "Output data from the simulation zone";
933 ntype.enum_name_legacy = "SIMULATION_OUTPUT";
935 ntype.initfunc = node_init;
936 ntype.declare = node_declare;
941 ntype.no_muting = true;
947 ntype, "NodeGeometrySimulationOutput", node_free_storage, node_copy_storage);
949}
950NOD_REGISTER_NODE(node_register)
951
952} // namespace sim_output_node
953
954} // namespace blender::nodes::node_geo_simulation_cc
955
956namespace blender::nodes {
957
958std::unique_ptr<LazyFunction> get_simulation_input_lazy_function(
959 const bNodeTree &node_tree,
960 const bNode &node,
961 GeometryNodesLazyFunctionGraphInfo &own_lf_graph_info)
962{
964 return std::make_unique<
966 node_tree, node, own_lf_graph_info);
967}
968
969std::unique_ptr<LazyFunction> get_simulation_output_lazy_function(
970 const bNode &node, GeometryNodesLazyFunctionGraphInfo &own_lf_graph_info)
971{
973 return std::make_unique<
975 node, own_lf_graph_info);
976}
977
979 void *prev,
980 const void *next,
981 const float factor)
982{
983 switch (socket_type) {
984 case SOCK_GEOMETRY: {
985 GeometrySet &prev_geo = *static_cast<GeometrySet *>(prev);
986 const GeometrySet &next_geo = *static_cast<const GeometrySet *>(next);
987 prev_geo = geometry::mix_geometries(std::move(prev_geo), next_geo, factor);
988 break;
989 }
990 case SOCK_FLOAT:
991 case SOCK_VECTOR:
992 case SOCK_INT:
993 case SOCK_BOOLEAN:
994 case SOCK_ROTATION:
995 case SOCK_RGBA:
996 case SOCK_MATRIX: {
997 const CPPType &type = *bke::socket_type_to_geo_nodes_base_cpp_type(socket_type);
998 SocketValueVariant prev_value_variant = *static_cast<const SocketValueVariant *>(prev);
999 SocketValueVariant next_value_variant = *static_cast<const SocketValueVariant *>(next);
1000 if (prev_value_variant.is_context_dependent_field() ||
1001 next_value_variant.is_context_dependent_field())
1002 {
1003 /* Fields are evaluated on geometries and are mixed there. */
1004 break;
1005 }
1006
1007 prev_value_variant.convert_to_single();
1008 next_value_variant.convert_to_single();
1009
1010 void *prev_value = prev_value_variant.get_single_ptr().get();
1011 const void *next_value = next_value_variant.get_single_ptr().get();
1012
1013 bke::attribute_math::convert_to_static_type(type, [&](auto dummy) {
1014 using T = decltype(dummy);
1015 *static_cast<T *>(prev_value) = bke::attribute_math::mix2(
1016 factor, *static_cast<T *>(prev_value), *static_cast<const T *>(next_value));
1017 });
1018 break;
1019 }
1020 default:
1021 break;
1022 }
1023}
1024
1025StructRNA *SimulationItemsAccessor::item_srna = &RNA_SimulationStateItem;
1026
1028{
1029 BLO_write_string(writer, item.name);
1030}
1031
1036
1037} // namespace blender::nodes
1038
1039blender::Span<NodeSimulationItem> NodeGeometrySimulationOutput::items_span() const
1040{
1041 return blender::Span<NodeSimulationItem>(items, items_num);
1042}
1043
1044blender::MutableSpan<NodeSimulationItem> NodeGeometrySimulationOutput::items_span()
1045{
1046 return blender::MutableSpan<NodeSimulationItem>(items, items_num);
1047}
Low-level operations for curves.
#define NODE_CLASS_INTERFACE
Definition BKE_node.hh:445
#define NODE_STORAGE_FUNCS(StorageT)
Definition BKE_node.hh:1215
#define GEO_NODE_SIMULATION_OUTPUT
#define GEO_NODE_SIMULATION_INPUT
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
#define final(a, b, c)
Definition BLI_hash.h:19
char * BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC
Definition string.cc:41
char * BLI_strncpy_utf8(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
#define ELEM(...)
void BLO_read_string(BlendDataReader *reader, char **ptr_p)
Definition readfile.cc:5351
void BLO_write_string(BlendWriter *writer, const char *data_ptr)
#define TIP_(msgid)
#define IFACE_(msgid)
#define DATA_(msgid)
@ SOCK_IN
eNodeSocketDatatype
@ SOCK_INT
@ SOCK_VECTOR
@ SOCK_BOOLEAN
@ SOCK_MATRIX
@ SOCK_FLOAT
@ SOCK_GEOMETRY
@ SOCK_ROTATION
@ SOCK_RGBA
#define NOD_REGISTER_NODE(REGISTER_FUNC)
#define C
Definition RandGen.cpp:29
void uiLayoutSetActive(uiLayout *layout, bool active)
void uiLayoutSetEnabled(uiLayout *layout, bool enabled)
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
#define UI_ITEM_NONE
void uiLayoutSetPropDecorate(uiLayout *layout, bool is_sep)
#define U
BMesh const char void * data
void resize(const int64_t new_size)
Span< T > as_span() const
Definition BLI_array.hh:232
static const CPPType & get()
void destruct(void *ptr) const
const ComputeContextHash & hash() const
const void * get() const
void * allocate(const int64_t size, const int64_t alignment)
constexpr int64_t size() const
Definition BLI_span.hh:252
constexpr IndexRange index_range() const
Definition BLI_span.hh:401
void append(const T &value)
void resize(const int64_t new_size)
std::optional< int > output_node_id
const bNode * output_node() const
const bNodeTreeZone * get_zone_by_node(const int32_t node_id) const
virtual SimulationZoneBehavior * get(const int zone_id) const =0
void output_simulation_state_move(lf::Params &params, const GeoNodesUserData &user_data, bke::bake::BakeDataBlockMap *data_block_map, bke::bake::BakeState zone_state) const
void pass_through(lf::Params &params, const GeoNodesUserData &user_data, bke::bake::BakeDataBlockMap *data_block_map) const
void execute_impl(lf::Params &params, const lf::Context &context) const final
LazyFunctionForSimulationInputNode(const bNodeTree &node_tree, const bNode &node, GeometryNodesLazyFunctionGraphInfo &own_lf_graph_info)
void output_simulation_state_copy(lf::Params &params, const GeoNodesUserData &user_data, bke::bake::BakeDataBlockMap *data_block_map, const bke::bake::BakeStateRef &zone_state) const
void output_mixed_cached_state(lf::Params &params, bke::bake::BakeDataBlockMap *data_block_map, const Object &self_object, const ComputeContext &compute_context, const bke::bake::BakeStateRef &prev_state, const bke::bake::BakeStateRef &next_state, const float mix_factor) const
void pass_through(lf::Params &params, GeoNodesUserData &user_data, bke::bake::BakeDataBlockMap *data_block_map) const
void execute_impl(lf::Params &params, const lf::Context &context) const final
void store_new_state(lf::Params &params, GeoNodesUserData &user_data, bke::bake::BakeDataBlockMap *data_block_map, const sim_output::StoreNewState &info) const
LazyFunctionForSimulationOutputNode(const bNode &node, GeometryNodesLazyFunctionGraphInfo &own_lf_graph_info)
void output_cached_state(lf::Params &params, GeoNodesUserData &user_data, bke::bake::BakeDataBlockMap *data_block_map, const bke::bake::BakeStateRef &state) const
std::optional< bke::bake::BakeState > get_bake_state_from_inputs(lf::Params &params, bke::bake::BakeDataBlockMap *data_block_map, const bool skip) const
KDTree_3d * tree
uint col
#define ID_IS_EDITABLE(_id)
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:123
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void * MEM_dupallocN(const void *vmemh)
Definition mallocn.cc:143
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
static ulong * next
static ulong state[N]
static void next_state()
#define T
void convert_to_static_type(const CPPType &cpp_type, const Func &func)
T mix2(float factor, const T &a, const T &b)
Array< std::unique_ptr< BakeItem > > move_socket_values_to_bake_items(Span< void * > socket_values, const BakeSocketConfig &config, BakeDataBlockMap *data_block_map)
void copy_bake_items_to_socket_values(Span< const BakeItem * > bake_items, const BakeSocketConfig &config, BakeDataBlockMap *data_block_map, FunctionRef< std::shared_ptr< AttributeFieldInput >(int, const CPPType &)> make_attribute_field, Span< void * > r_socket_values)
void move_bake_items_to_socket_values(Span< BakeItem * > bake_items, const BakeSocketConfig &config, BakeDataBlockMap *data_block_map, FunctionRef< std::shared_ptr< AttributeFieldInput >(int socket_index, const CPPType &)> make_attribute_field, Span< void * > r_socket_values)
void node_register_type(bNodeType &ntype)
Definition node.cc:2748
const CPPType * socket_type_to_geo_nodes_base_cpp_type(eNodeSocketDatatype type)
Definition node.cc:5413
bNodeLink & node_add_link(bNodeTree &ntree, bNode &fromnode, bNodeSocket &fromsock, bNode &tonode, bNodeSocket &tosock)
Definition node.cc:4087
bNodeSocketType * node_socket_type_find_static(int type, int subtype=0)
Definition node.cc:2803
std::string hash_to_anonymous_attribute_name(Args &&...args)
void node_type_storage(bNodeType &ntype, std::optional< StringRefNull > storagename, void(*freefunc)(bNode *node), void(*copyfunc)(bNodeTree *dest_ntree, bNode *dest_node, const bNode *src_node))
Definition node.cc:5603
bke::GeometrySet mix_geometries(bke::GeometrySet a, const bke::GeometrySet &b, float factor)
static void node_label(const bNodeTree *, const bNode *, char *label, const int label_maxncpy)
static bool node_insert_link(bNodeTree *ntree, bNode *node, bNodeLink *link)
static void node_blend_write(const bNodeTree &, const bNode &node, BlendWriter &writer)
static void node_copy_storage(bNodeTree *, bNode *dst_node, const bNode *src_node)
static void node_extra_info(NodeExtraInfoParams &params)
static bool node_insert_link(bNodeTree *ntree, bNode *node, bNodeLink *link)
static void node_gather_link_searches(GatherLinkSearchOpParams &params)
static void node_blend_read(bNodeTree &, bNode &node, BlendDataReader &reader)
static const CPPType & get_simulation_item_cpp_type(const eNodeSocketDatatype socket_type)
static void node_layout_ex(uiLayout *layout, bContext *C, PointerRNA *current_node_ptr)
static bke::bake::BakeState move_values_to_simulation_state(const Span< NodeSimulationItem > node_simulation_items, const Span< void * > input_values, bke::bake::BakeDataBlockMap *data_block_map)
static std::shared_ptr< AttributeFieldInput > make_attribute_field(const Object &self_object, const ComputeContext &compute_context, const bNode &node, const NodeSimulationItem &item, const CPPType &type)
static void move_simulation_state_to_values(const Span< NodeSimulationItem > node_simulation_items, bke::bake::BakeState zone_state, const Object &self_object, const ComputeContext &compute_context, const bNode &node, bke::bake::BakeDataBlockMap *data_block_map, Span< void * > r_output_values)
static void draw_simulation_state(const bContext *C, uiLayout *layout, bNodeTree &ntree, bNode &output_node)
static bke::bake::BakeSocketConfig make_bake_socket_config(const Span< NodeSimulationItem > node_simulation_items)
static void copy_simulation_state_to_values(const Span< NodeSimulationItem > node_simulation_items, const bke::bake::BakeStateRef &zone_state, const Object &self_object, const ComputeContext &compute_context, const bNode &node, bke::bake::BakeDataBlockMap *data_block_map, Span< void * > r_output_values)
std::variant< PassThrough, OutputCopy, OutputMove > Behavior
std::variant< PassThrough, StoreNewState, ReadSingle, ReadInterpolated, ReadError > Behavior
static void draw_items_list_with_operators(const bContext *C, uiLayout *layout, const bNodeTree &tree, const bNode &node)
static void draw_active_item_props(const bNodeTree &tree, const bNode &node, const FunctionRef< void(PointerRNA *item_ptr)> draw_item)
void blend_write(BlendWriter *writer, const bNode &node)
void blend_read_data(BlendDataReader *reader, bNode &node)
void copy_array(const bNode &src_node, bNode &dst_node)
Accessor::ItemT * add_item_with_socket_type_and_name(bNode &node, const eNodeSocketDatatype socket_type, const char *name)
bool try_add_item_via_any_extend_socket(bNodeTree &ntree, bNode &extend_node, bNode &storage_node, bNodeLink &link, const std::optional< StringRef > socket_identifier=std::nullopt)
bool get_bake_draw_context(const bContext *C, const bNode &node, BakeDrawContext &r_ctx)
std::unique_ptr< LazyFunction > get_simulation_output_lazy_function(const bNode &node, GeometryNodesLazyFunctionGraphInfo &own_lf_graph_info)
void draw_data_blocks(const bContext *C, uiLayout *layout, PointerRNA &bake_rna)
std::unique_ptr< LazyFunction > get_simulation_input_lazy_function(const bNodeTree &node_tree, const bNode &node, GeometryNodesLazyFunctionGraphInfo &own_lf_graph_info)
void update_node_declaration_and_sockets(bNodeTree &ntree, bNode &node)
void draw_common_bake_settings(bContext *C, BakeDrawContext &ctx, uiLayout *layout)
void draw_bake_button_row(const BakeDrawContext &ctx, uiLayout *layout, bool is_in_sidebar=false)
std::string make_anonymous_attribute_socket_inspection_string(const bNodeSocket &socket)
std::optional< FoundNestedNodeID > find_nested_node_id(const GeoNodesUserData &user_data, const int node_id)
bool socket_type_supports_fields(const eNodeSocketDatatype socket_type)
void set_default_remaining_node_outputs(lf::Params &params, const bNode &node)
std::optional< std::string > get_bake_state_string(const BakeDrawContext &ctx)
void mix_baked_data_item(eNodeSocketDatatype socket_type, void *prev, const void *next, const float factor)
std::string get_baked_string(const BakeDrawContext &ctx)
void geo_node_type_base(blender::bke::bNodeType *ntype, std::string idname, const std::optional< int16_t > legacy_type)
void node_free_standard_storage(bNode *node)
Definition node_util.cc:42
void node_copy_standard_storage(bNodeTree *, bNode *dest_node, const bNode *src_node)
Definition node_util.cc:54
char name[66]
Definition DNA_ID.h:415
ID * owner_id
Definition RNA_types.hh:51
void * data
Definition RNA_types.hh:53
bNodeSocketTypeHandle * typeinfo
float location[2]
int16_t type_legacy
void * storage
int32_t identifier
Defines a socket type.
Definition BKE_node.hh:152
const blender::CPPType * geometry_nodes_cpp_type
Definition BKE_node.hh:203
Defines a node type.
Definition BKE_node.hh:226
NodeBlendWriteFunction blend_write_storage_content
Definition BKE_node.hh:383
std::string ui_description
Definition BKE_node.hh:232
NodeBlendDataReadFunction blend_data_read_storage_content
Definition BKE_node.hh:384
void(* initfunc)(bNodeTree *ntree, bNode *node)
Definition BKE_node.hh:277
void(* labelfunc)(const bNodeTree *ntree, const bNode *node, char *label, int label_maxncpy)
Definition BKE_node.hh:258
void(* draw_buttons_ex)(uiLayout *, bContext *C, PointerRNA *ptr)
Definition BKE_node.hh:249
NodeExtraInfoFunction get_extra_info
Definition BKE_node.hh:374
const char * enum_name_legacy
Definition BKE_node.hh:235
NodeGatherSocketLinkOperationsFunction gather_link_search_ops
Definition BKE_node.hh:371
bool(* insert_link)(bNodeTree *ntree, bNode *node, bNodeLink *link)
Definition BKE_node.hh:321
NodeDeclareFunction declare
Definition BKE_node.hh:355
void(* register_operators)()
Definition BKE_node.hh:410
Vector< Vector< int, 1 > > geometries_by_attribute
Map< int, const BakeItem * > items_by_id
Map< int, std::unique_ptr< BakeItem > > items_by_id
geo_eval_log::GeoTreeLogger * try_get_tree_logger(const GeoNodesUserData &user_data) const
static void blend_read_data_item(BlendDataReader *reader, ItemT &item)
static std::string socket_identifier_for_item(const NodeSimulationItem &item)
static void blend_write_item(BlendWriter *writer, const ItemT &item)
static bool supports_socket_type(const eNodeSocketDatatype socket_type)
std::function< void(bke::bake::BakeState state)> store_fn
PanelLayout panel(const bContext *C, blender::StringRef idname, bool default_closed)
void label(blender::StringRef name, int icon)
uiLayout & column(bool align)
i
Definition text_draw.cc:230