Compositor: Expose interpolation in Corner Pin node
This patch exposes an interpolation option to the Corner Pin node, allowing to choose between Nearest, Bilinear, Bicubic, and Anisotropic. Pull Request: https://projects.blender.org/blender/blender/pulls/123206
This commit is contained in:
@@ -27,7 +27,7 @@
|
||||
|
||||
/* Blender file format version. */
|
||||
#define BLENDER_FILE_VERSION BLENDER_VERSION
|
||||
#define BLENDER_FILE_SUBVERSION 17
|
||||
#define BLENDER_FILE_SUBVERSION 18
|
||||
|
||||
/* Minimum Blender version that supports reading file written with the current
|
||||
* version. Older Blender versions will test this and cancel loading the file, showing a warning to
|
||||
|
||||
@@ -6684,6 +6684,19 @@ void blo_do_versions_400(FileData *fd, Library * /*lib*/, Main *bmain)
|
||||
version_set_uv_face_overlay_defaults(bmain);
|
||||
}
|
||||
|
||||
if (!MAIN_VERSION_FILE_ATLEAST(bmain, 405, 18)) {
|
||||
FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
|
||||
if (ntree->type == NTREE_COMPOSIT) {
|
||||
LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
|
||||
if (node->type_legacy == CMP_NODE_CORNERPIN) {
|
||||
node->custom1 = CMP_NODE_CORNER_PIN_INTERPOLATION_ANISOTROPIC;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
FOREACH_NODETREE_END;
|
||||
}
|
||||
|
||||
/* Always run this versioning; meshes are written with the legacy format which always needs to
|
||||
* be converted to the new format on file load. Can be moved to a subversion check in a larger
|
||||
* breaking release. */
|
||||
|
||||
@@ -233,10 +233,11 @@ set(GLSL_SRC
|
||||
shaders/compositor_parallel_reduction.glsl
|
||||
shaders/compositor_pixel_coordinates.glsl
|
||||
shaders/compositor_pixelate.glsl
|
||||
shaders/compositor_plane_deform.glsl
|
||||
shaders/compositor_plane_deform_anisotropic.glsl
|
||||
shaders/compositor_plane_deform_mask.glsl
|
||||
shaders/compositor_plane_deform_motion_blur.glsl
|
||||
shaders/compositor_plane_deform_motion_blur_mask.glsl
|
||||
shaders/compositor_plane_deform.glsl
|
||||
shaders/compositor_premultiply_alpha.glsl
|
||||
shaders/compositor_projector_lens_distortion.glsl
|
||||
shaders/compositor_read_input.glsl
|
||||
|
||||
@@ -409,6 +409,9 @@ class Result {
|
||||
/* Identical to sample_nearest_extended but with bilinear interpolation. */
|
||||
float4 sample_bilinear_extended(const float2 &coordinates) const;
|
||||
|
||||
/* Identical to sample_nearest_extended but with cubic interpolation. */
|
||||
float4 sample_cubic_extended(const float2 &coordinates) const;
|
||||
|
||||
float4 sample_nearest_wrap(const float2 &coordinates, bool wrap_x, bool wrap_y) const;
|
||||
float4 sample_bilinear_wrap(const float2 &coordinates, bool wrap_x, bool wrap_y) const;
|
||||
float4 sample_cubic_wrap(const float2 &coordinates, bool wrap_x, bool wrap_y) const;
|
||||
@@ -756,6 +759,28 @@ BLI_INLINE_METHOD float4 Result::sample_bilinear_extended(const float2 &coordina
|
||||
return pixel_value;
|
||||
}
|
||||
|
||||
BLI_INLINE_METHOD float4 Result::sample_cubic_extended(const float2 &coordinates) const
|
||||
{
|
||||
float4 pixel_value = float4(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
if (is_single_value_) {
|
||||
this->get_cpp_type().copy_assign(this->cpu_data().data(), pixel_value);
|
||||
return pixel_value;
|
||||
}
|
||||
|
||||
const int2 size = domain_.size;
|
||||
const float2 texel_coordinates = (coordinates * float2(size)) - 0.5f;
|
||||
|
||||
const float *buffer = static_cast<const float *>(this->cpu_data().data());
|
||||
math::interpolate_cubic_bspline_fl(buffer,
|
||||
pixel_value,
|
||||
size.x,
|
||||
size.y,
|
||||
this->channels_count(),
|
||||
texel_coordinates.x,
|
||||
texel_coordinates.y);
|
||||
return pixel_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a Result as the userdata argument, sample it at the given coordinates using extended
|
||||
* boundary condition and write the result to the result argument.
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "gpu_shader_bicubic_sampler_lib.glsl"
|
||||
#include "gpu_shader_compositor_texture_utilities.glsl"
|
||||
|
||||
void main()
|
||||
@@ -19,14 +20,7 @@ void main()
|
||||
}
|
||||
vec2 projected_coordinates = transformed_coordinates.xy / transformed_coordinates.z;
|
||||
|
||||
/* The derivatives of the projected coordinates with respect to x and y are the first and
|
||||
* second columns respectively, divided by the z projection factor as can be shown by
|
||||
* differentiating the above matrix multiplication with respect to x and y. Divide by the
|
||||
* output size since textureGrad assumes derivatives with respect to texel coordinates. */
|
||||
vec2 x_gradient = (homography_matrix[0].xy / transformed_coordinates.z) / output_size.x;
|
||||
vec2 y_gradient = (homography_matrix[1].xy / transformed_coordinates.z) / output_size.y;
|
||||
|
||||
vec4 sampled_color = textureGrad(input_tx, projected_coordinates, x_gradient, y_gradient);
|
||||
vec4 sampled_color = SAMPLER_FUNCTION(input_tx, projected_coordinates);
|
||||
|
||||
/* Premultiply the mask value as an alpha. */
|
||||
vec4 plane_color = sampled_color * texture_load(mask_tx, texel).x;
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "gpu_shader_compositor_texture_utilities.glsl"
|
||||
|
||||
void main()
|
||||
{
|
||||
ivec2 texel = ivec2(gl_GlobalInvocationID.xy);
|
||||
vec2 output_size = vec2(imageSize(output_img));
|
||||
|
||||
vec2 coordinates = (vec2(texel) + vec2(0.5)) / output_size;
|
||||
|
||||
vec3 transformed_coordinates = to_float3x3(homography_matrix) * vec3(coordinates, 1.0);
|
||||
/* Point is at infinity and will be zero when sampled, so early exit. */
|
||||
if (transformed_coordinates.z == 0.0) {
|
||||
imageStore(output_img, texel, vec4(0.0));
|
||||
return;
|
||||
}
|
||||
vec2 projected_coordinates = transformed_coordinates.xy / transformed_coordinates.z;
|
||||
|
||||
/* The derivatives of the projected coordinates with respect to x and y are the first and
|
||||
* second columns respectively, divided by the z projection factor as can be shown by
|
||||
* differentiating the above matrix multiplication with respect to x and y. Divide by the
|
||||
* output size since textureGrad assumes derivatives with respect to texel coordinates. */
|
||||
vec2 x_gradient = (homography_matrix[0].xy / transformed_coordinates.z) / output_size.x;
|
||||
vec2 y_gradient = (homography_matrix[1].xy / transformed_coordinates.z) / output_size.y;
|
||||
|
||||
vec4 sampled_color = textureGrad(input_tx, projected_coordinates, x_gradient, y_gradient);
|
||||
|
||||
/* Premultiply the mask value as an alpha. */
|
||||
vec4 plane_color = sampled_color * texture_load(mask_tx, texel).x;
|
||||
|
||||
imageStore(output_img, texel, plane_color);
|
||||
}
|
||||
@@ -12,16 +12,34 @@ COMPUTE_SOURCE("compositor_plane_deform_mask.glsl")
|
||||
DO_STATIC_COMPILATION()
|
||||
GPU_SHADER_CREATE_END()
|
||||
|
||||
GPU_SHADER_CREATE_INFO(compositor_plane_deform)
|
||||
GPU_SHADER_CREATE_INFO(compositor_plane_deform_shared)
|
||||
LOCAL_GROUP_SIZE(16, 16)
|
||||
PUSH_CONSTANT(MAT4, homography_matrix)
|
||||
SAMPLER(0, FLOAT_2D, input_tx)
|
||||
SAMPLER(1, FLOAT_2D, mask_tx)
|
||||
IMAGE(0, GPU_RGBA16F, WRITE, FLOAT_2D, output_img)
|
||||
GPU_SHADER_CREATE_END()
|
||||
|
||||
GPU_SHADER_CREATE_INFO(compositor_plane_deform)
|
||||
ADDITIONAL_INFO(compositor_plane_deform_shared)
|
||||
DEFINE_VALUE("SAMPLER_FUNCTION", "texture")
|
||||
COMPUTE_SOURCE("compositor_plane_deform.glsl")
|
||||
DO_STATIC_COMPILATION()
|
||||
GPU_SHADER_CREATE_END()
|
||||
|
||||
GPU_SHADER_CREATE_INFO(compositor_plane_deform_bicubic)
|
||||
ADDITIONAL_INFO(compositor_plane_deform_shared)
|
||||
DEFINE_VALUE("SAMPLER_FUNCTION", "texture_bicubic")
|
||||
COMPUTE_SOURCE("compositor_plane_deform.glsl")
|
||||
DO_STATIC_COMPILATION()
|
||||
GPU_SHADER_CREATE_END()
|
||||
|
||||
GPU_SHADER_CREATE_INFO(compositor_plane_deform_anisotropic)
|
||||
ADDITIONAL_INFO(compositor_plane_deform_shared)
|
||||
COMPUTE_SOURCE("compositor_plane_deform_anisotropic.glsl")
|
||||
DO_STATIC_COMPILATION()
|
||||
GPU_SHADER_CREATE_END()
|
||||
|
||||
GPU_SHADER_CREATE_INFO(compositor_plane_deform_motion_blur_mask)
|
||||
LOCAL_GROUP_SIZE(16, 16)
|
||||
PUSH_CONSTANT(INT, number_of_motion_blur_samples)
|
||||
|
||||
@@ -2931,6 +2931,14 @@ typedef enum CMPNodeInterpolation {
|
||||
CMP_NODE_INTERPOLATION_BICUBIC = 2,
|
||||
} CMPNodeInterpolation;
|
||||
|
||||
/* CornerPin node interpolation option. */
|
||||
typedef enum CMPNodeCornerPinInterpolation {
|
||||
CMP_NODE_CORNER_PIN_INTERPOLATION_NEAREST = 0,
|
||||
CMP_NODE_CORNER_PIN_INTERPOLATION_BILINEAR = 1,
|
||||
CMP_NODE_CORNER_PIN_INTERPOLATION_BICUBIC = 2,
|
||||
CMP_NODE_CORNER_PIN_INTERPOLATION_ANISOTROPIC = 3,
|
||||
} CMPNodeCornerPinInterpolation;
|
||||
|
||||
/* Stabilize 2D node. Stored in custom2. */
|
||||
typedef enum CMPNodeStabilizeInverse {
|
||||
CMP_NODE_STABILIZE_FLAG_INVERSE = 1,
|
||||
|
||||
@@ -9191,6 +9191,42 @@ static void def_cmp_colorcorrection(BlenderRNA * /*brna*/, StructRNA *srna)
|
||||
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
|
||||
}
|
||||
|
||||
static void def_cmp_cornerpin(BlenderRNA * /*brna*/, StructRNA *srna)
|
||||
{
|
||||
static const EnumPropertyItem cmp_cornerpin_interpolation_items[] = {
|
||||
{CMP_NODE_CORNER_PIN_INTERPOLATION_NEAREST,
|
||||
"NEAREST",
|
||||
0,
|
||||
"Nearest",
|
||||
"Use Nearest interpolation"},
|
||||
{CMP_NODE_CORNER_PIN_INTERPOLATION_BILINEAR,
|
||||
"BILINEAR",
|
||||
0,
|
||||
"Bilinear",
|
||||
"Use Bilinear interpolation"},
|
||||
{CMP_NODE_CORNER_PIN_INTERPOLATION_BICUBIC,
|
||||
"BICUBIC",
|
||||
0,
|
||||
"Bicubic",
|
||||
"Use Cubic B-Spline interpolation"},
|
||||
{CMP_NODE_CORNER_PIN_INTERPOLATION_ANISOTROPIC,
|
||||
"ANISOTROPIC",
|
||||
0,
|
||||
"Anisotropic",
|
||||
"Use Anisotropic interpolation"},
|
||||
{0, nullptr, 0, nullptr, nullptr},
|
||||
};
|
||||
|
||||
PropertyRNA *prop;
|
||||
|
||||
prop = RNA_def_property(srna, "interpolation", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, nullptr, "custom1");
|
||||
RNA_def_property_enum_items(prop, cmp_cornerpin_interpolation_items);
|
||||
RNA_def_property_enum_default(prop, CMP_NODE_CORNER_PIN_INTERPOLATION_ANISOTROPIC);
|
||||
RNA_def_property_ui_text(prop, "Interpolation", "Interpolation method");
|
||||
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
|
||||
}
|
||||
|
||||
static void def_cmp_viewer(BlenderRNA * /*brna*/, StructRNA *srna)
|
||||
{
|
||||
PropertyRNA *prop;
|
||||
@@ -12544,7 +12580,7 @@ static void rna_def_nodes(BlenderRNA *brna)
|
||||
define("CompositorNode", "CompositorNodeCombYUVA");
|
||||
define("CompositorNode", "CompositorNodeComposite", def_cmp_composite);
|
||||
define("CompositorNode", "CompositorNodeConvertColorSpace", def_cmp_convert_color_space);
|
||||
define("CompositorNode", "CompositorNodeCornerPin");
|
||||
define("CompositorNode", "CompositorNodeCornerPin", def_cmp_cornerpin);
|
||||
define("CompositorNode", "CompositorNodeCrop", def_cmp_crop);
|
||||
define("CompositorNode", "CompositorNodeCryptomatte", def_cmp_cryptomatte_legacy);
|
||||
define("CompositorNode", "CompositorNodeCryptomatteV2", def_cmp_cryptomatte);
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
#include "BKE_tracking.h"
|
||||
|
||||
#include "UI_interface.hh"
|
||||
|
||||
#include "COM_algorithm_smaa.hh"
|
||||
#include "COM_node_operation.hh"
|
||||
#include "COM_utilities.hh"
|
||||
@@ -53,6 +55,16 @@ static void cmp_node_cornerpin_declare(NodeDeclarationBuilder &b)
|
||||
b.add_output<decl::Float>("Plane");
|
||||
}
|
||||
|
||||
static void node_composit_init_cornerpin(bNodeTree * /*ntree*/, bNode *node)
|
||||
{
|
||||
node->custom1 = CMP_NODE_CORNER_PIN_INTERPOLATION_ANISOTROPIC;
|
||||
}
|
||||
|
||||
static void node_composit_buts_cornerpin(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
|
||||
{
|
||||
uiItemR(layout, ptr, "interpolation", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE);
|
||||
}
|
||||
|
||||
using namespace blender::compositor;
|
||||
|
||||
class CornerPinOperation : public NodeOperation {
|
||||
@@ -106,14 +118,23 @@ class CornerPinOperation : public NodeOperation {
|
||||
|
||||
void compute_plane_gpu(const float3x3 &homography_matrix, Result &plane_mask)
|
||||
{
|
||||
GPUShader *shader = context().get_shader("compositor_plane_deform");
|
||||
GPUShader *shader = this->context().get_shader(this->get_realization_shader_name());
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
GPU_shader_uniform_mat3_as_mat4(shader, "homography_matrix", homography_matrix.ptr());
|
||||
|
||||
Result &input_image = get_input("Image");
|
||||
GPU_texture_mipmap_mode(input_image, true, true);
|
||||
GPU_texture_anisotropic_filter(input_image, true);
|
||||
/* The texture sampler should use bilinear interpolation for both the bilinear and bicubic
|
||||
* cases, as the logic used by the bicubic realization shader expects textures to use bilinear
|
||||
* interpolation. */
|
||||
const CMPNodeCornerPinInterpolation interpolation = this->get_interpolation();
|
||||
const bool use_bilinear = ELEM(interpolation,
|
||||
CMP_NODE_CORNER_PIN_INTERPOLATION_BICUBIC,
|
||||
CMP_NODE_CORNER_PIN_INTERPOLATION_BILINEAR);
|
||||
const bool use_anisotropic = interpolation == CMP_NODE_CORNER_PIN_INTERPOLATION_ANISOTROPIC;
|
||||
GPU_texture_filter_mode(input_image, use_bilinear);
|
||||
GPU_texture_anisotropic_filter(input_image, use_anisotropic);
|
||||
GPU_texture_extend_mode(input_image, GPU_SAMPLER_EXTEND_MODE_EXTEND);
|
||||
input_image.bind_as_texture(shader, "input_tx");
|
||||
|
||||
@@ -150,17 +171,30 @@ class CornerPinOperation : public NodeOperation {
|
||||
output.store_pixel(texel, float4(0.0f));
|
||||
return;
|
||||
}
|
||||
|
||||
float2 projected_coordinates = transformed_coordinates.xy() / transformed_coordinates.z;
|
||||
|
||||
/* The derivatives of the projected coordinates with respect to x and y are the first and
|
||||
* second columns respectively, divided by the z projection factor as can be shown by
|
||||
* differentiating the above matrix multiplication with respect to x and y. Divide by the
|
||||
* output size since sample_ewa assumes derivatives with respect to texel coordinates. */
|
||||
float2 x_gradient = (homography_matrix[0].xy() / transformed_coordinates.z) / size.x;
|
||||
float2 y_gradient = (homography_matrix[1].xy() / transformed_coordinates.z) / size.y;
|
||||
|
||||
float4 sampled_color = input.sample_ewa_extended(
|
||||
projected_coordinates, x_gradient, y_gradient);
|
||||
float4 sampled_color;
|
||||
switch (this->get_interpolation()) {
|
||||
case CMP_NODE_CORNER_PIN_INTERPOLATION_BICUBIC:
|
||||
sampled_color = input.sample_cubic_extended(projected_coordinates);
|
||||
break;
|
||||
case CMP_NODE_CORNER_PIN_INTERPOLATION_BILINEAR:
|
||||
sampled_color = input.sample_bilinear_extended(projected_coordinates);
|
||||
break;
|
||||
case CMP_NODE_CORNER_PIN_INTERPOLATION_NEAREST:
|
||||
sampled_color = input.sample_nearest_extended(projected_coordinates);
|
||||
break;
|
||||
case CMP_NODE_CORNER_PIN_INTERPOLATION_ANISOTROPIC:
|
||||
/* The derivatives of the projected coordinates with respect to x and y are the first and
|
||||
* second columns respectively, divided by the z projection factor as can be shown by
|
||||
* differentiating the above matrix multiplication with respect to x and y. Divide by the
|
||||
* output size since sample_ewa assumes derivatives with respect to texel coordinates. */
|
||||
float2 x_gradient = (homography_matrix[0].xy() / transformed_coordinates.z) / size.x;
|
||||
float2 y_gradient = (homography_matrix[1].xy() / transformed_coordinates.z) / size.y;
|
||||
sampled_color = input.sample_ewa_extended(projected_coordinates, x_gradient, y_gradient);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Premultiply the mask value as an alpha. */
|
||||
float4 plane_color = sampled_color * plane_mask.load_pixel<float>(texel);
|
||||
@@ -250,6 +284,27 @@ class CornerPinOperation : public NodeOperation {
|
||||
BKE_tracking_homography_between_two_quads(corners, identity_corners, homography_matrix.ptr());
|
||||
return homography_matrix;
|
||||
}
|
||||
|
||||
const char *get_realization_shader_name() const
|
||||
{
|
||||
switch (this->get_interpolation()) {
|
||||
case CMP_NODE_CORNER_PIN_INTERPOLATION_NEAREST:
|
||||
case CMP_NODE_CORNER_PIN_INTERPOLATION_BILINEAR:
|
||||
return "compositor_plane_deform";
|
||||
case CMP_NODE_CORNER_PIN_INTERPOLATION_BICUBIC:
|
||||
return "compositor_plane_deform_bicubic";
|
||||
case CMP_NODE_CORNER_PIN_INTERPOLATION_ANISOTROPIC:
|
||||
return "compositor_plane_deform_anisotropic";
|
||||
}
|
||||
|
||||
BLI_assert_unreachable();
|
||||
return "compositor_plane_deform_anisotropic";
|
||||
}
|
||||
|
||||
CMPNodeCornerPinInterpolation get_interpolation() const
|
||||
{
|
||||
return static_cast<CMPNodeCornerPinInterpolation>(bnode().custom1);
|
||||
}
|
||||
};
|
||||
|
||||
static NodeOperation *get_compositor_operation(Context &context, DNode node)
|
||||
@@ -271,6 +326,8 @@ void register_node_type_cmp_cornerpin()
|
||||
ntype.enum_name_legacy = "CORNERPIN";
|
||||
ntype.nclass = NODE_CLASS_DISTORT;
|
||||
ntype.declare = file_ns::cmp_node_cornerpin_declare;
|
||||
ntype.initfunc = file_ns::node_composit_init_cornerpin;
|
||||
ntype.draw_buttons = file_ns::node_composit_buts_cornerpin;
|
||||
ntype.get_compositor_operation = file_ns::get_compositor_operation;
|
||||
|
||||
blender::bke::node_register_type(ntype);
|
||||
|
||||
Reference in New Issue
Block a user