diff options
author | Omar Emara <mail@OmarEmara.dev> | 2022-08-10 11:21:18 +0300 |
---|---|---|
committer | Omar Emara <mail@OmarEmara.dev> | 2022-08-10 11:21:18 +0300 |
commit | c014021802c323c3ed55c3c283717975a3d93edf (patch) | |
tree | a2537ce8187e6acff56b3936d994ab73447b3ad0 /source/blender/nodes | |
parent | b5df7a02ac754de8e04fdeda4d1c3f0fcdf6a7a2 (diff) |
Realtime Compositor: Add basic matte nodes
This patch implements the following nodes for the realtime compositor:
- Box mask node.
- Channel matte node.
- Chroma matte node.
- Color matte node.
- Color spill node.
- Difference matte node.
- Distance matte node.
- Ellipse matte node.
- Luminance matte node.
Differential Revision: https://developer.blender.org/D15230
Reviewed By: Clement Foucault
Diffstat (limited to 'source/blender/nodes')
9 files changed, 724 insertions, 15 deletions
diff --git a/source/blender/nodes/composite/nodes/node_composite_boxmask.cc b/source/blender/nodes/composite/nodes/node_composite_boxmask.cc index f39b69c63f2..9c7bb6432cb 100644 --- a/source/blender/nodes/composite/nodes/node_composite_boxmask.cc +++ b/source/blender/nodes/composite/nodes/node_composite_boxmask.cc @@ -5,9 +5,18 @@ * \ingroup cmpnodes */ +#include <cmath> + +#include "BLI_math_vec_types.hh" + #include "UI_interface.h" #include "UI_resources.h" +#include "GPU_shader.h" + +#include "COM_node_operation.hh" +#include "COM_utilities.hh" + #include "node_composite_util.hh" /* **************** SCALAR MATH ******************** */ @@ -48,6 +57,98 @@ static void node_composit_buts_boxmask(uiLayout *layout, bContext *UNUSED(C), Po uiItemR(layout, ptr, "mask_type", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); } +using namespace blender::realtime_compositor; + +class BoxMaskOperation : public NodeOperation { + public: + using NodeOperation::NodeOperation; + + void execute() override + { + GPUShader *shader = shader_manager().get(get_shader_name()); + GPU_shader_bind(shader); + + const Domain domain = compute_domain(); + + GPU_shader_uniform_2iv(shader, "domain_size", domain.size); + + GPU_shader_uniform_2fv(shader, "location", get_location()); + GPU_shader_uniform_2fv(shader, "size", get_size() / 2.0f); + GPU_shader_uniform_1f(shader, "cos_angle", std::cos(get_angle())); + GPU_shader_uniform_1f(shader, "sin_angle", std::sin(get_angle())); + + const Result &input_mask = get_input("Mask"); + input_mask.bind_as_texture(shader, "base_mask_tx"); + + const Result &value = get_input("Value"); + value.bind_as_texture(shader, "mask_value_tx"); + + Result &output_mask = get_result("Mask"); + output_mask.allocate_texture(domain); + output_mask.bind_as_image(shader, "output_mask_img"); + + compute_dispatch_threads_at_least(shader, domain.size); + + input_mask.unbind_as_texture(); + value.unbind_as_texture(); + output_mask.unbind_as_image(); + GPU_shader_unbind(); + } + + Domain compute_domain() override + { + if (get_input("Mask").is_single_value()) { + return Domain(context().get_output_size()); + } + return get_input("Mask").domain(); + } + + CMPNodeMaskType get_mask_type() + { + return (CMPNodeMaskType)bnode().custom1; + } + + const char *get_shader_name() + { + switch (get_mask_type()) { + default: + case CMP_NODE_MASKTYPE_ADD: + return "compositor_box_mask_add"; + case CMP_NODE_MASKTYPE_SUBTRACT: + return "compositor_box_mask_subtract"; + case CMP_NODE_MASKTYPE_MULTIPLY: + return "compositor_box_mask_multiply"; + case CMP_NODE_MASKTYPE_NOT: + return "compositor_box_mask_not"; + } + } + + NodeBoxMask &get_node_box_mask() + { + return *static_cast<NodeBoxMask *>(bnode().storage); + } + + float2 get_location() + { + return float2(get_node_box_mask().x, get_node_box_mask().y); + } + + float2 get_size() + { + return float2(get_node_box_mask().width, get_node_box_mask().height); + } + + float get_angle() + { + return get_node_box_mask().rotation; + } +}; + +static NodeOperation *get_compositor_operation(Context &context, DNode node) +{ + return new BoxMaskOperation(context, node); +} + } // namespace blender::nodes::node_composite_boxmask_cc void register_node_type_cmp_boxmask() @@ -61,6 +162,7 @@ void register_node_type_cmp_boxmask() ntype.draw_buttons = file_ns::node_composit_buts_boxmask; node_type_init(&ntype, file_ns::node_composit_init_boxmask); node_type_storage(&ntype, "NodeBoxMask", node_free_standard_storage, node_copy_standard_storage); + ntype.get_compositor_operation = file_ns::get_compositor_operation; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/composite/nodes/node_composite_channel_matte.cc b/source/blender/nodes/composite/nodes/node_composite_channel_matte.cc index 627f07fdfce..e899f7eb100 100644 --- a/source/blender/nodes/composite/nodes/node_composite_channel_matte.cc +++ b/source/blender/nodes/composite/nodes/node_composite_channel_matte.cc @@ -10,6 +10,10 @@ #include "UI_interface.h" #include "UI_resources.h" +#include "GPU_material.h" + +#include "COM_shader_node.hh" + #include "node_composite_util.hh" /* ******************* Channel Matte Node ********************************* */ @@ -18,7 +22,9 @@ namespace blender::nodes::node_composite_channel_matte_cc { static void cmp_node_channel_matte_declare(NodeDeclarationBuilder &b) { - b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f}); + b.add_input<decl::Color>(N_("Image")) + .default_value({1.0f, 1.0f, 1.0f, 1.0f}) + .compositor_domain_priority(0); b.add_output<decl::Color>(N_("Image")); b.add_output<decl::Float>(N_("Matte")); } @@ -79,6 +85,96 @@ static void node_composit_buts_channel_matte(uiLayout *layout, col, ptr, "limit_min", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); } +using namespace blender::realtime_compositor; + +class ChannelMatteShaderNode : public ShaderNode { + public: + using ShaderNode::ShaderNode; + + void compile(GPUMaterial *material) override + { + GPUNodeStack *inputs = get_inputs_array(); + GPUNodeStack *outputs = get_outputs_array(); + + const float color_space = get_color_space(); + const float matte_channel = get_matte_channel(); + float limit_channels[2]; + get_limit_channels(limit_channels); + const float max_limit = get_max_limit(); + const float min_limit = get_min_limit(); + + GPU_stack_link(material, + &bnode(), + "node_composite_channel_matte", + inputs, + outputs, + GPU_constant(&color_space), + GPU_constant(&matte_channel), + GPU_constant(limit_channels), + GPU_uniform(&max_limit), + GPU_uniform(&min_limit)); + } + + /* 1 -> CMP_NODE_CHANNEL_MATTE_CS_RGB + * 2 -> CMP_NODE_CHANNEL_MATTE_CS_HSV + * 3 -> CMP_NODE_CHANNEL_MATTE_CS_YUV + * 4 -> CMP_NODE_CHANNEL_MATTE_CS_YCC */ + int get_color_space() + { + return bnode().custom1; + } + + /* Get the index of the channel used to generate the matte. */ + int get_matte_channel() + { + return bnode().custom2 - 1; + } + + NodeChroma *get_node_chroma() + { + return static_cast<NodeChroma *>(bnode().storage); + } + + /* Get the index of the channel used to compute the limit value. */ + int get_limit_channel() + { + return get_node_chroma()->channel - 1; + } + + /* Get the indices of the channels used to compute the limit value. We always assume the limit + * algorithm is Max, if it is a single limit channel, store it in both limit channels, because + * the maximum of two identical values is is the same value. */ + void get_limit_channels(float limit_channels[2]) + { + if (get_node_chroma()->algorithm == CMP_NODE_CHANNEL_MATTE_LIMIT_ALGORITHM_MAX) { + /* If the algorithm is Max, store the indices of the other two channels other than the matte + * channel. */ + limit_channels[0] = (get_matte_channel() + 1) % 3; + limit_channels[1] = (get_matte_channel() + 2) % 3; + } + else { + /* If the algorithm is Single, store the index of the limit channel in both channels. */ + limit_channels[0] = get_limit_channel(); + limit_channels[1] = get_limit_channel(); + } + } + + float get_max_limit() + { + return get_node_chroma()->t1; + } + + float get_min_limit() + { + return get_node_chroma()->t2; + } +}; + +static ShaderNode *get_compositor_shader_node(DNode node) +{ + return new ChannelMatteShaderNode(node); +} + } // namespace blender::nodes::node_composite_channel_matte_cc void register_node_type_cmp_channel_matte() @@ -93,6 +189,7 @@ void register_node_type_cmp_channel_matte() ntype.flag |= NODE_PREVIEW; node_type_init(&ntype, file_ns::node_composit_init_channel_matte); node_type_storage(&ntype, "NodeChroma", node_free_standard_storage, node_copy_standard_storage); + ntype.get_compositor_shader_node = file_ns::get_compositor_shader_node; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/composite/nodes/node_composite_chroma_matte.cc b/source/blender/nodes/composite/nodes/node_composite_chroma_matte.cc index 69319c6825d..9dcd4213949 100644 --- a/source/blender/nodes/composite/nodes/node_composite_chroma_matte.cc +++ b/source/blender/nodes/composite/nodes/node_composite_chroma_matte.cc @@ -5,11 +5,15 @@ * \ingroup cmpnodes */ -#include "BLI_math_rotation.h" +#include <cmath> #include "UI_interface.h" #include "UI_resources.h" +#include "GPU_material.h" + +#include "COM_shader_node.hh" + #include "node_composite_util.hh" /* ******************* Chroma Key ********************************************************** */ @@ -18,8 +22,12 @@ namespace blender::nodes::node_composite_chroma_matte_cc { static void cmp_node_chroma_matte_declare(NodeDeclarationBuilder &b) { - b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f}); - b.add_input<decl::Color>(N_("Key Color")).default_value({1.0f, 1.0f, 1.0f, 1.0f}); + b.add_input<decl::Color>(N_("Image")) + .default_value({1.0f, 1.0f, 1.0f, 1.0f}) + .compositor_domain_priority(0); + b.add_input<decl::Color>(N_("Key Color")) + .default_value({1.0f, 1.0f, 1.0f, 1.0f}) + .compositor_domain_priority(1); b.add_output<decl::Color>(N_("Image")); b.add_output<decl::Float>(N_("Matte")); } @@ -51,6 +59,57 @@ static void node_composit_buts_chroma_matte(uiLayout *layout, bContext *UNUSED(C // uiItemR(col, ptr, "shadow_adjust", UI_ITEM_R_SLIDER, nullptr, ICON_NONE); } +using namespace blender::realtime_compositor; + +class ChromaMatteShaderNode : public ShaderNode { + public: + using ShaderNode::ShaderNode; + + void compile(GPUMaterial *material) override + { + GPUNodeStack *inputs = get_inputs_array(); + GPUNodeStack *outputs = get_outputs_array(); + + const float acceptance = get_acceptance(); + const float cutoff = get_cutoff(); + const float falloff = get_falloff(); + + GPU_stack_link(material, + &bnode(), + "node_composite_chroma_matte", + inputs, + outputs, + GPU_uniform(&acceptance), + GPU_uniform(&cutoff), + GPU_uniform(&falloff)); + } + + NodeChroma *get_node_chroma() + { + return static_cast<NodeChroma *>(bnode().storage); + } + + float get_acceptance() + { + return std::tan(get_node_chroma()->t1) / 2.0f; + } + + float get_cutoff() + { + return get_node_chroma()->t2; + } + + float get_falloff() + { + return get_node_chroma()->fstrength; + } +}; + +static ShaderNode *get_compositor_shader_node(DNode node) +{ + return new ChromaMatteShaderNode(node); +} + } // namespace blender::nodes::node_composite_chroma_matte_cc void register_node_type_cmp_chroma_matte() @@ -65,6 +124,7 @@ void register_node_type_cmp_chroma_matte() ntype.flag |= NODE_PREVIEW; node_type_init(&ntype, file_ns::node_composit_init_chroma_matte); node_type_storage(&ntype, "NodeChroma", node_free_standard_storage, node_copy_standard_storage); + ntype.get_compositor_shader_node = file_ns::get_compositor_shader_node; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/composite/nodes/node_composite_color_matte.cc b/source/blender/nodes/composite/nodes/node_composite_color_matte.cc index 474fb1b72f2..5e3aaf512e6 100644 --- a/source/blender/nodes/composite/nodes/node_composite_color_matte.cc +++ b/source/blender/nodes/composite/nodes/node_composite_color_matte.cc @@ -8,6 +8,10 @@ #include "UI_interface.h" #include "UI_resources.h" +#include "GPU_material.h" + +#include "COM_shader_node.hh" + #include "node_composite_util.hh" /* ******************* Color Matte ********************************************************** */ @@ -16,8 +20,12 @@ namespace blender::nodes::node_composite_color_matte_cc { static void cmp_node_color_matte_declare(NodeDeclarationBuilder &b) { - b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f}); - b.add_input<decl::Color>(N_("Key Color")).default_value({1.0f, 1.0f, 1.0f, 1.0f}); + b.add_input<decl::Color>(N_("Image")) + .default_value({1.0f, 1.0f, 1.0f, 1.0f}) + .compositor_domain_priority(0); + b.add_input<decl::Color>(N_("Key Color")) + .default_value({1.0f, 1.0f, 1.0f, 1.0f}) + .compositor_domain_priority(1); b.add_output<decl::Color>(N_("Image")); b.add_output<decl::Float>(N_("Matte")); } @@ -50,6 +58,58 @@ static void node_composit_buts_color_matte(uiLayout *layout, bContext *UNUSED(C) col, ptr, "color_value", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); } +using namespace blender::realtime_compositor; + +class ColorMatteShaderNode : public ShaderNode { + public: + using ShaderNode::ShaderNode; + + void compile(GPUMaterial *material) override + { + GPUNodeStack *inputs = get_inputs_array(); + GPUNodeStack *outputs = get_outputs_array(); + + const float hue_epsilon = get_hue_epsilon(); + const float saturation_epsilon = get_saturation_epsilon(); + const float value_epsilon = get_value_epsilon(); + + GPU_stack_link(material, + &bnode(), + "node_composite_color_matte", + inputs, + outputs, + GPU_uniform(&hue_epsilon), + GPU_uniform(&saturation_epsilon), + GPU_uniform(&value_epsilon)); + } + + NodeChroma *get_node_chroma() + { + return static_cast<NodeChroma *>(bnode().storage); + } + + float get_hue_epsilon() + { + /* Divide by 2 because the hue wraps around. */ + return get_node_chroma()->t1 / 2.0f; + } + + float get_saturation_epsilon() + { + return get_node_chroma()->t2; + } + + float get_value_epsilon() + { + return get_node_chroma()->t3; + } +}; + +static ShaderNode *get_compositor_shader_node(DNode node) +{ + return new ColorMatteShaderNode(node); +} + } // namespace blender::nodes::node_composite_color_matte_cc void register_node_type_cmp_color_matte() @@ -64,6 +124,7 @@ void register_node_type_cmp_color_matte() ntype.flag |= NODE_PREVIEW; node_type_init(&ntype, file_ns::node_composit_init_color_matte); node_type_storage(&ntype, "NodeChroma", node_free_standard_storage, node_copy_standard_storage); + ntype.get_compositor_shader_node = file_ns::get_compositor_shader_node; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/composite/nodes/node_composite_color_spill.cc b/source/blender/nodes/composite/nodes/node_composite_color_spill.cc index 9ad5dfbaeb2..9744c01a256 100644 --- a/source/blender/nodes/composite/nodes/node_composite_color_spill.cc +++ b/source/blender/nodes/composite/nodes/node_composite_color_spill.cc @@ -10,6 +10,10 @@ #include "UI_interface.h" #include "UI_resources.h" +#include "GPU_material.h" + +#include "COM_shader_node.hh" + #include "node_composite_util.hh" /* ******************* Color Spill Suppression ********************************* */ @@ -18,8 +22,15 @@ namespace blender::nodes::node_composite_color_spill_cc { static void cmp_node_color_spill_declare(NodeDeclarationBuilder &b) { - b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f}); - b.add_input<decl::Float>(N_("Fac")).default_value(1.0f).min(0.0f).max(1.0f).subtype(PROP_FACTOR); + b.add_input<decl::Color>(N_("Image")) + .default_value({1.0f, 1.0f, 1.0f, 1.0f}) + .compositor_domain_priority(0); + b.add_input<decl::Float>(N_("Fac")) + .default_value(1.0f) + .min(0.0f) + .max(1.0f) + .subtype(PROP_FACTOR) + .compositor_domain_priority(1); b.add_output<decl::Color>(N_("Image")); } @@ -27,8 +38,8 @@ static void node_composit_init_color_spill(bNodeTree *UNUSED(ntree), bNode *node { NodeColorspill *ncs = MEM_cnew<NodeColorspill>(__func__); node->storage = ncs; + node->custom2 = CMP_NODE_COLOR_SPILL_LIMIT_ALGORITHM_SINGLE; node->custom1 = 2; /* green channel */ - node->custom2 = 0; /* simple limit algorithm */ ncs->limchan = 0; /* limit by red */ ncs->limscale = 1.0f; /* limit scaling factor */ ncs->unspill = 0; /* do not use unspill */ @@ -80,6 +91,103 @@ static void node_composit_buts_color_spill(uiLayout *layout, bContext *UNUSED(C) } } +using namespace blender::realtime_compositor; + +class ColorSpillShaderNode : public ShaderNode { + public: + using ShaderNode::ShaderNode; + + void compile(GPUMaterial *material) override + { + GPUNodeStack *inputs = get_inputs_array(); + GPUNodeStack *outputs = get_outputs_array(); + + const float spill_channel = get_spill_channel(); + float spill_scale[3]; + get_spill_scale(spill_scale); + float limit_channels[2]; + get_limit_channels(limit_channels); + const float limit_scale = get_limit_scale(); + + GPU_stack_link(material, + &bnode(), + "node_composite_color_spill", + inputs, + outputs, + GPU_constant(&spill_channel), + GPU_uniform(spill_scale), + GPU_constant(limit_channels), + GPU_uniform(&limit_scale)); + } + + /* Get the index of the channel used for spilling. */ + int get_spill_channel() + { + return bnode().custom1 - 1; + } + + CMPNodeColorSpillLimitAlgorithm get_limit_algorithm() + { + return (CMPNodeColorSpillLimitAlgorithm)bnode().custom2; + } + + NodeColorspill *get_node_color_spill() + { + return static_cast<NodeColorspill *>(bnode().storage); + } + + void get_spill_scale(float spill_scale[3]) + { + const NodeColorspill *node_color_spill = get_node_color_spill(); + if (node_color_spill->unspill) { + spill_scale[0] = node_color_spill->uspillr; + spill_scale[1] = node_color_spill->uspillg; + spill_scale[2] = node_color_spill->uspillb; + spill_scale[get_spill_channel()] *= -1.0f; + } + else { + spill_scale[0] = 0.0f; + spill_scale[1] = 0.0f; + spill_scale[2] = 0.0f; + spill_scale[get_spill_channel()] = -1.0f; + } + } + + /* Get the index of the channel used for limiting. */ + int get_limit_channel() + { + return get_node_color_spill()->limchan; + } + + /* Get the indices of the channels used to compute the limit value. We always assume the limit + * algorithm is Average, if it is a single limit channel, store it in both limit channels, + * because the average of two identical values is the same value. */ + void get_limit_channels(float limit_channels[2]) + { + if (get_limit_algorithm() == CMP_NODE_COLOR_SPILL_LIMIT_ALGORITHM_AVERAGE) { + /* If the algorithm is Average, store the indices of the other two channels other than the + * spill channel. */ + limit_channels[0] = (get_spill_channel() + 1) % 3; + limit_channels[1] = (get_spill_channel() + 2) % 3; + } + else { + /* If the algorithm is Single, store the index of the limit channel in both channels. */ + limit_channels[0] = get_limit_channel(); + limit_channels[1] = get_limit_channel(); + } + } + + float get_limit_scale() + { + return get_node_color_spill()->limscale; + } +}; + +static ShaderNode *get_compositor_shader_node(DNode node) +{ + return new ColorSpillShaderNode(node); +} + } // namespace blender::nodes::node_composite_color_spill_cc void register_node_type_cmp_color_spill() @@ -94,6 +202,7 @@ void register_node_type_cmp_color_spill() node_type_init(&ntype, file_ns::node_composit_init_color_spill); node_type_storage( &ntype, "NodeColorspill", node_free_standard_storage, node_copy_standard_storage); + ntype.get_compositor_shader_node = file_ns::get_compositor_shader_node; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/composite/nodes/node_composite_diff_matte.cc b/source/blender/nodes/composite/nodes/node_composite_diff_matte.cc index b87bbe439db..e129dcaa6ef 100644 --- a/source/blender/nodes/composite/nodes/node_composite_diff_matte.cc +++ b/source/blender/nodes/composite/nodes/node_composite_diff_matte.cc @@ -8,6 +8,10 @@ #include "UI_interface.h" #include "UI_resources.h" +#include "GPU_material.h" + +#include "COM_shader_node.hh" + #include "node_composite_util.hh" /* ******************* channel Difference Matte ********************************* */ @@ -16,8 +20,12 @@ namespace blender::nodes::node_composite_diff_matte_cc { static void cmp_node_diff_matte_declare(NodeDeclarationBuilder &b) { - b.add_input<decl::Color>(N_("Image 1")).default_value({1.0f, 1.0f, 1.0f, 1.0f}); - b.add_input<decl::Color>(N_("Image 2")).default_value({1.0f, 1.0f, 1.0f, 1.0f}); + b.add_input<decl::Color>(N_("Image 1")) + .default_value({1.0f, 1.0f, 1.0f, 1.0f}) + .compositor_domain_priority(0); + b.add_input<decl::Color>(N_("Image 2")) + .default_value({1.0f, 1.0f, 1.0f, 1.0f}) + .compositor_domain_priority(1); b.add_output<decl::Color>(N_("Image")); b.add_output<decl::Float>(N_("Matte")); } @@ -40,6 +48,50 @@ static void node_composit_buts_diff_matte(uiLayout *layout, bContext *UNUSED(C), uiItemR(col, ptr, "falloff", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); } +using namespace blender::realtime_compositor; + +class DifferenceMatteShaderNode : public ShaderNode { + public: + using ShaderNode::ShaderNode; + + void compile(GPUMaterial *material) override + { + GPUNodeStack *inputs = get_inputs_array(); + GPUNodeStack *outputs = get_outputs_array(); + + const float tolerance = get_tolerance(); + const float falloff = get_falloff(); + + GPU_stack_link(material, + &bnode(), + "node_composite_difference_matte", + inputs, + outputs, + GPU_uniform(&tolerance), + GPU_uniform(&falloff)); + } + + NodeChroma *get_node_chroma() + { + return static_cast<NodeChroma *>(bnode().storage); + } + + float get_tolerance() + { + return get_node_chroma()->t1; + } + + float get_falloff() + { + return get_node_chroma()->t2; + } +}; + +static ShaderNode *get_compositor_shader_node(DNode node) +{ + return new DifferenceMatteShaderNode(node); +} + } // namespace blender::nodes::node_composite_diff_matte_cc void register_node_type_cmp_diff_matte() @@ -54,6 +106,7 @@ void register_node_type_cmp_diff_matte() ntype.flag |= NODE_PREVIEW; node_type_init(&ntype, file_ns::node_composit_init_diff_matte); node_type_storage(&ntype, "NodeChroma", node_free_standard_storage, node_copy_standard_storage); + ntype.get_compositor_shader_node = file_ns::get_compositor_shader_node; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/composite/nodes/node_composite_distance_matte.cc b/source/blender/nodes/composite/nodes/node_composite_distance_matte.cc index a8646d8498e..9d910b3f409 100644 --- a/source/blender/nodes/composite/nodes/node_composite_distance_matte.cc +++ b/source/blender/nodes/composite/nodes/node_composite_distance_matte.cc @@ -8,6 +8,10 @@ #include "UI_interface.h" #include "UI_resources.h" +#include "GPU_material.h" + +#include "COM_shader_node.hh" + #include "node_composite_util.hh" /* ******************* channel Distance Matte ********************************* */ @@ -16,8 +20,12 @@ namespace blender::nodes::node_composite_distance_matte_cc { static void cmp_node_distance_matte_declare(NodeDeclarationBuilder &b) { - b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f}); - b.add_input<decl::Color>(N_("Key Color")).default_value({1.0f, 1.0f, 1.0f, 1.0f}); + b.add_input<decl::Color>(N_("Image")) + .default_value({1.0f, 1.0f, 1.0f, 1.0f}) + .compositor_domain_priority(0); + b.add_input<decl::Color>(N_("Key Color")) + .default_value({1.0f, 1.0f, 1.0f, 1.0f}) + .compositor_domain_priority(1); b.add_output<decl::Color>(N_("Image")); b.add_output<decl::Float>(N_("Matte")); } @@ -26,7 +34,7 @@ static void node_composit_init_distance_matte(bNodeTree *UNUSED(ntree), bNode *n { NodeChroma *c = MEM_cnew<NodeChroma>(__func__); node->storage = c; - c->channel = 1; + c->channel = CMP_NODE_DISTANCE_MATTE_COLOR_SPACE_RGBA; c->t1 = 0.1f; c->t2 = 0.1f; } @@ -48,6 +56,66 @@ static void node_composit_buts_distance_matte(uiLayout *layout, uiItemR(col, ptr, "falloff", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); } +using namespace blender::realtime_compositor; + +class DistanceMatteShaderNode : public ShaderNode { + public: + using ShaderNode::ShaderNode; + + void compile(GPUMaterial *material) override + { + GPUNodeStack *inputs = get_inputs_array(); + GPUNodeStack *outputs = get_outputs_array(); + + const float tolerance = get_tolerance(); + const float falloff = get_falloff(); + + if (get_color_space() == CMP_NODE_DISTANCE_MATTE_COLOR_SPACE_RGBA) { + GPU_stack_link(material, + &bnode(), + "node_composite_distance_matte_rgba", + inputs, + outputs, + GPU_uniform(&tolerance), + GPU_uniform(&falloff)); + return; + } + + GPU_stack_link(material, + &bnode(), + "node_composite_distance_matte_ycca", + inputs, + outputs, + GPU_uniform(&tolerance), + GPU_uniform(&falloff)); + } + + NodeChroma *get_node_chroma() + { + return static_cast<NodeChroma *>(bnode().storage); + } + + CMPNodeDistanceMatteColorSpace get_color_space() + { + return (CMPNodeDistanceMatteColorSpace)get_node_chroma()->channel; + } + + float get_tolerance() + { + return get_node_chroma()->t1; + } + + float get_falloff() + { + return get_node_chroma()->t2; + } +}; + +static ShaderNode *get_compositor_shader_node(DNode node) +{ + return new DistanceMatteShaderNode(node); +} + } // namespace blender::nodes::node_composite_distance_matte_cc void register_node_type_cmp_distance_matte() @@ -62,6 +130,7 @@ void register_node_type_cmp_distance_matte() ntype.flag |= NODE_PREVIEW; node_type_init(&ntype, file_ns::node_composit_init_distance_matte); node_type_storage(&ntype, "NodeChroma", node_free_standard_storage, node_copy_standard_storage); + ntype.get_compositor_shader_node = file_ns::get_compositor_shader_node; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/composite/nodes/node_composite_ellipsemask.cc b/source/blender/nodes/composite/nodes/node_composite_ellipsemask.cc index 4da6a0a442e..54dfa00eadd 100644 --- a/source/blender/nodes/composite/nodes/node_composite_ellipsemask.cc +++ b/source/blender/nodes/composite/nodes/node_composite_ellipsemask.cc @@ -5,9 +5,18 @@ * \ingroup cmpnodes */ +#include <cmath> + +#include "BLI_math_vec_types.hh" + #include "UI_interface.h" #include "UI_resources.h" +#include "GPU_shader.h" + +#include "COM_node_operation.hh" +#include "COM_utilities.hh" + #include "node_composite_util.hh" /* **************** SCALAR MATH ******************** */ @@ -46,6 +55,98 @@ static void node_composit_buts_ellipsemask(uiLayout *layout, bContext *UNUSED(C) uiItemR(layout, ptr, "mask_type", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); } +using namespace blender::realtime_compositor; + +class EllipseMaskOperation : public NodeOperation { + public: + using NodeOperation::NodeOperation; + + void execute() override + { + GPUShader *shader = shader_manager().get(get_shader_name()); + GPU_shader_bind(shader); + + const Domain domain = compute_domain(); + + GPU_shader_uniform_2iv(shader, "domain_size", domain.size); + + GPU_shader_uniform_2fv(shader, "location", get_location()); + GPU_shader_uniform_2fv(shader, "radius", get_size() / 2.0f); + GPU_shader_uniform_1f(shader, "cos_angle", std::cos(get_angle())); + GPU_shader_uniform_1f(shader, "sin_angle", std::sin(get_angle())); + + const Result &input_mask = get_input("Mask"); + input_mask.bind_as_texture(shader, "base_mask_tx"); + + const Result &value = get_input("Value"); + value.bind_as_texture(shader, "mask_value_tx"); + + Result &output_mask = get_result("Mask"); + output_mask.allocate_texture(domain); + output_mask.bind_as_image(shader, "output_mask_img"); + + compute_dispatch_threads_at_least(shader, domain.size); + + input_mask.unbind_as_texture(); + value.unbind_as_texture(); + output_mask.unbind_as_image(); + GPU_shader_unbind(); + } + + Domain compute_domain() override + { + if (get_input("Mask").is_single_value()) { + return Domain(context().get_output_size()); + } + return get_input("Mask").domain(); + } + + CMPNodeMaskType get_mask_type() + { + return (CMPNodeMaskType)bnode().custom1; + } + + const char *get_shader_name() + { + switch (get_mask_type()) { + default: + case CMP_NODE_MASKTYPE_ADD: + return "compositor_ellipse_mask_add"; + case CMP_NODE_MASKTYPE_SUBTRACT: + return "compositor_ellipse_mask_subtract"; + case CMP_NODE_MASKTYPE_MULTIPLY: + return "compositor_ellipse_mask_multiply"; + case CMP_NODE_MASKTYPE_NOT: + return "compositor_ellipse_mask_not"; + } + } + + NodeEllipseMask &get_node_ellipse_mask() + { + return *static_cast<NodeEllipseMask *>(bnode().storage); + } + + float2 get_location() + { + return float2(get_node_ellipse_mask().x, get_node_ellipse_mask().y); + } + + float2 get_size() + { + return float2(get_node_ellipse_mask().width, get_node_ellipse_mask().height); + } + + float get_angle() + { + return get_node_ellipse_mask().rotation; + } +}; + +static NodeOperation *get_compositor_operation(Context &context, DNode node) +{ + return new EllipseMaskOperation(context, node); +} + } // namespace blender::nodes::node_composite_ellipsemask_cc void register_node_type_cmp_ellipsemask() @@ -61,6 +162,7 @@ void register_node_type_cmp_ellipsemask() node_type_init(&ntype, file_ns::node_composit_init_ellipsemask); node_type_storage( &ntype, "NodeEllipseMask", node_free_standard_storage, node_copy_standard_storage); + ntype.get_compositor_operation = file_ns::get_compositor_operation; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/composite/nodes/node_composite_luma_matte.cc b/source/blender/nodes/composite/nodes/node_composite_luma_matte.cc index 94697a2aafd..092a12a7ea4 100644 --- a/source/blender/nodes/composite/nodes/node_composite_luma_matte.cc +++ b/source/blender/nodes/composite/nodes/node_composite_luma_matte.cc @@ -5,9 +5,15 @@ * \ingroup cmpnodes */ +#include "IMB_colormanagement.h" + #include "UI_interface.h" #include "UI_resources.h" +#include "GPU_material.h" + +#include "COM_shader_node.hh" + #include "node_composite_util.hh" /* ******************* Luma Matte Node ********************************* */ @@ -16,7 +22,9 @@ namespace blender::nodes::node_composite_luma_matte_cc { static void cmp_node_luma_matte_declare(NodeDeclarationBuilder &b) { - b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f}); + b.add_input<decl::Color>(N_("Image")) + .default_value({1.0f, 1.0f, 1.0f, 1.0f}) + .compositor_domain_priority(0); b.add_output<decl::Color>(N_("Image")); b.add_output<decl::Float>(N_("Matte")); } @@ -40,6 +48,53 @@ static void node_composit_buts_luma_matte(uiLayout *layout, bContext *UNUSED(C), col, ptr, "limit_min", UI_ITEM_R_SPLIT_EMPTY_NAME | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); } +using namespace blender::realtime_compositor; + +class LuminanceMatteShaderNode : public ShaderNode { + public: + using ShaderNode::ShaderNode; + + void compile(GPUMaterial *material) override + { + GPUNodeStack *inputs = get_inputs_array(); + GPUNodeStack *outputs = get_outputs_array(); + + const float high = get_high(); + const float low = get_low(); + float luminance_coefficients[3]; + IMB_colormanagement_get_luminance_coefficients(luminance_coefficients); + + GPU_stack_link(material, + &bnode(), + "node_composite_luminance_matte", + inputs, + outputs, + GPU_uniform(&high), + GPU_uniform(&low), + GPU_constant(luminance_coefficients)); + } + + NodeChroma *get_node_chroma() + { + return static_cast<NodeChroma *>(bnode().storage); + } + + float get_high() + { + return get_node_chroma()->t1; + } + + float get_low() + { + return get_node_chroma()->t2; + } +}; + +static ShaderNode *get_compositor_shader_node(DNode node) +{ + return new LuminanceMatteShaderNode(node); +} + } // namespace blender::nodes::node_composite_luma_matte_cc void register_node_type_cmp_luma_matte() @@ -54,6 +109,7 @@ void register_node_type_cmp_luma_matte() ntype.flag |= NODE_PREVIEW; node_type_init(&ntype, file_ns::node_composit_init_luma_matte); node_type_storage(&ntype, "NodeChroma", node_free_standard_storage, node_copy_standard_storage); + ntype.get_compositor_shader_node = file_ns::get_compositor_shader_node; nodeRegisterType(&ntype); } |