From e53f0066f9bb84670bfc3987001a81e68bc78005 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Mon, 29 Sep 2025 18:17:35 +0200 Subject: [PATCH] Fix #146409: nested shader node outputs are ignored This was supported before, and was accidentally removed in 32c301e3cf417. This patch brings back support for nested shader node outputs. Only rule is that they must not be in a zone. Pull Request: https://projects.blender.org/blender/blender/pulls/146983 --- .../nodes/NOD_node_in_compute_context.hh | 47 ++++++++++++++- .../nodes/intern/shader_nodes_inline.cc | 60 +++++++++++++++---- 2 files changed, 93 insertions(+), 14 deletions(-) diff --git a/source/blender/nodes/NOD_node_in_compute_context.hh b/source/blender/nodes/NOD_node_in_compute_context.hh index e03af06160f..61a7c28445b 100644 --- a/source/blender/nodes/NOD_node_in_compute_context.hh +++ b/source/blender/nodes/NOD_node_in_compute_context.hh @@ -43,7 +43,7 @@ struct NodeInContext { }; /** - * Utility struct to pair a socket with a compute context. This unique identifies a socket in a + * Utility struct to pair a socket with a compute context. This uniquely identifies a socket in a * node-tree evaluation. */ struct SocketInContext { @@ -65,6 +65,20 @@ struct SocketInContext { BLI_STRUCT_EQUALITY_OPERATORS_2(SocketInContext, context_hash(), socket) }; +/** + * Utility struct to pair a tree with a compute context. + */ +struct TreeInContext { + const ComputeContext *context = nullptr; + const bNodeTree *tree = nullptr; + + uint64_t hash() const; + ComputeContextHash context_hash() const; + const bNodeTree *operator->() const; + const bNodeTree &operator*() const; + operator bool() const; +}; + /* -------------------------------------------------------------------- */ /** \name #NodeInContext Inline Methods * \{ */ @@ -142,4 +156,35 @@ inline NodeInContext SocketInContext::owner_node() const /** \} */ +/* -------------------------------------------------------------------- */ +/** \name #TreeInContext Inline Methods + * \{ */ + +inline uint64_t TreeInContext::hash() const +{ + return get_default_hash(this->context_hash(), this->tree); +} + +inline ComputeContextHash TreeInContext::context_hash() const +{ + return context ? context->hash() : ComputeContextHash{}; +} + +inline const bNodeTree *TreeInContext::operator->() const +{ + return this->tree; +} + +inline const bNodeTree &TreeInContext::operator*() const +{ + return *this->tree; +} + +inline TreeInContext::operator bool() const +{ + return this->tree != nullptr; +} + +/** \} */ + } // namespace blender::nodes diff --git a/source/blender/nodes/intern/shader_nodes_inline.cc b/source/blender/nodes/intern/shader_nodes_inline.cc index 4637af091c7..5034bbc54d3 100644 --- a/source/blender/nodes/intern/shader_nodes_inline.cc +++ b/source/blender/nodes/intern/shader_nodes_inline.cc @@ -272,23 +272,24 @@ class ShaderNodesInliner { return true; } - Vector find_final_output_sockets() const + Vector find_final_output_sockets() { - const bke::bNodeTreeZones *zones = src_tree_.zones(); - if (!zones) { - return {}; - } + Vector trees; + this->find_trees_potentially_containing_shader_outputs_recursive(nullptr, src_tree_, trees); Vector output_sockets; auto add_output_type = [&](const char *output_type) { - for (const bNode *node : src_tree_.nodes_by_type(output_type)) { - const bke::bNodeTreeZone *zone = zones->get_zone_by_node(node->identifier); - if (zone) { - params_.r_error_messages.append({node, TIP_("Output node must not be in zone")}); - continue; - } - for (const bNodeSocket *socket : node->input_sockets()) { - output_sockets.append({nullptr, socket}); + for (const TreeInContext &tree : trees) { + const bke::bNodeTreeZones &zones = *tree->zones(); + for (const bNode *node : tree->nodes_by_type(output_type)) { + const bke::bNodeTreeZone *zone = zones.get_zone_by_node(node->identifier); + if (zone) { + params_.r_error_messages.append({node, TIP_("Output node must not be in zone")}); + continue; + } + for (const bNodeSocket *socket : node->input_sockets()) { + output_sockets.append({tree.context, socket}); + } } } }; @@ -316,6 +317,39 @@ class ShaderNodesInliner { return output_sockets; } + void find_trees_potentially_containing_shader_outputs_recursive(const ComputeContext *context, + const bNodeTree &tree, + Vector &r_trees) + { + const bke::bNodeTreeZones *zones = src_tree_.zones(); + if (!zones) { + return; + } + if (tree.has_available_link_cycle()) { + return; + } + r_trees.append({context, &tree}); + for (const bNode *group_node : tree.group_nodes()) { + if (group_node->is_muted()) { + continue; + } + const bNodeTree *group = id_cast(group_node->id); + if (!group || ID_MISSING(&group->id)) { + continue; + } + group->ensure_topology_cache(); + const bke::bNodeTreeZone *zone = zones->get_zone_by_node(group_node->identifier); + if (zone) { + /* Node groups in zones are ignored. */ + continue; + } + const ComputeContext &group_context = compute_context_cache_.for_group_node( + context, group_node->identifier, &tree); + this->find_trees_potentially_containing_shader_outputs_recursive( + &group_context, *group, r_trees); + } + } + void handle_socket(const SocketInContext &socket) { if (!socket->is_available()) {