Moving these defines to a separate header makes their "legacy" status
more obvious. This commit just adds the include wherever necessary.
Followup to 971c96a92c.
Pull Request: https://projects.blender.org/blender/blender/pulls/132875
156 lines
5.4 KiB
C++
156 lines
5.4 KiB
C++
/* SPDX-FileCopyrightText: 2024 Blender Authors
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
#include <string>
|
|
|
|
#include <fmt/format.h>
|
|
|
|
#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_legacy_types.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<std::string> &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<std::string> &used_passes)
|
|
{
|
|
if (node->custom1 != CMP_NODE_CRYPTOMATTE_SOURCE_RENDER) {
|
|
return;
|
|
}
|
|
|
|
Scene *scene = reinterpret_cast<Scene *>(node->id);
|
|
if (!scene) {
|
|
return;
|
|
}
|
|
|
|
cryptomatte::CryptomatteSessionPtr session = cryptomatte::CryptomatteSessionPtr(
|
|
BKE_cryptomatte_init_from_scene(scene, false));
|
|
|
|
const Vector<std::string> &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<NodeCryptomatte *>(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<const bNodeTree *> &node_trees_already_searched,
|
|
Set<std::string> &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_legacy) {
|
|
case NODE_GROUP:
|
|
case NODE_CUSTOM_GROUP: {
|
|
const bNodeTree *node_group_tree = reinterpret_cast<const bNodeTree *>(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<std::string> get_used_passes(const Scene &scene, const ViewLayer *view_layer)
|
|
{
|
|
Set<std::string> used_passes;
|
|
Set<const bNodeTree *> 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
|