WIP: Compositor: Add interpolation option to displace node in compositor #119908

Draft
Noah Pinales wants to merge 1 commits from Noah-Pinales/blender:com-displace-interp into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
8 changed files with 97 additions and 19 deletions

View File

@ -3,6 +3,7 @@
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "COM_DisplaceNode.h"
#include "BKE_node.hh"
#include "COM_DisplaceOperation.h"
#include "COM_DisplaceSimpleOperation.h"
@ -16,20 +17,46 @@ DisplaceNode::DisplaceNode(bNode *editor_node) : Node(editor_node)
void DisplaceNode::convert_to_operations(NodeConverter &converter,
const CompositorContext &context) const
{
NodeOperation *operation;
const bNode *bnode = this->get_bnode();
PixelSampler sampler = PixelSampler::Nearest;
switch (bnode->custom1) {
case 0:
sampler = PixelSampler::Nearest;
break;
case 1:
sampler = PixelSampler::Bilinear;
break;
case 2:
sampler = PixelSampler::Bicubic;
break;
}
if (context.get_quality() == eCompositorQuality::Low) {
operation = new DisplaceSimpleOperation();
DisplaceSimpleOperation *operation = new DisplaceSimpleOperation();
operation->set_sampler(sampler);
converter.add_operation(operation);
converter.map_input_socket(get_input_socket(0), operation->get_input_socket(0));
converter.map_input_socket(get_input_socket(1), operation->get_input_socket(1));
converter.map_input_socket(get_input_socket(2), operation->get_input_socket(2));
converter.map_input_socket(get_input_socket(3), operation->get_input_socket(3));
converter.map_output_socket(get_output_socket(0), operation->get_output_socket());
}
else {
operation = new DisplaceOperation();
}
converter.add_operation(operation);
DisplaceOperation *operation = new DisplaceOperation();
converter.map_input_socket(get_input_socket(0), operation->get_input_socket(0));
converter.map_input_socket(get_input_socket(1), operation->get_input_socket(1));
converter.map_input_socket(get_input_socket(2), operation->get_input_socket(2));
converter.map_input_socket(get_input_socket(3), operation->get_input_socket(3));
converter.map_output_socket(get_output_socket(0), operation->get_output_socket());
operation->set_sampler(sampler);
converter.add_operation(operation);
converter.map_input_socket(get_input_socket(0), operation->get_input_socket(0));
converter.map_input_socket(get_input_socket(1), operation->get_input_socket(1));
converter.map_input_socket(get_input_socket(2), operation->get_input_socket(2));
converter.map_input_socket(get_input_socket(3), operation->get_input_socket(3));
converter.map_output_socket(get_output_socket(0), operation->get_output_socket());
}
}
} // namespace blender::compositor

View File

@ -141,19 +141,14 @@ void DisplaceOperation::update_memory_buffer_partial(MemoryBuffer *output,
Span<MemoryBuffer *> inputs)
{
const MemoryBuffer *input_color = inputs[0];
PixelSampler sampler = (PixelSampler)sampler_;
for (BuffersIterator<float> it = output->iterate_with({}, area); !it.is_end(); ++it) {
const float xy[2] = {float(it.x), float(it.y)};
float uv[2];
float deriv[2][2];
pixel_transform(xy, uv, deriv);
if (is_zero_v2(deriv[0]) && is_zero_v2(deriv[1])) {
input_color->read_elem_bilinear(uv[0], uv[1], it.out);
}
else {
/* EWA filtering (without nearest it gets blurry with NO distortion). */
input_color->read_elem_filtered(uv[0], uv[1], deriv[0], deriv[1], false, it.out);
}
input_color->read_elem_sampled(uv[0], uv[1], sampler, it.out);
}
}

View File

@ -35,6 +35,14 @@ class DisplaceOperation : public MultiThreadedOperation {
const rcti &area,
Span<MemoryBuffer *> inputs) override;
void set_sampler(PixelSampler sampler)
{
sampler_ = (int)sampler;
}
protected:
int sampler_;
private:
bool read_displacement(
float x, float y, float xscale, float yscale, const float origin[2], float &r_u, float &r_v);

View File

