Compositor: implement interpolation methods for Translate node #119603
|
@ -407,7 +407,10 @@ class MemoryBuffer {
|
|||
*/
|
||||
MemoryBuffer *inflate() const;
|
||||
|
||||
inline void wrap_pixel(int &x, int &y, MemoryBufferExtend extend_x, MemoryBufferExtend extend_y)
|
||||
inline void wrap_pixel(int &x,
|
||||
int &y,
|
||||
MemoryBufferExtend extend_x,
|
||||
MemoryBufferExtend extend_y) const
|
||||
{
|
||||
const int w = get_width();
|
||||
const int h = get_height();
|
||||
|
@ -503,10 +506,11 @@ class MemoryBuffer {
|
|||
}
|
||||
|
||||
inline void read(float *result,
|
||||
int x,
|
||||
int y,
|
||||
float x,
|
||||
float y,
|
||||
PixelSampler sampler = PixelSampler::Nearest,
|
||||
MemoryBufferExtend extend_x = MemoryBufferExtend::Clip,
|
||||
MemoryBufferExtend extend_y = MemoryBufferExtend::Clip)
|
||||
MemoryBufferExtend extend_y = MemoryBufferExtend::Clip) const
|
||||
{
|
||||
bool clip_x = (extend_x == MemoryBufferExtend::Clip && (x < rect_.xmin || x >= rect_.xmax));
|
||||
bool clip_y = (extend_y == MemoryBufferExtend::Clip && (y < rect_.ymin || y >= rect_.ymax));
|
||||
|
@ -515,12 +519,10 @@ class MemoryBuffer {
|
|||
memset(result, 0, num_channels_ * sizeof(float));
|
||||
}
|
||||
else {
|
||||
int u = x;
|
||||
int v = y;
|
||||
float u = x;
|
||||
float v = y;
|
||||
this->wrap_pixel(u, v, extend_x, extend_y);
|
||||
const int offset = get_coords_offset(u, v);
|
||||
float *buffer = &buffer_[offset];
|
||||
memcpy(result, buffer, sizeof(float) * num_channels_);
|
||||
this->read_elem_sampled(u, v, sampler, result);
|
||||
}
|
||||
}
|
||||
void write_pixel(int x, int y, const float color[4]);
|
||||
|
|
|
@ -61,6 +61,7 @@ void Stabilize2dNode::convert_to_operations(NodeConverter &converter,
|
|||
rotate_operation->set_do_degree2_rad_conversion(false);
|
||||
rotate_operation->set_sampler(sampler);
|
||||
TranslateOperation *translate_operation = new TranslateCanvasOperation();
|
||||
translate_operation->set_sampler(sampler);
|
||||
|
||||
converter.add_operation(scale_operation);
|
||||
converter.add_operation(translate_operation);
|
||||
|
|
|
@ -28,6 +28,18 @@ void TranslateNode::convert_to_operations(NodeConverter &converter,
|
|||
operation->set_wrapping(data->wrap_axis);
|
||||
operation->set_is_relative(data->relative);
|
||||
|
||||
switch (data->interpolation) {
|
||||
case CMP_NODE_INTERPOLATION_NEAREST:
|
||||
operation->set_sampler(PixelSampler::Nearest);
|
||||
break;
|
||||
case CMP_NODE_INTERPOLATION_BILINEAR:
|
||||
operation->set_sampler(PixelSampler::Bilinear);
|
||||
break;
|
||||
case CMP_NODE_INTERPOLATION_BICUBIC:
|
||||
operation->set_sampler(PixelSampler::Bicubic);
|
||||
break;
|
||||
}
|
||||
|
||||
converter.add_operation(operation);
|
||||
converter.map_input_socket(input_xsocket, operation->get_input_socket(1));
|
||||
converter.map_input_socket(input_ysocket, operation->get_input_socket(2));
|
||||
|
|
|
@ -18,6 +18,7 @@ TranslateOperation::TranslateOperation(DataType data_type, ResizeMode resize_mod
|
|||
is_relative_ = false;
|
||||
this->x_extend_mode_ = MemoryBufferExtend::Clip;
|
||||
this->y_extend_mode_ = MemoryBufferExtend::Clip;
|
||||
this->sampler_ = PixelSampler::Nearest;
|
||||
|
||||
this->flags_.can_be_constant = true;
|
||||
}
|
||||
|
@ -96,14 +97,20 @@ void TranslateOperation::update_memory_buffer_partial(MemoryBuffer *output,
|
|||
return;
|
||||
}
|
||||
|
||||
const int delta_x = this->get_delta_x();
|
||||
const int delta_y = this->get_delta_y();
|
||||
float delta_x = this->get_delta_x();
|
||||
float delta_y = this->get_delta_y();
|
||||
if (sampler_ == PixelSampler::Nearest) {
|
||||
/* Use same rounding convention for GPU compositor. */
|
||||
delta_x = round(delta_x);
|
||||
delta_y = round(delta_y);
|
||||
}
|
||||
|
||||
for (int y = area.ymin; y < area.ymax; y++) {
|
||||
float *out = output->get_elem(area.xmin, y);
|
||||
for (int x = area.xmin; x < area.xmax; x++) {
|
||||
const int input_x = x - delta_x;
|
||||
const int input_y = y - delta_y;
|
||||
input->read(out, input_x, input_y, x_extend_mode_, y_extend_mode_);
|
||||
const float input_x = x - delta_x;
|
||||
const float input_y = y - delta_y;
|
||||
input->read(out, input_x, input_y, sampler_, x_extend_mode_, y_extend_mode_);
|
||||
out += output->elem_stride;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ class TranslateOperation : public MultiThreadedOperation {
|
|||
float delta_y_;
|
||||
bool is_delta_set_;
|
||||
bool is_relative_;
|
||||
PixelSampler sampler_;
|
||||
|
||||
std::mutex mutex_;
|
||||
|
||||
|
@ -51,6 +52,15 @@ class TranslateOperation : public MultiThreadedOperation {
|
|||
return is_relative_;
|
||||
}
|
||||
|
||||
PixelSampler get_sampler()
|
||||
{
|
||||
return sampler_;
|
||||
}
|
||||
void set_sampler(PixelSampler sampler)
|
||||
{
|
||||
sampler_ = sampler;
|
||||
}
|
||||
|
||||
inline void ensure_delta()
|
||||
{
|
||||
if (!is_delta_set_) {
|
||||
|
|
|
@ -1420,6 +1420,7 @@ typedef struct NodeTrackPosData {
|
|||
typedef struct NodeTranslateData {
|
||||
char wrap_axis;
|
||||
char relative;
|
||||
short interpolation;
|
||||
} NodeTranslateData;
|
||||
|
||||
typedef struct NodePlaneTrackDeformData {
|
||||
|
@ -2565,12 +2566,13 @@ typedef enum CMPNodeKuwahara {
|
|||
CMP_NODE_KUWAHARA_ANISOTROPIC = 1,
|
||||
} CMPNodeKuwahara;
|
||||
|
||||
/* Stabilize 2D node. Stored in custom1. */
|
||||
typedef enum CMPNodeStabilizeInterpolation {
|
||||
CMP_NODE_STABILIZE_INTERPOLATION_NEAREST = 0,
|
||||
CMP_NODE_STABILIZE_INTERPOLATION_BILINEAR = 1,
|
||||
CMP_NODE_STABILIZE_INTERPOLATION_BICUBIC = 2,
|
||||
} CMPNodeStabilizeInterpolation;
|
||||
/* Stabilize 2D node. Stored in custom1 for Stabilize 2D node and in interpolation for Translate
|
||||
* node. */
|
||||
typedef enum CMPNodeInterpolation {
|
||||
CMP_NODE_INTERPOLATION_NEAREST = 0,
|
||||
CMP_NODE_INTERPOLATION_BILINEAR = 1,
|
||||
CMP_NODE_INTERPOLATION_BICUBIC = 2,
|
||||
} CMPNodeInterpolation;
|
||||
|
||||
/* Stabilize 2D node. Stored in custom2. */
|
||||
typedef enum CMPNodeStabilizeInverse {
|
||||
|
|
|
@ -8478,10 +8478,23 @@ static void def_cmp_translate(StructRNA *srna)
|
|||
{0, nullptr, 0, nullptr, nullptr},
|
||||
};
|
||||
|
||||
static const EnumPropertyItem interpolation_items[] = {
|
||||
{CMP_NODE_INTERPOLATION_NEAREST, "Nearest", 0, "Nearest", "Use nearest interpolation"},
|
||||
{CMP_NODE_INTERPOLATION_BILINEAR, "Bilinear", 0, "Bilinear", "Use bilinear interpolation"},
|
||||
{CMP_NODE_INTERPOLATION_BICUBIC, "Bicubic", 0, "Bicubic", "Use bicubic interpolation"},
|
||||
{0, nullptr, 0, nullptr, nullptr},
|
||||
};
|
||||
|
||||
PropertyRNA *prop;
|
||||
|
||||
RNA_def_struct_sdna_from(srna, "NodeTranslateData", "storage");
|
||||
|
||||
prop = RNA_def_property(srna, "interpolation", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, NULL, "interpolation");
|
||||
RNA_def_property_enum_items(prop, interpolation_items);
|
||||
RNA_def_property_ui_text(prop, "", "");
|
||||
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
|
||||
|
||||
prop = RNA_def_property(srna, "use_relative", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, nullptr, "relative", 1);
|
||||
RNA_def_property_ui_text(
|
||||
|
|
|
@ -116,12 +116,12 @@ class Stabilize2DOperation : public NodeOperation {
|
|||
|
||||
Interpolation get_interpolation()
|
||||
{
|
||||
switch (static_cast<CMPNodeStabilizeInterpolation>(bnode().custom1)) {
|
||||
case CMP_NODE_STABILIZE_INTERPOLATION_NEAREST:
|
||||
switch (static_cast<CMPNodeInterpolation>(bnode().custom1)) {
|
||||
case CMP_NODE_INTERPOLATION_NEAREST:
|
||||
return Interpolation::Nearest;
|
||||
case CMP_NODE_STABILIZE_INTERPOLATION_BILINEAR:
|
||||
case CMP_NODE_INTERPOLATION_BILINEAR:
|
||||
return Interpolation::Bilinear;
|
||||
case CMP_NODE_STABILIZE_INTERPOLATION_BICUBIC:
|
||||
case CMP_NODE_INTERPOLATION_BICUBIC:
|
||||
return Interpolation::Bicubic;
|
||||
}
|
||||
|
||||
|
|
|
@ -48,6 +48,7 @@ static void node_composit_init_translate(bNodeTree * /*ntree*/, bNode *node)
|
|||
|
||||
static void node_composit_buts_translate(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
|
||||
{
|
||||
uiItemR(layout, ptr, "interpolation", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
|
||||
uiItemR(layout, ptr, "use_relative", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
|
||||
uiItemR(layout, ptr, "wrap_axis", UI_ITEM_R_SPLIT_EMPTY_NAME, nullptr, ICON_NONE);
|
||||
}
|
||||
|
@ -77,10 +78,26 @@ class TranslateOperation : public NodeOperation {
|
|||
RealizationOptions realization_options = input.get_realization_options();
|
||||
realization_options.wrap_x = get_wrap_x();
|
||||
realization_options.wrap_y = get_wrap_y();
|
||||
realization_options.interpolation = get_interpolation();
|
||||
|
||||
transform(context(), input, result, transformation, realization_options);
|
||||
}
|
||||
|
||||
Interpolation get_interpolation()
|
||||
{
|
||||
switch (node_storage(bnode()).interpolation) {
|
||||
case CMP_NODE_INTERPOLATION_NEAREST:
|
||||
return Interpolation::Nearest;
|
||||
case CMP_NODE_INTERPOLATION_BILINEAR:
|
||||
return Interpolation::Bilinear;
|
||||
case CMP_NODE_INTERPOLATION_BICUBIC:
|
||||
return Interpolation::Bicubic;
|
||||
}
|
||||
|
||||
BLI_assert_unreachable();
|
||||
return Interpolation::Nearest;
|
||||
}
|
||||
|
||||
bool get_use_relative()
|
||||
{
|
||||
return node_storage(bnode()).relative;
|
||||
|
|
Loading…
Reference in New Issue