This patch implements the Anisotropic Kuwahara filter for the Realtime compositor and replaces the existing CPU implementation with a new one to be compatible with the GPU implementation. The implementation is based on three papers on Anisotropic Kuwahara filtering, presented and detailed in the code. The new implementation exposes two extra parameters that control the sharpness and directionality of the output, giving more artistic freedom. While the implementation is different from the existing CPU implementation, it is a higher quality one that is also faster and conforms better to the methods described in the papers. Examples can be seen in the pull request description. Pull Request: https://projects.blender.org/blender/blender/pulls/110786
83 lines
3.1 KiB
C++
83 lines
3.1 KiB
C++
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
#include "DNA_node_types.h"
|
|
#include "DNA_scene_types.h"
|
|
|
|
#include "COM_KuwaharaNode.h"
|
|
|
|
#include "COM_GaussianXBlurOperation.h"
|
|
#include "COM_GaussianYBlurOperation.h"
|
|
#include "COM_KuwaharaAnisotropicOperation.h"
|
|
#include "COM_KuwaharaAnisotropicStructureTensorOperation.h"
|
|
#include "COM_KuwaharaClassicOperation.h"
|
|
|
|
namespace blender::compositor {
|
|
|
|
void KuwaharaNode::convert_to_operations(NodeConverter &converter,
|
|
const CompositorContext & /*context*/) const
|
|
{
|
|
const bNode *node = this->get_bnode();
|
|
const NodeKuwaharaData *data = (const NodeKuwaharaData *)node->storage;
|
|
|
|
switch (data->variation) {
|
|
case CMP_NODE_KUWAHARA_CLASSIC: {
|
|
KuwaharaClassicOperation *operation = new KuwaharaClassicOperation();
|
|
operation->set_kernel_size(data->size);
|
|
|
|
converter.add_operation(operation);
|
|
converter.map_input_socket(get_input_socket(0), operation->get_input_socket(0));
|
|
converter.map_output_socket(get_output_socket(0), operation->get_output_socket());
|
|
break;
|
|
}
|
|
|
|
case CMP_NODE_KUWAHARA_ANISOTROPIC: {
|
|
KuwaharaAnisotropicStructureTensorOperation *structure_tensor_operation =
|
|
new KuwaharaAnisotropicStructureTensorOperation();
|
|
converter.add_operation(structure_tensor_operation);
|
|
converter.map_input_socket(get_input_socket(0),
|
|
structure_tensor_operation->get_input_socket(0));
|
|
|
|
NodeBlurData blur_data;
|
|
blur_data.sizex = data->uniformity;
|
|
blur_data.sizey = data->uniformity;
|
|
blur_data.relative = false;
|
|
blur_data.filtertype = R_FILTER_GAUSS;
|
|
|
|
GaussianXBlurOperation *blur_x_operation = new GaussianXBlurOperation();
|
|
blur_x_operation->set_data(&blur_data);
|
|
blur_x_operation->set_size(1.0f);
|
|
|
|
converter.add_operation(blur_x_operation);
|
|
converter.add_link(structure_tensor_operation->get_output_socket(0),
|
|
blur_x_operation->get_input_socket(0));
|
|
|
|
GaussianYBlurOperation *blur_y_operation = new GaussianYBlurOperation();
|
|
blur_y_operation->set_data(&blur_data);
|
|
blur_y_operation->set_size(1.0f);
|
|
|
|
converter.add_operation(blur_y_operation);
|
|
converter.add_link(blur_x_operation->get_output_socket(0),
|
|
blur_y_operation->get_input_socket(0));
|
|
|
|
KuwaharaAnisotropicOperation *kuwahara_anisotropic_operation =
|
|
new KuwaharaAnisotropicOperation();
|
|
kuwahara_anisotropic_operation->data = *data;
|
|
|
|
converter.add_operation(kuwahara_anisotropic_operation);
|
|
converter.map_input_socket(get_input_socket(0),
|
|
kuwahara_anisotropic_operation->get_input_socket(0));
|
|
converter.add_link(blur_y_operation->get_output_socket(0),
|
|
kuwahara_anisotropic_operation->get_input_socket(1));
|
|
|
|
converter.map_output_socket(get_output_socket(0),
|
|
kuwahara_anisotropic_operation->get_output_socket(0));
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
} // namespace blender::compositor
|