@ -46,6 +46,7 @@ void DisplaceSimpleOperation::update_memory_buffer_partial(MemoryBuffer *output,
const float width = this->get_width();
const float height = this->get_height();
const MemoryBuffer *input_color = inputs[0];
PixelSampler sampler = (PixelSampler)sampler_;
for (BuffersIterator<float> it = output->iterate_with(inputs.drop_front(1), area); !it.is_end();
++it)
{
@ -69,7 +70,7 @@ void DisplaceSimpleOperation::update_memory_buffer_partial(MemoryBuffer *output,
CLAMP(u, 0.0f, width - 1.0f);
CLAMP(v, 0.0f, height - 1.0f);
input_color->read_elem_checked(u, v, it.out);
input_color->read_elem_sampled(u, v, sampler, it.out);
}
}

View File

@ -22,6 +22,14 @@ class DisplaceSimpleOperation : public MultiThreadedOperation {
void update_memory_buffer_partial(MemoryBuffer *output,
const rcti &area,
Span<MemoryBuffer *> inputs) override;
void set_sampler(PixelSampler sampler)
{
sampler_ = (int)sampler;
}
protected:
int sampler_;
};
} // namespace blender::compositor

View File

@ -6636,6 +6636,36 @@ static void def_cmp_scale(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
static void def_cmp_displace(StructRNA *srna)
{
PropertyRNA *prop;
static const EnumPropertyItem interpolation_items[] = {
{CMP_NODE_STABILIZE_INTERPOLATION_NEAREST,
"NEAREST",
0,
"Nearest",
"Use nearest interpolation"},
{CMP_NODE_STABILIZE_INTERPOLATION_BILINEAR,
"BILINEAR",
0,
"Bilinear",
"Use bilinear interpolation"},
{CMP_NODE_STABILIZE_INTERPOLATION_BICUBIC,
"BICUBIC",
0,
"Bicubic",
"Use bicubic interpolation"},
{0, nullptr, 0, nullptr, nullptr},
};
prop = RNA_def_property(srna, "interpolation", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, nullptr, "custom1");
RNA_def_property_enum_items(prop, interpolation_items);
RNA_def_property_ui_text(prop, "Interpolation", "Which interpolation method to use");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
static void def_cmp_rotate(StructRNA *srna)
{
PropertyRNA *prop;

View File

@ -172,7 +172,7 @@ DefNode(CompositorNode, CMP_NODE_MAP_UV, def_cmp_map_uv, "MAP_UV
DefNode(CompositorNode, CMP_NODE_ID_MASK, def_cmp_id_mask, "ID_MASK", IDMask, "ID Mask", "" )
DefNode(CompositorNode, CMP_NODE_DOUBLEEDGEMASK, def_cmp_double_edge_mask,"DOUBLEEDGEMASK", DoubleEdgeMask, "Double Edge Mask", "" )
DefNode(CompositorNode, CMP_NODE_DEFOCUS, def_cmp_defocus, "DEFOCUS", Defocus, "Defocus", "" )
DefNode(CompositorNode, CMP_NODE_DISPLACE, 0, "DISPLACE", Displace, "Displace", "" )
DefNode(CompositorNode, CMP_NODE_DISPLACE, def_cmp_displace, "DISPLACE", Displace, "Displace", "" )
DefNode(CompositorNode, CMP_NODE_COMBHSVA_LEGACY,0, "COMBHSVA", CombHSVA, "Combine HSVA", "" )
DefNode(CompositorNode, CMP_NODE_MATH, def_math, "MATH", Math, "Math", "" )
DefNode(CompositorNode, CMP_NODE_LUMA_MATTE, def_cmp_luma_matte, "LUMA_MATTE", LumaMatte, "Luminance Key", "" )

View File

@ -11,6 +11,9 @@
#include "GPU_shader.hh"
#include "GPU_texture.hh"
#include "UI_interface.hh"
#include "UI_resources.hh"
#include "COM_node_operation.hh"
#include "COM_utilities.hh"
@ -44,6 +47,11 @@ static void cmp_node_displace_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Color>("Image");
}
static void node_composit_buts_displace(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
{
uiItemR(layout, ptr, "interpolation", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
}
using namespace blender::realtime_compositor;
class DisplaceOperation : public NodeOperation {
@ -129,6 +137,7 @@ void register_node_type_cmp_displace()
cmp_node_type_base(&ntype, CMP_NODE_DISPLACE, "Displace", NODE_CLASS_DISTORT);
ntype.declare = file_ns::cmp_node_displace_declare;
ntype.draw_buttons = file_ns::node_composit_buts_displace;
ntype.get_compositor_operation = file_ns::get_compositor_operation;
nodeRegisterType(&ntype);