diff options
Diffstat (limited to 'source/blender/compositor')
-rw-r--r-- | source/blender/compositor/intern/COM_Converter.cc | 3 | ||||
-rw-r--r-- | source/blender/compositor/nodes/COM_CryptomatteNode.cc | 255 | ||||
-rw-r--r-- | source/blender/compositor/nodes/COM_CryptomatteNode.h | 62 |
3 files changed, 282 insertions, 38 deletions
diff --git a/source/blender/compositor/intern/COM_Converter.cc b/source/blender/compositor/intern/COM_Converter.cc index 7d897d29576..91439f54710 100644 --- a/source/blender/compositor/intern/COM_Converter.cc +++ b/source/blender/compositor/intern/COM_Converter.cc @@ -406,6 +406,9 @@ Node *COM_convert_bnode(bNode *b_node) case CMP_NODE_SUNBEAMS: node = new SunBeamsNode(b_node); break; + case CMP_NODE_CRYPTOMATTE_LEGACY: + node = new CryptomatteLegacyNode(b_node); + break; case CMP_NODE_CRYPTOMATTE: node = new CryptomatteNode(b_node); break; diff --git a/source/blender/compositor/nodes/COM_CryptomatteNode.cc b/source/blender/compositor/nodes/COM_CryptomatteNode.cc index 27ef98af8f3..4c698b5609f 100644 --- a/source/blender/compositor/nodes/COM_CryptomatteNode.cc +++ b/source/blender/compositor/nodes/COM_CryptomatteNode.cc @@ -17,64 +17,247 @@ */ #include "COM_CryptomatteNode.h" -#include "COM_ConvertOperation.h" -#include "COM_CryptomatteOperation.h" - +#include "BKE_node.h" #include "BLI_assert.h" #include "BLI_hash_mm3.h" #include "BLI_listbase.h" #include "BLI_string.h" - +#include "COM_ConvertOperation.h" +#include "COM_CryptomatteOperation.h" +#include "COM_MultilayerImageOperation.h" +#include "COM_RenderLayersProg.h" #include "COM_SetAlphaMultiplyOperation.h" +#include "COM_SetColorOperation.h" #include <iterator> +#include <string> + +/** \name Cryptomatte base + * \{ */ -CryptomatteNode::CryptomatteNode(bNode *editorNode) : Node(editorNode) +void CryptomatteBaseNode::convertToOperations(NodeConverter &converter, + const CompositorContext &context) const { - /* pass */ + NodeOutput *output_image_socket = this->getOutputSocket(0); + + bNode *node = this->getbNode(); + NodeCryptomatte *cryptomatte_settings = static_cast<NodeCryptomatte *>(node->storage); + + CryptomatteOperation *cryptomatte_operation = create_cryptomatte_operation( + converter, context, *node, cryptomatte_settings); + converter.addOperation(cryptomatte_operation); + + NodeOutput *output_matte_socket = this->getOutputSocket(1); + SeparateChannelOperation *extract_mask_operation = new SeparateChannelOperation; + extract_mask_operation->setChannel(3); + converter.addOperation(extract_mask_operation); + converter.addLink(cryptomatte_operation->getOutputSocket(0), + extract_mask_operation->getInputSocket(0)); + converter.mapOutputSocket(output_matte_socket, extract_mask_operation->getOutputSocket(0)); + + NodeInput *input_image_socket = this->getInputSocket(0); + SetAlphaMultiplyOperation *apply_mask_operation = new SetAlphaMultiplyOperation(); + converter.mapInputSocket(input_image_socket, apply_mask_operation->getInputSocket(0)); + converter.addOperation(apply_mask_operation); + converter.addLink(extract_mask_operation->getOutputSocket(0), + apply_mask_operation->getInputSocket(1)); + converter.mapOutputSocket(output_image_socket, apply_mask_operation->getOutputSocket(0)); + + NodeOutput *output_pick_socket = this->getOutputSocket(2); + SetAlphaMultiplyOperation *extract_pick_operation = new SetAlphaMultiplyOperation(); + converter.addOperation(extract_pick_operation); + converter.addInputValue(extract_pick_operation->getInputSocket(1), 1.0f); + converter.addLink(cryptomatte_operation->getOutputSocket(0), + extract_pick_operation->getInputSocket(0)); + converter.mapOutputSocket(output_pick_socket, extract_pick_operation->getOutputSocket(0)); } -void CryptomatteNode::convertToOperations(NodeConverter &converter, - const CompositorContext & /*context*/) const +/* \} */ + +/** \name Cryptomatte V2 + * \{ */ +static std::string prefix_from_node(const bNode &node) { - NodeInput *inputSocketImage = this->getInputSocket(0); - NodeOutput *outputSocketImage = this->getOutputSocket(0); - NodeOutput *outputSocketMatte = this->getOutputSocket(1); - NodeOutput *outputSocketPick = this->getOutputSocket(2); + char prefix[MAX_NAME]; + ntreeCompositCryptomatteLayerPrefix(&node, prefix, sizeof(prefix)); + return std::string(prefix, BLI_strnlen(prefix, sizeof(prefix))); +} - bNode *node = this->getbNode(); - NodeCryptomatte *cryptoMatteSettings = (NodeCryptomatte *)node->storage; +static std::string combined_layer_pass_name(RenderLayer *render_layer, RenderPass *render_pass) +{ + if (render_layer->name[0] == '\0') { + return std::string(render_pass->name, + BLI_strnlen(render_pass->name, sizeof(render_pass->name))); + } - CryptomatteOperation *operation = new CryptomatteOperation(getNumberOfInputSockets() - 1); - if (cryptoMatteSettings) { - LISTBASE_FOREACH (CryptomatteEntry *, cryptomatte_entry, &cryptoMatteSettings->entries) { - operation->addObjectIndex(cryptomatte_entry->encoded_hash); + std::string combined_name = + blender::StringRef(render_layer->name, + BLI_strnlen(render_layer->name, sizeof(render_layer->name))) + + "." + + blender::StringRef(render_pass->name, + BLI_strnlen(render_pass->name, sizeof(render_pass->name))); + return combined_name; +} + +void CryptomatteNode::input_operations_from_render_source( + const CompositorContext &context, + const bNode &node, + blender::Vector<NodeOperation *> &r_input_operations) +{ + Scene *scene = (Scene *)node.id; + if (!scene) { + return; + } + + BLI_assert(GS(scene->id.name) == ID_SCE); + Render *render = RE_GetSceneRender(scene); + RenderResult *render_result = render ? RE_AcquireResultRead(render) : nullptr; + + if (!render_result) { + return; + } + + const short cryptomatte_layer_id = 0; + const std::string prefix = prefix_from_node(node); + LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) { + RenderLayer *render_layer = RE_GetRenderLayer(render_result, view_layer->name); + if (render_layer) { + LISTBASE_FOREACH (RenderPass *, render_pass, &render_layer->passes) { + const std::string combined_name = combined_layer_pass_name(render_layer, render_pass); + if (blender::StringRef(combined_name).startswith(prefix)) { + RenderLayersProg *op = new RenderLayersProg( + render_pass->name, COM_DT_COLOR, render_pass->channels); + op->setScene(scene); + op->setLayerId(cryptomatte_layer_id); + op->setRenderData(context.getRenderData()); + op->setViewName(context.getViewName()); + r_input_operations.append(op); + } + } } } + RE_ReleaseResult(render); +} - converter.addOperation(operation); +void CryptomatteNode::input_operations_from_image_source( + const CompositorContext &context, + const bNode &node, + blender::Vector<NodeOperation *> &r_input_operations) +{ + NodeCryptomatte *cryptomatte_settings = (NodeCryptomatte *)node.storage; + Image *image = (Image *)node.id; + if (!image) { + return; + } - for (int i = 0; i < getNumberOfInputSockets() - 1; i++) { - converter.mapInputSocket(this->getInputSocket(i + 1), operation->getInputSocket(i)); + BLI_assert(GS(image->id.name) == ID_IM); + if (image->type != IMA_TYPE_MULTILAYER) { + return; } - SeparateChannelOperation *separateOperation = new SeparateChannelOperation; - separateOperation->setChannel(3); - converter.addOperation(separateOperation); + ImageUser *iuser = &cryptomatte_settings->iuser; + BKE_image_user_frame_calc(image, iuser, context.getFramenumber()); + ImBuf *ibuf = BKE_image_acquire_ibuf(image, iuser, nullptr); - SetAlphaMultiplyOperation *operationAlpha = new SetAlphaMultiplyOperation(); - converter.addOperation(operationAlpha); + if (image->rr) { + int view = 0; + if (BLI_listbase_count_at_most(&image->rr->views, 2) > 1) { + if (iuser->view == 0) { + /* Heuristic to match image name with scene names, check if the view name exists in the + * image. */ + view = BLI_findstringindex( + &image->rr->views, context.getViewName(), offsetof(RenderView, name)); + if (view == -1) { + view = 0; + } + } + else { + view = iuser->view - 1; + } + } - converter.addLink(operation->getOutputSocket(0), separateOperation->getInputSocket(0)); - converter.addLink(separateOperation->getOutputSocket(0), operationAlpha->getInputSocket(1)); + const std::string prefix = prefix_from_node(node); + LISTBASE_FOREACH (RenderLayer *, render_layer, &image->rr->layers) { + LISTBASE_FOREACH (RenderPass *, render_pass, &render_layer->passes) { + const std::string combined_name = combined_layer_pass_name(render_layer, render_pass); + if (blender::StringRef(combined_name).startswith(prefix)) { + MultilayerColorOperation *op = new MultilayerColorOperation( + render_layer, render_pass, view); + op->setImage(image); + op->setImageUser(iuser); + op->setFramenumber(context.getFramenumber()); + r_input_operations.append(op); + } + } + } + } + BKE_image_release_ibuf(image, ibuf, nullptr); +} - SetAlphaMultiplyOperation *clearAlphaOperation = new SetAlphaMultiplyOperation(); - converter.addOperation(clearAlphaOperation); - converter.addInputValue(clearAlphaOperation->getInputSocket(1), 1.0f); +blender::Vector<NodeOperation *> CryptomatteNode::create_input_operations( + const CompositorContext &context, const bNode &node) +{ + blender::Vector<NodeOperation *> input_operations; + switch (node.custom1) { + case CMP_CRYPTOMATTE_SRC_RENDER: + input_operations_from_render_source(context, node, input_operations); + break; + case CMP_CRYPTOMATTE_SRC_IMAGE: + input_operations_from_image_source(context, node, input_operations); + break; + } - converter.addLink(operation->getOutputSocket(0), clearAlphaOperation->getInputSocket(0)); + if (input_operations.is_empty()) { + SetColorOperation *op = new SetColorOperation(); + op->setChannel1(0.0f); + op->setChannel2(1.0f); + op->setChannel3(0.0f); + op->setChannel4(0.0f); + input_operations.append(op); + } + return input_operations; +} +CryptomatteOperation *CryptomatteNode::create_cryptomatte_operation( + NodeConverter &converter, + const CompositorContext &context, + const bNode &node, + const NodeCryptomatte *cryptomatte_settings) const +{ + blender::Vector<NodeOperation *> input_operations = create_input_operations(context, node); + CryptomatteOperation *operation = new CryptomatteOperation(input_operations.size()); + LISTBASE_FOREACH (CryptomatteEntry *, cryptomatte_entry, &cryptomatte_settings->entries) { + operation->addObjectIndex(cryptomatte_entry->encoded_hash); + } + for (int i = 0; i < input_operations.size(); ++i) { + converter.addOperation(input_operations[i]); + converter.addLink(input_operations[i]->getOutputSocket(), operation->getInputSocket(i)); + } + return operation; +} + +/* \} */ + +/** \name Cryptomatte legacy + * \{ */ - converter.mapInputSocket(inputSocketImage, operationAlpha->getInputSocket(0)); - converter.mapOutputSocket(outputSocketMatte, separateOperation->getOutputSocket(0)); - converter.mapOutputSocket(outputSocketImage, operationAlpha->getOutputSocket(0)); - converter.mapOutputSocket(outputSocketPick, clearAlphaOperation->getOutputSocket(0)); +CryptomatteOperation *CryptomatteLegacyNode::create_cryptomatte_operation( + NodeConverter &converter, + const CompositorContext &UNUSED(context), + const bNode &UNUSED(node), + const NodeCryptomatte *cryptomatte_settings) const +{ + const int num_inputs = getNumberOfInputSockets() - 1; + CryptomatteOperation *operation = new CryptomatteOperation(num_inputs); + if (cryptomatte_settings) { + LISTBASE_FOREACH (CryptomatteEntry *, cryptomatte_entry, &cryptomatte_settings->entries) { + operation->addObjectIndex(cryptomatte_entry->encoded_hash); + } + } + + for (int i = 0; i < num_inputs; i++) { + converter.mapInputSocket(this->getInputSocket(i + 1), operation->getInputSocket(i)); + } + + return operation; } + +/* \} */
\ No newline at end of file diff --git a/source/blender/compositor/nodes/COM_CryptomatteNode.h b/source/blender/compositor/nodes/COM_CryptomatteNode.h index 1fb8893efa0..e99a104c914 100644 --- a/source/blender/compositor/nodes/COM_CryptomatteNode.h +++ b/source/blender/compositor/nodes/COM_CryptomatteNode.h @@ -18,14 +18,72 @@ #pragma once +#include "BLI_string_ref.hh" +#include "BLI_vector.hh" + +#include "COM_CryptomatteOperation.h" #include "COM_Node.h" /** * \brief CryptomatteNode * \ingroup Node */ -class CryptomatteNode : public Node { +class CryptomatteBaseNode : public Node { + protected: + CryptomatteBaseNode(bNode *editor_node) : Node(editor_node) + { + /* pass */ + } + public: - CryptomatteNode(bNode *editorNode); void convertToOperations(NodeConverter &converter, const CompositorContext &context) const; + + protected: + virtual CryptomatteOperation *create_cryptomatte_operation( + NodeConverter &converter, + const CompositorContext &context, + const bNode &node, + const NodeCryptomatte *cryptomatte_settings) const = 0; +}; + +class CryptomatteNode : public CryptomatteBaseNode { + public: + CryptomatteNode(bNode *editor_node) : CryptomatteBaseNode(editor_node) + { + /* pass */ + } + + protected: + CryptomatteOperation *create_cryptomatte_operation( + NodeConverter &converter, + const CompositorContext &context, + const bNode &node, + const NodeCryptomatte *cryptomatte_settings) const override; + + private: + static blender::Vector<NodeOperation *> create_input_operations(const CompositorContext &context, + const bNode &node); + static void input_operations_from_render_source( + const CompositorContext &context, + const bNode &node, + blender::Vector<NodeOperation *> &r_input_operations); + static void input_operations_from_image_source( + const CompositorContext &context, + const bNode &node, + blender::Vector<NodeOperation *> &r_input_operations); +}; + +class CryptomatteLegacyNode : public CryptomatteBaseNode { + public: + CryptomatteLegacyNode(bNode *editor_node) : CryptomatteBaseNode(editor_node) + { + /* pass */ + } + + protected: + CryptomatteOperation *create_cryptomatte_operation( + NodeConverter &converter, + const CompositorContext &context, + const bNode &node, + const NodeCryptomatte *cryptomatte_settings) const override; }; |