Files
test2/source/blender/nodes/composite/nodes/node_composite_bokehblur.cc
Clément Foucault 8f44c37f5c Cleanup: Rename BLI_math_vec_types* files to BLI_math_vector_types
This is for the sake of consistency and clarity.
2023-01-06 20:09:51 +01:00

223 lines
6.5 KiB
C++

/* SPDX-License-Identifier: GPL-2.0-or-later
* Copyright 2006 Blender Foundation. All rights reserved. */
/** \file
* \ingroup cmpnodes
*/
#include "BLI_math_base.hh"
#include "BLI_math_vector_types.hh"
#include "UI_interface.h"
#include "UI_resources.h"
#include "GPU_texture.h"
#include "COM_node_operation.hh"
#include "COM_utilities.hh"
#include "node_composite_util.hh"
/* **************** BLUR ******************** */
namespace blender::nodes::node_composite_bokehblur_cc {
static void cmp_node_bokehblur_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Color>(N_("Image"))
.default_value({0.8f, 0.8f, 0.8f, 1.0f})
.compositor_domain_priority(0);
b.add_input<decl::Color>(N_("Bokeh"))
.default_value({1.0f, 1.0f, 1.0f, 1.0f})
.compositor_skip_realization();
b.add_input<decl::Float>(N_("Size"))
.default_value(1.0f)
.min(0.0f)
.max(10.0f)
.compositor_domain_priority(1);
b.add_input<decl::Float>(N_("Bounding box"))
.default_value(1.0f)
.min(0.0f)
.max(1.0f)
.compositor_domain_priority(2);
b.add_output<decl::Color>(N_("Image"));
}
static void node_composit_init_bokehblur(bNodeTree * /*ntree*/, bNode *node)
{
node->custom3 = 4.0f;
node->custom4 = 16.0f;
}
static void node_composit_buts_bokehblur(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
{
uiItemR(layout, ptr, "use_variable_size", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
// uiItemR(layout, ptr, "f_stop", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE); /* UNUSED */
uiItemR(layout, ptr, "blur_max", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
uiItemR(layout, ptr, "use_extended_bounds", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
}
using namespace blender::realtime_compositor;
class BokehBlurOperation : public NodeOperation {
public:
using NodeOperation::NodeOperation;
void execute() override
{
if (is_identity()) {
get_input("Image").pass_through(get_result("Image"));
return;
}
if (get_input("Size").is_single_value() || !get_variable_size()) {
execute_constant_size();
}
else {
execute_variable_size();
}
}
void execute_constant_size()
{
GPUShader *shader = shader_manager().get("compositor_blur");
GPU_shader_bind(shader);
GPU_shader_uniform_1i(shader, "radius", int(compute_blur_radius()));
GPU_shader_uniform_1b(shader, "extend_bounds", get_extend_bounds());
const Result &input_image = get_input("Image");
input_image.bind_as_texture(shader, "input_tx");
const Result &input_weights = get_input("Bokeh");
input_weights.bind_as_texture(shader, "weights_tx");
const Result &input_mask = get_input("Bounding box");
input_mask.bind_as_texture(shader, "mask_tx");
Domain domain = compute_domain();
if (get_extend_bounds()) {
/* Add a radius amount of pixels in both sides of the image, hence the multiply by 2. */
domain.size += int2(int(compute_blur_radius()) * 2);
}
Result &output_image = get_result("Image");
output_image.allocate_texture(domain);
output_image.bind_as_image(shader, "output_img");
compute_dispatch_threads_at_least(shader, domain.size);
GPU_shader_unbind();
output_image.unbind_as_image();
input_image.unbind_as_texture();
input_weights.unbind_as_texture();
input_mask.unbind_as_texture();
}
void execute_variable_size()
{
GPUShader *shader = shader_manager().get("compositor_blur_variable_size");
GPU_shader_bind(shader);
GPU_shader_uniform_1f(shader, "base_size", compute_blur_radius());
GPU_shader_uniform_1i(shader, "search_radius", get_max_size());
const Result &input_image = get_input("Image");
input_image.bind_as_texture(shader, "input_tx");
const Result &input_weights = get_input("Bokeh");
input_weights.bind_as_texture(shader, "weights_tx");
const Result &input_size = get_input("Size");
input_size.bind_as_texture(shader, "size_tx");
const Result &input_mask = get_input("Bounding box");
input_mask.bind_as_texture(shader, "mask_tx");
const Domain domain = compute_domain();
Result &output_image = get_result("Image");
output_image.allocate_texture(domain);
output_image.bind_as_image(shader, "output_img");
compute_dispatch_threads_at_least(shader, domain.size);
GPU_shader_unbind();
output_image.unbind_as_image();
input_image.unbind_as_texture();
input_weights.unbind_as_texture();
input_size.unbind_as_texture();
input_mask.unbind_as_texture();
}
float compute_blur_radius()
{
const int2 image_size = get_input("Image").domain().size;
const int max_size = math::max(image_size.x, image_size.y);
/* The [0, 10] range of the size is arbitrary and is merely in place to avoid very long
* computations of the bokeh blur. */
const float size = math::clamp(get_input("Size").get_float_value_default(1.0f), 0.0f, 10.0f);
/* The 100 divisor is arbitrary and was chosen using visual judgment. */
return size * (max_size / 100.0f);
}
bool is_identity()
{
const Result &input = get_input("Image");
if (input.is_single_value()) {
return true;
}
if (compute_blur_radius() == 0.0f) {
return true;
}
/* This input is, in fact, a boolean mask. If it is zero, no blurring will take place.
* Otherwise, the blurring will take place ignoring the value of the input entirely. */
const Result &bounding_box = get_input("Bounding box");
if (bounding_box.is_single_value() && bounding_box.get_float_value() == 0.0) {
return true;
}
return false;
}
bool get_extend_bounds()
{
return bnode().custom1 & CMP_NODEFLAG_BLUR_EXTEND_BOUNDS;
}
bool get_variable_size()
{
return bnode().custom1 & CMP_NODEFLAG_BLUR_VARIABLE_SIZE;
}
int get_max_size()
{
return int(bnode().custom4);
}
};
static NodeOperation *get_compositor_operation(Context &context, DNode node)
{
return new BokehBlurOperation(context, node);
}
} // namespace blender::nodes::node_composite_bokehblur_cc
void register_node_type_cmp_bokehblur()
{
namespace file_ns = blender::nodes::node_composite_bokehblur_cc;
static bNodeType ntype;
cmp_node_type_base(&ntype, CMP_NODE_BOKEHBLUR, "Bokeh Blur", NODE_CLASS_OP_FILTER);
ntype.declare = file_ns::cmp_node_bokehblur_declare;
ntype.draw_buttons = file_ns::node_composit_buts_bokehblur;
ntype.initfunc = file_ns::node_composit_init_bokehblur;
ntype.get_compositor_operation = file_ns::get_compositor_operation;
nodeRegisterType(&ntype);
}