diff options
Diffstat (limited to 'source/blender/nodes')
-rw-r--r-- | source/blender/nodes/NOD_composite.h | 1 | ||||
-rw-r--r-- | source/blender/nodes/NOD_static_types.h | 3 | ||||
-rw-r--r-- | source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc | 271 |
3 files changed, 232 insertions, 43 deletions
diff --git a/source/blender/nodes/NOD_composite.h b/source/blender/nodes/NOD_composite.h index 6ad02986010..b0dd0edeec5 100644 --- a/source/blender/nodes/NOD_composite.h +++ b/source/blender/nodes/NOD_composite.h @@ -106,6 +106,7 @@ void register_node_type_cmp_doubleedgemask(void); void register_node_type_cmp_keyingscreen(void); void register_node_type_cmp_keying(void); void register_node_type_cmp_cryptomatte(void); +void register_node_type_cmp_cryptomatte_legacy(void); void register_node_type_cmp_translate(void); void register_node_type_cmp_rotate(void); diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index 493aaa05675..e9983d7e92c 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -220,7 +220,8 @@ DefNode(CompositorNode, CMP_NODE_PIXELATE, 0, "PIXELA DefNode(CompositorNode, CMP_NODE_PLANETRACKDEFORM,def_cmp_planetrackdeform,"PLANETRACKDEFORM",PlaneTrackDeform,"Plane Track Deform","" ) DefNode(CompositorNode, CMP_NODE_CORNERPIN, 0, "CORNERPIN", CornerPin, "Corner Pin", "" ) DefNode(CompositorNode, CMP_NODE_SUNBEAMS, def_cmp_sunbeams, "SUNBEAMS", SunBeams, "Sun Beams", "" ) -DefNode(CompositorNode, CMP_NODE_CRYPTOMATTE, def_cmp_cryptomatte, "CRYPTOMATTE", Cryptomatte, "Cryptomatte", "" ) +DefNode(CompositorNode, CMP_NODE_CRYPTOMATTE, def_cmp_cryptomatte, "CRYPTOMATTE_V2", CryptomatteV2, "Cryptomatte", "" ) +DefNode(CompositorNode, CMP_NODE_CRYPTOMATTE_LEGACY, def_cmp_cryptomatte_legacy, "CRYPTOMATTE", Cryptomatte, "Cryptomatte (Legacy)", "" ) DefNode(CompositorNode, CMP_NODE_DENOISE, def_cmp_denoise, "DENOISE", Denoise, "Denoise", "" ) DefNode(CompositorNode, CMP_NODE_EXPOSURE, 0, "EXPOSURE", Exposure, "Exposure", "" ) diff --git a/source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc b/source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc index 84cd84e41c7..d81076c2fa6 100644 --- a/source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc +++ b/source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc @@ -21,11 +21,84 @@ * \ingroup cmpnodes */ +#include "node_composite_util.h" + #include "BLI_assert.h" #include "BLI_dynstr.h" #include "BLI_hash_mm3.h" +#include "BLI_string_ref.hh" #include "BLI_utildefines.h" -#include "node_composite_util.h" + +#include "BKE_context.h" +#include "BKE_cryptomatte.hh" +#include "BKE_global.h" +#include "BKE_lib_id.h" +#include "BKE_library.h" +#include "BKE_main.h" + +#include <optional> + +/** \name Cryptomatte + * \{ */ + +static blender::bke::cryptomatte::CryptomatteSessionPtr cryptomatte_init_from_node( + const bNode &node, const int frame_number, const bool use_meta_data) +{ + blender::bke::cryptomatte::CryptomatteSessionPtr session; + if (node.type != CMP_NODE_CRYPTOMATTE) { + return session; + } + + NodeCryptomatte *node_cryptomatte = static_cast<NodeCryptomatte *>(node.storage); + switch (node.custom1) { + case CMP_CRYPTOMATTE_SRC_RENDER: { + Scene *scene = (Scene *)node.id; + if (!scene) { + return session; + } + BLI_assert(GS(scene->id.name) == ID_SCE); + + if (use_meta_data) { + Render *render = (scene) ? RE_GetSceneRender(scene) : nullptr; + RenderResult *render_result = render ? RE_AcquireResultRead(render) : nullptr; + if (render_result) { + session = blender::bke::cryptomatte::CryptomatteSessionPtr( + BKE_cryptomatte_init_from_render_result(render_result)); + } + if (render) { + RE_ReleaseResult(render); + } + } + + if (session == nullptr) { + session = blender::bke::cryptomatte::CryptomatteSessionPtr( + BKE_cryptomatte_init_from_scene(scene)); + } + + break; + } + + case CMP_CRYPTOMATTE_SRC_IMAGE: { + Image *image = (Image *)node.id; + BLI_assert(!image || GS(image->id.name) == ID_IM); + if (!image || image->type != IMA_TYPE_MULTILAYER) { + break; + } + + ImageUser *iuser = &node_cryptomatte->iuser; + BKE_image_user_frame_calc(image, iuser, frame_number); + ImBuf *ibuf = BKE_image_acquire_ibuf(image, iuser, nullptr); + RenderResult *render_result = image->rr; + if (render_result) { + session = blender::bke::cryptomatte::CryptomatteSessionPtr( + BKE_cryptomatte_init_from_render_result(render_result)); + } + BKE_image_release_ibuf(image, ibuf, nullptr); + break; + } + } + return session; +} extern "C" { static CryptomatteEntry *cryptomatte_find(const NodeCryptomatte &n, float encoded_hash) @@ -38,21 +111,29 @@ static CryptomatteEntry *cryptomatte_find(const NodeCryptomatte &n, float encode return nullptr; } -static void cryptomatte_add(NodeCryptomatte &n, float f) +static void cryptomatte_add(bNode &node, NodeCryptomatte &node_cryptomatte, float encoded_hash) { /* Check if entry already exist. */ - if (cryptomatte_find(n, f)) { + if (cryptomatte_find(node_cryptomatte, encoded_hash)) { return; } + CryptomatteEntry *entry = static_cast<CryptomatteEntry *>( MEM_callocN(sizeof(CryptomatteEntry), __func__)); - entry->encoded_hash = f; - BLI_addtail(&n.entries, entry); + entry->encoded_hash = encoded_hash; + /* TODO(jbakker): Get current frame from scene. */ + blender::bke::cryptomatte::CryptomatteSessionPtr session = cryptomatte_init_from_node( + node, 0, true); + if (session) { + BKE_cryptomatte_find_name(session.get(), encoded_hash, entry->name, sizeof(entry->name)); + } + + BLI_addtail(&node_cryptomatte.entries, entry); } -static void cryptomatte_remove(NodeCryptomatte &n, float f) +static void cryptomatte_remove(NodeCryptomatte &n, float encoded_hash) { - CryptomatteEntry *entry = cryptomatte_find(n, f); + CryptomatteEntry *entry = cryptomatte_find(n, encoded_hash); if (!entry) { return; } @@ -60,73 +141,104 @@ static void cryptomatte_remove(NodeCryptomatte &n, float f) MEM_freeN(entry); } -static bNodeSocketTemplate outputs[] = { +static bNodeSocketTemplate cmp_node_cryptomatte_in[] = { + {SOCK_RGBA, N_("Image"), 0.0f, 0.0f, 0.0f, 1.0f}, {-1, ""}}; + +static bNodeSocketTemplate cmp_node_cryptomatte_out[] = { {SOCK_RGBA, N_("Image")}, {SOCK_FLOAT, N_("Matte")}, {SOCK_RGBA, N_("Pick")}, {-1, ""}, }; -void ntreeCompositCryptomatteSyncFromAdd(bNodeTree *UNUSED(ntree), bNode *node) +void ntreeCompositCryptomatteSyncFromAdd(bNode *node) { + BLI_assert(ELEM(node->type, CMP_NODE_CRYPTOMATTE, CMP_NODE_CRYPTOMATTE_LEGACY)); NodeCryptomatte *n = static_cast<NodeCryptomatte *>(node->storage); - if (n->add[0] != 0.0f) { - cryptomatte_add(*n, n->add[0]); - zero_v3(n->add); + if (n->runtime.add[0] != 0.0f) { + cryptomatte_add(*node, *n, n->runtime.add[0]); + zero_v3(n->runtime.add); } } -void ntreeCompositCryptomatteSyncFromRemove(bNodeTree *UNUSED(ntree), bNode *node) +void ntreeCompositCryptomatteSyncFromRemove(bNode *node) { + BLI_assert(ELEM(node->type, CMP_NODE_CRYPTOMATTE, CMP_NODE_CRYPTOMATTE_LEGACY)); NodeCryptomatte *n = static_cast<NodeCryptomatte *>(node->storage); - if (n->remove[0] != 0.0f) { - cryptomatte_remove(*n, n->remove[0]); - zero_v3(n->remove); + if (n->runtime.remove[0] != 0.0f) { + cryptomatte_remove(*n, n->runtime.remove[0]); + zero_v3(n->runtime.remove); } } - -bNodeSocket *ntreeCompositCryptomatteAddSocket(bNodeTree *ntree, bNode *node) +void ntreeCompositCryptomatteUpdateLayerNames(bNode *node) { + BLI_assert(node->type == CMP_NODE_CRYPTOMATTE); NodeCryptomatte *n = static_cast<NodeCryptomatte *>(node->storage); - char sockname[32]; - n->num_inputs++; - BLI_snprintf(sockname, sizeof(sockname), "Crypto %.2d", n->num_inputs - 1); - bNodeSocket *sock = nodeAddStaticSocket( - ntree, node, SOCK_IN, SOCK_RGBA, PROP_NONE, nullptr, sockname); - return sock; + BLI_freelistN(&n->runtime.layers); + + blender::bke::cryptomatte::CryptomatteSessionPtr session = cryptomatte_init_from_node( + *node, 0, false); + + if (session) { + for (blender::StringRef layer_name : + blender::bke::cryptomatte::BKE_cryptomatte_layer_names_get(*session)) { + CryptomatteLayer *layer = static_cast<CryptomatteLayer *>( + MEM_callocN(sizeof(CryptomatteLayer), __func__)); + layer_name.copy(layer->name); + BLI_addtail(&n->runtime.layers, layer); + } + } } -int ntreeCompositCryptomatteRemoveSocket(bNodeTree *ntree, bNode *node) +void ntreeCompositCryptomatteLayerPrefix(const bNode *node, char *r_prefix, size_t prefix_len) { - NodeCryptomatte *n = static_cast<NodeCryptomatte *>(node->storage); - if (n->num_inputs < 2) { - return 0; + BLI_assert(node->type == CMP_NODE_CRYPTOMATTE); + NodeCryptomatte *node_cryptomatte = (NodeCryptomatte *)node->storage; + blender::bke::cryptomatte::CryptomatteSessionPtr session = cryptomatte_init_from_node( + *node, 0, false); + std::string first_layer_name; + + if (session) { + for (blender::StringRef layer_name : + blender::bke::cryptomatte::BKE_cryptomatte_layer_names_get(*session)) { + if (first_layer_name.empty()) { + first_layer_name = layer_name; + } + + if (layer_name == node_cryptomatte->layer_name) { + BLI_strncpy(r_prefix, node_cryptomatte->layer_name, prefix_len); + return; + } + } } - bNodeSocket *sock = static_cast<bNodeSocket *>(node->inputs.last); - nodeRemoveSocket(ntree, node, sock); - n->num_inputs--; - return 1; + + const char *cstr = first_layer_name.c_str(); + BLI_strncpy(r_prefix, cstr, prefix_len); } -static void init(bNodeTree *ntree, bNode *node) +static void node_init_cryptomatte(bNodeTree *UNUSED(ntree), bNode *node) { NodeCryptomatte *user = static_cast<NodeCryptomatte *>( MEM_callocN(sizeof(NodeCryptomatte), __func__)); node->storage = user; +} - nodeAddStaticSocket(ntree, node, SOCK_IN, SOCK_RGBA, PROP_NONE, "image", "Image"); - - /* Add three inputs by default, as recommended by the Cryptomatte specification. */ - ntreeCompositCryptomatteAddSocket(ntree, node); - ntreeCompositCryptomatteAddSocket(ntree, node); - ntreeCompositCryptomatteAddSocket(ntree, node); +static void node_init_api_cryptomatte(const bContext *C, PointerRNA *ptr) +{ + Scene *scene = CTX_data_scene(C); + bNode *node = static_cast<bNode *>(ptr->data); + BLI_assert(node->type == CMP_NODE_CRYPTOMATTE); + node->id = &scene->id; + id_us_plus(node->id); } static void node_free_cryptomatte(bNode *node) { + BLI_assert(ELEM(node->type, CMP_NODE_CRYPTOMATTE, CMP_NODE_CRYPTOMATTE_LEGACY)); NodeCryptomatte *nc = static_cast<NodeCryptomatte *>(node->storage); if (nc) { + BLI_freelistN(&nc->runtime.layers); BLI_freelistN(&nc->entries); MEM_freeN(nc); } @@ -140,17 +252,92 @@ static void node_copy_cryptomatte(bNodeTree *UNUSED(dest_ntree), NodeCryptomatte *dest_nc = static_cast<NodeCryptomatte *>(MEM_dupallocN(src_nc)); BLI_duplicatelist(&dest_nc->entries, &src_nc->entries); + BLI_listbase_clear(&dest_nc->runtime.layers); dest_node->storage = dest_nc; } +static bool node_poll_cryptomatte(bNodeType *UNUSED(ntype), bNodeTree *ntree) +{ + if (STREQ(ntree->idname, "CompositorNodeTree")) { + Scene *scene; + + /* See node_composit_poll_rlayers. */ + for (scene = static_cast<Scene *>(G.main->scenes.first); scene; + scene = static_cast<Scene *>(scene->id.next)) { + if (scene->nodetree == ntree) { + break; + } + } + + return scene != nullptr; + } + return false; +} + void register_node_type_cmp_cryptomatte(void) { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_CRYPTOMATTE, "Cryptomatte", NODE_CLASS_CONVERTOR, 0); - node_type_socket_templates(&ntype, nullptr, outputs); - node_type_init(&ntype, init); + cmp_node_type_base(&ntype, CMP_NODE_CRYPTOMATTE, "Cryptomatte", NODE_CLASS_MATTE, 0); + node_type_socket_templates(&ntype, cmp_node_cryptomatte_in, cmp_node_cryptomatte_out); + node_type_init(&ntype, node_init_cryptomatte); + ntype.initfunc_api = node_init_api_cryptomatte; + ntype.poll = node_poll_cryptomatte; + node_type_storage(&ntype, "NodeCryptomatte", node_free_cryptomatte, node_copy_cryptomatte); + nodeRegisterType(&ntype); +} + +/** \} */ + +/** \name Cryptomatte Legacy + * \{ */ +static void node_init_cryptomatte_legacy(bNodeTree *ntree, bNode *node) +{ + node_init_cryptomatte(ntree, node); + + nodeAddStaticSocket(ntree, node, SOCK_IN, SOCK_RGBA, PROP_NONE, "image", "Image"); + + /* Add three inputs by default, as recommended by the Cryptomatte specification. */ + ntreeCompositCryptomatteAddSocket(ntree, node); + ntreeCompositCryptomatteAddSocket(ntree, node); + ntreeCompositCryptomatteAddSocket(ntree, node); +} + +bNodeSocket *ntreeCompositCryptomatteAddSocket(bNodeTree *ntree, bNode *node) +{ + BLI_assert(node->type == CMP_NODE_CRYPTOMATTE_LEGACY); + NodeCryptomatte *n = static_cast<NodeCryptomatte *>(node->storage); + char sockname[32]; + n->num_inputs++; + BLI_snprintf(sockname, sizeof(sockname), "Crypto %.2d", n->num_inputs - 1); + bNodeSocket *sock = nodeAddStaticSocket( + ntree, node, SOCK_IN, SOCK_RGBA, PROP_NONE, nullptr, sockname); + return sock; +} + +int ntreeCompositCryptomatteRemoveSocket(bNodeTree *ntree, bNode *node) +{ + BLI_assert(node->type == CMP_NODE_CRYPTOMATTE_LEGACY); + NodeCryptomatte *n = static_cast<NodeCryptomatte *>(node->storage); + if (n->num_inputs < 2) { + return 0; + } + bNodeSocket *sock = static_cast<bNodeSocket *>(node->inputs.last); + nodeRemoveSocket(ntree, node, sock); + n->num_inputs--; + return 1; +} + +void register_node_type_cmp_cryptomatte_legacy(void) +{ + static bNodeType ntype; + + cmp_node_type_base(&ntype, CMP_NODE_CRYPTOMATTE_LEGACY, "Cryptomatte", NODE_CLASS_MATTE, 0); + node_type_socket_templates(&ntype, nullptr, cmp_node_cryptomatte_out); + node_type_init(&ntype, node_init_cryptomatte_legacy); node_type_storage(&ntype, "NodeCryptomatte", node_free_cryptomatte, node_copy_cryptomatte); nodeRegisterType(&ntype); } + +/** \} */ } |