This patch adjusts the Variable Size Bokeh Blur node such that it matches between CPU and GPU. The GPU implementation is mostly followed for the reasons stated below. The first difference is a bug in the CPU implementation, where the upper limit of the blur window is not considered, but the lower limit is. The second difference is due to CPU ignoring outside pixels instead of clamping them to border, which is done until an option is added to the node to control the boundary condition. The third difference is due to CPU ignoring the bounding box input. The fourth difference is that CPU doesn't allow zero maximum blur radius, which is a valid option. The fifth difference is that the threshold option, which is only used for the Defocus node, was considered in a greater than manner, while it should be greater than or equal. Since the default threshold of one should allow a blur size of one. The GPU implementation now considers the maximum size of its input, following the CPU implementation. Pull Request: https://projects.blender.org/blender/blender/pulls/117947
134 lines
5.1 KiB
C++
134 lines
5.1 KiB
C++
/* SPDX-FileCopyrightText: 2011 Blender Authors
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
#include "DNA_scene_types.h"
|
|
|
|
#include "BKE_camera.h"
|
|
|
|
#include "COM_BokehImageOperation.h"
|
|
#include "COM_ConvertDepthToRadiusOperation.h"
|
|
#include "COM_DefocusNode.h"
|
|
#include "COM_FastGaussianBlurOperation.h"
|
|
#include "COM_GammaCorrectOperation.h"
|
|
#include "COM_MathBaseOperation.h"
|
|
#include "COM_SetValueOperation.h"
|
|
#include "COM_VariableSizeBokehBlurOperation.h"
|
|
|
|
namespace blender::compositor {
|
|
|
|
DefocusNode::DefocusNode(bNode *editor_node) : Node(editor_node)
|
|
{
|
|
/* pass */
|
|
}
|
|
|
|
void DefocusNode::convert_to_operations(NodeConverter &converter,
|
|
const CompositorContext &context) const
|
|
{
|
|
const bNode *node = this->get_bnode();
|
|
const NodeDefocus *data = (const NodeDefocus *)node->storage;
|
|
|
|
NodeOperation *radius_operation;
|
|
if (data->no_zbuf) {
|
|
MathMultiplyOperation *multiply = new MathMultiplyOperation();
|
|
SetValueOperation *multiplier = new SetValueOperation();
|
|
multiplier->set_value(data->scale);
|
|
SetValueOperation *max_radius = new SetValueOperation();
|
|
max_radius->set_value(data->maxblur);
|
|
MathMinimumOperation *minimize = new MathMinimumOperation();
|
|
|
|
converter.add_operation(multiply);
|
|
converter.add_operation(multiplier);
|
|
converter.add_operation(max_radius);
|
|
converter.add_operation(minimize);
|
|
|
|
converter.map_input_socket(get_input_socket(1), multiply->get_input_socket(0));
|
|
converter.add_link(multiplier->get_output_socket(), multiply->get_input_socket(1));
|
|
converter.add_link(multiply->get_output_socket(), minimize->get_input_socket(0));
|
|
converter.add_link(max_radius->get_output_socket(), minimize->get_input_socket(1));
|
|
|
|
radius_operation = minimize;
|
|
}
|
|
else {
|
|
ConvertDepthToRadiusOperation *radius_op = new ConvertDepthToRadiusOperation();
|
|
radius_op->set_data(data);
|
|
radius_op->set_scene(get_scene(context));
|
|
converter.add_operation(radius_op);
|
|
converter.map_input_socket(get_input_socket(1), radius_op->get_input_socket(0));
|
|
converter.map_input_socket(get_input_socket(0), radius_op->get_input_socket(1));
|
|
|
|
GaussianXBlurOperation *blur_x_operation = new GaussianXBlurOperation();
|
|
converter.add_operation(blur_x_operation);
|
|
converter.add_link(radius_op->get_output_socket(), blur_x_operation->get_input_socket(0));
|
|
|
|
GaussianYBlurOperation *blur_y_operation = new GaussianYBlurOperation();
|
|
converter.add_operation(blur_y_operation);
|
|
converter.add_link(blur_x_operation->get_output_socket(),
|
|
blur_y_operation->get_input_socket(0));
|
|
|
|
MathMinimumOperation *minimum_operation = new MathMinimumOperation();
|
|
converter.add_operation(minimum_operation);
|
|
converter.add_link(blur_y_operation->get_output_socket(),
|
|
minimum_operation->get_input_socket(0));
|
|
converter.add_link(radius_op->get_output_socket(), minimum_operation->get_input_socket(1));
|
|
|
|
radius_op->set_blur_x_operation(blur_x_operation);
|
|
radius_op->set_blur_y_operation(blur_y_operation);
|
|
|
|
radius_operation = minimum_operation;
|
|
}
|
|
|
|
NodeBokehImage *bokehdata = new NodeBokehImage();
|
|
bokehdata->angle = data->rotation;
|
|
bokehdata->rounding = 0.0f;
|
|
bokehdata->flaps = data->bktype;
|
|
if (data->bktype < 3) {
|
|
bokehdata->flaps = 5;
|
|
bokehdata->rounding = 1.0f;
|
|
}
|
|
bokehdata->catadioptric = 0.0f;
|
|
bokehdata->lensshift = 0.0f;
|
|
|
|
BokehImageOperation *bokeh = new BokehImageOperation();
|
|
bokeh->set_data(bokehdata);
|
|
bokeh->delete_data_on_finish();
|
|
converter.add_operation(bokeh);
|
|
|
|
SetValueOperation *bounding_box_operation = new SetValueOperation();
|
|
bounding_box_operation->set_value(1.0f);
|
|
converter.add_operation(bounding_box_operation);
|
|
|
|
VariableSizeBokehBlurOperation *operation = new VariableSizeBokehBlurOperation();
|
|
operation->set_quality(eCompositorQuality::High);
|
|
operation->set_max_blur(data->maxblur);
|
|
operation->set_threshold(data->bthresh);
|
|
converter.add_operation(operation);
|
|
|
|
converter.add_link(bokeh->get_output_socket(), operation->get_input_socket(1));
|
|
converter.add_link(radius_operation->get_output_socket(), operation->get_input_socket(2));
|
|
converter.add_link(bounding_box_operation->get_output_socket(), operation->get_input_socket(3));
|
|
|
|
if (data->gamco) {
|
|
GammaCorrectOperation *correct = new GammaCorrectOperation();
|
|
converter.add_operation(correct);
|
|
GammaUncorrectOperation *inverse = new GammaUncorrectOperation();
|
|
converter.add_operation(inverse);
|
|
|
|
converter.map_input_socket(get_input_socket(0), correct->get_input_socket(0));
|
|
converter.add_link(correct->get_output_socket(), operation->get_input_socket(0));
|
|
converter.add_link(operation->get_output_socket(), inverse->get_input_socket(0));
|
|
converter.map_output_socket(get_output_socket(), inverse->get_output_socket());
|
|
}
|
|
else {
|
|
converter.map_input_socket(get_input_socket(0), operation->get_input_socket(0));
|
|
converter.map_output_socket(get_output_socket(), operation->get_output_socket());
|
|
}
|
|
}
|
|
|
|
const Scene *DefocusNode::get_scene(const CompositorContext &context) const
|
|
{
|
|
return get_bnode()->id ? reinterpret_cast<Scene *>(get_bnode()->id) : context.get_scene();
|
|
}
|
|
|
|
} // namespace blender::compositor
|