/* SPDX-FileCopyrightText: 2024 Blender Authors * * SPDX-License-Identifier: GPL-2.0-or-later */ #include #include #include "BLI_index_range.hh" #include "BLI_math_base.hh" #include "BLI_set.hh" #include "BLI_string_ref.hh" #include "BKE_compositor.hh" #include "BKE_cryptomatte.hh" #include "BKE_node.hh" #include "BKE_node_runtime.hh" #include "DNA_layer_types.h" #include "DNA_node_types.h" #include "DNA_scene_types.h" namespace blender::bke::compositor { /* Adds the pass names of the passes used by the given Render Layer node to the given used passes. * This essentially adds the identifiers of the outputs that are logically linked, their the * identifiers are the names of the passes. Note however that the Image output is actually the * Combined pass, but named as Image for compatibility reasons. */ static void add_passes_used_by_render_layer_node(const bNode *node, Set &used_passes) { for (const bNodeSocket *output : node->output_sockets()) { if (output->is_logically_linked()) { if (StringRef(output->identifier) == "Image") { used_passes.add(RE_PASSNAME_COMBINED); } else { used_passes.add(output->identifier); } } } } /* Adds the pass names of all Cryptomatte layers needed by the given node to the given used passes. * Only passes in the given viewer layers are added. */ static void add_passes_used_by_cryptomatte_node(const bNode *node, const ViewLayer *view_layer, Set &used_passes) { if (node->custom1 != CMP_NODE_CRYPTOMATTE_SOURCE_RENDER) { return; } Scene *scene = reinterpret_cast(node->id); if (!scene) { return; } cryptomatte::CryptomatteSessionPtr session = cryptomatte::CryptomatteSessionPtr( BKE_cryptomatte_init_from_scene(scene, false)); const Vector &layer_names = cryptomatte::BKE_cryptomatte_layer_names_get(*session); if (layer_names.is_empty()) { return; } /* If the stored layer name doesn't corresponds to an existing Cryptomatte layer, fallback to the * name of the first layer. */ const NodeCryptomatte *data = static_cast(node->storage); const std::string layer_name = layer_names.contains(data->layer_name) ? data->layer_name : layer_names[0]; /* Does not use passes from the given view layer, so no need to add anything. */ if (!StringRef(layer_name).startswith(view_layer->name)) { return; } /* Find out which type of Cryptomatte layers the node needs. Also ensure the type is enabled in * the view layer, because the node can use one of the types as a placeholder. */ const char *cryptomatte_type_name = nullptr; if (StringRef(layer_name).endswith(RE_PASSNAME_CRYPTOMATTE_OBJECT)) { if (view_layer->cryptomatte_flag & VIEW_LAYER_CRYPTOMATTE_OBJECT) { cryptomatte_type_name = RE_PASSNAME_CRYPTOMATTE_OBJECT; } } else if (StringRef(layer_name).endswith(RE_PASSNAME_CRYPTOMATTE_ASSET)) { if (view_layer->cryptomatte_flag & VIEW_LAYER_CRYPTOMATTE_ASSET) { cryptomatte_type_name = RE_PASSNAME_CRYPTOMATTE_ASSET; } } else if (StringRef(layer_name).endswith(RE_PASSNAME_CRYPTOMATTE_MATERIAL)) { if (view_layer->cryptomatte_flag & VIEW_LAYER_CRYPTOMATTE_MATERIAL) { cryptomatte_type_name = RE_PASSNAME_CRYPTOMATTE_MATERIAL; } } if (!cryptomatte_type_name) { return; } /* Each layer stores two ranks/levels, so do ceiling division by two. */ const int cryptomatte_layers_count = int(math::ceil(view_layer->cryptomatte_levels / 2.0f)); for (const int i : IndexRange(cryptomatte_layers_count)) { used_passes.add(fmt::format("{}{:02}", cryptomatte_type_name, i)); } } /* Adds the pass names of the passes used by the given compositor node tree to the given used * passes. This is called recursively for node groups. */ static void add_used_passes_recursive(const bNodeTree *node_tree, const ViewLayer *view_layer, Set &node_trees_already_searched, Set &used_passes) { if (node_tree == nullptr) { return; } node_tree->ensure_topology_cache(); for (const bNode *node : node_tree->all_nodes()) { if (node->is_muted()) { continue; } switch (node->type) { case NODE_GROUP: case NODE_CUSTOM_GROUP: { const bNodeTree *node_group_tree = reinterpret_cast(node->id); if (node_trees_already_searched.add(node_group_tree)) { add_used_passes_recursive( node_group_tree, view_layer, node_trees_already_searched, used_passes); } break; } case CMP_NODE_R_LAYERS: add_passes_used_by_render_layer_node(node, used_passes); break; case CMP_NODE_CRYPTOMATTE: add_passes_used_by_cryptomatte_node(node, view_layer, used_passes); break; default: break; } } } Set get_used_passes(const Scene &scene, const ViewLayer *view_layer) { Set used_passes; Set node_trees_already_searched; add_used_passes_recursive(scene.nodetree, view_layer, node_trees_already_searched, used_passes); return used_passes; } } // namespace blender::bke::compositor