Realtime Compositor: Implement Corner Pin node
This patch implements the Corner Pin node for the realtime compositor. This is different from the existing compositor in that single value inputs produce single value outputs, instead of assuming the size of the render. Pull Request: https://projects.blender.org/blender/blender/pulls/107363
This commit is contained in:
@@ -129,6 +129,7 @@ set(GLSL_SRC
|
||||
shaders/compositor_morphological_step.glsl
|
||||
shaders/compositor_normalize.glsl
|
||||
shaders/compositor_parallel_reduction.glsl
|
||||
shaders/compositor_plane_deform.glsl
|
||||
shaders/compositor_projector_lens_distortion.glsl
|
||||
shaders/compositor_read_pass.glsl
|
||||
shaders/compositor_realize_on_domain.glsl
|
||||
@@ -227,6 +228,7 @@ set(SRC_SHADER_CREATE_INFOS
|
||||
shaders/infos/compositor_morphological_step_info.hh
|
||||
shaders/infos/compositor_normalize_info.hh
|
||||
shaders/infos/compositor_parallel_reduction_info.hh
|
||||
shaders/infos/compositor_plane_deform_info.hh
|
||||
shaders/infos/compositor_projector_lens_distortion_info.hh
|
||||
shaders/infos/compositor_read_pass_info.hh
|
||||
shaders/infos/compositor_realize_on_domain_info.hh
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
#pragma BLENDER_REQUIRE(gpu_shader_compositor_texture_utilities.glsl)
|
||||
|
||||
void main()
|
||||
{
|
||||
ivec2 texel = ivec2(gl_GlobalInvocationID.xy);
|
||||
|
||||
/* Add 0.5 to evaluate the input sampler at the center of the pixel and divide by the image size
|
||||
* to get the coordinates into the sampler's expected [0, 1] range. */
|
||||
vec2 coordinates = (vec2(texel) + vec2(0.5)) / vec2(texture_size(input_tx));
|
||||
|
||||
vec3 transformed_coordinates = mat3(homography_matrix) * vec3(coordinates, 1.0);
|
||||
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. */
|
||||
vec2 x_gradient = homography_matrix[0].xy / transformed_coordinates.z;
|
||||
vec2 y_gradient = homography_matrix[1].xy / transformed_coordinates.z;
|
||||
|
||||
vec4 sampled_color = textureGrad(input_tx, projected_coordinates, x_gradient, y_gradient);
|
||||
|
||||
imageStore(output_img, texel, sampled_color);
|
||||
imageStore(mask_img, texel, sampled_color.aaaa);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "gpu_shader_create_info.hh"
|
||||
|
||||
GPU_SHADER_CREATE_INFO(compositor_plane_deform)
|
||||
.local_group_size(16, 16)
|
||||
.push_constant(Type::MAT4, "homography_matrix")
|
||||
.sampler(0, ImageType::FLOAT_2D, "input_tx")
|
||||
.image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img")
|
||||
.image(1, GPU_R16F, Qualifier::WRITE, ImageType::FLOAT_2D, "mask_img")
|
||||
.compute_source("compositor_plane_deform.glsl")
|
||||
.do_static_compilation(true);
|
||||
@@ -5,9 +5,19 @@
|
||||
* \ingroup cmpnodes
|
||||
*/
|
||||
|
||||
#include "BLI_math_geom.h"
|
||||
#include "BLI_math_matrix_types.hh"
|
||||
#include "BLI_math_vector_types.hh"
|
||||
|
||||
#include "BLT_translation.h"
|
||||
|
||||
#include "GPU_shader.h"
|
||||
#include "GPU_texture.h"
|
||||
|
||||
#include "BKE_tracking.h"
|
||||
|
||||
#include "COM_node_operation.hh"
|
||||
#include "COM_utilities.hh"
|
||||
|
||||
#include "node_composite_util.hh"
|
||||
|
||||
@@ -15,23 +25,29 @@ namespace blender::nodes::node_composite_cornerpin_cc {
|
||||
|
||||
static void cmp_node_cornerpin_declare(NodeDeclarationBuilder &b)
|
||||
{
|
||||
b.add_input<decl::Color>(N_("Image")).default_value({1.0f, 1.0f, 1.0f, 1.0f});
|
||||
b.add_input<decl::Color>(N_("Image"))
|
||||
.default_value({1.0f, 1.0f, 1.0f, 1.0f})
|
||||
.compositor_domain_priority(0);
|
||||
b.add_input<decl::Vector>(N_("Upper Left"))
|
||||
.default_value({0.0f, 1.0f, 0.0f})
|
||||
.min(0.0f)
|
||||
.max(1.0f);
|
||||
.max(1.0f)
|
||||
.compositor_expects_single_value();
|
||||
b.add_input<decl::Vector>(N_("Upper Right"))
|
||||
.default_value({1.0f, 1.0f, 0.0f})
|
||||
.min(0.0f)
|
||||
.max(1.0f);
|
||||
.max(1.0f)
|
||||
.compositor_expects_single_value();
|
||||
b.add_input<decl::Vector>(N_("Lower Left"))
|
||||
.default_value({0.0f, 0.0f, 0.0f})
|
||||
.min(0.0f)
|
||||
.max(1.0f);
|
||||
.max(1.0f)
|
||||
.compositor_expects_single_value();
|
||||
b.add_input<decl::Vector>(N_("Lower Right"))
|
||||
.default_value({1.0f, 0.0f, 0.0f})
|
||||
.min(0.0f)
|
||||
.max(1.0f);
|
||||
.max(1.0f)
|
||||
.compositor_expects_single_value();
|
||||
b.add_output<decl::Color>(N_("Image"));
|
||||
b.add_output<decl::Float>(N_("Plane"));
|
||||
}
|
||||
@@ -44,9 +60,70 @@ class CornerPinOperation : public NodeOperation {
|
||||
|
||||
void execute() override
|
||||
{
|
||||
get_input("Image").pass_through(get_result("Image"));
|
||||
get_result("Plane").allocate_invalid();
|
||||
context().set_info_message("Viewport compositor setup not fully supported");
|
||||
const float3x3 homography_matrix = compute_homography_matrix();
|
||||
|
||||
Result &input_image = get_input("Image");
|
||||
Result &output_image = get_result("Image");
|
||||
Result &output_mask = get_result("Plane");
|
||||
if (input_image.is_single_value() || homography_matrix == float3x3::identity()) {
|
||||
if (output_image.should_compute()) {
|
||||
input_image.pass_through(output_image);
|
||||
}
|
||||
if (output_mask.should_compute()) {
|
||||
output_mask.allocate_single_value();
|
||||
output_mask.set_float_value(1.0f);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
GPUShader *shader = shader_manager().get("compositor_plane_deform");
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
GPU_shader_uniform_mat3_as_mat4(shader, "homography_matrix", homography_matrix.ptr());
|
||||
|
||||
GPU_texture_mipmap_mode(input_image.texture(), true, true);
|
||||
GPU_texture_anisotropic_filter(input_image.texture(), true);
|
||||
GPU_texture_extend_mode(input_image.texture(), GPU_SAMPLER_EXTEND_MODE_CLAMP_TO_BORDER);
|
||||
input_image.bind_as_texture(shader, "input_tx");
|
||||
|
||||
const Domain domain = compute_domain();
|
||||
output_image.allocate_texture(domain);
|
||||
output_image.bind_as_image(shader, "output_img");
|
||||
|
||||
output_mask.allocate_texture(domain);
|
||||
output_mask.bind_as_image(shader, "mask_img");
|
||||
|
||||
compute_dispatch_threads_at_least(shader, domain.size);
|
||||
|
||||
input_image.unbind_as_texture();
|
||||
output_image.unbind_as_image();
|
||||
output_mask.unbind_as_image();
|
||||
GPU_shader_unbind();
|
||||
}
|
||||
|
||||
float3x3 compute_homography_matrix()
|
||||
{
|
||||
float2 lower_left = get_input("Lower Left").get_vector_value_default(float4(0.0f)).xy();
|
||||
float2 lower_right = get_input("Lower Right").get_vector_value_default(float4(0.0f)).xy();
|
||||
float2 upper_right = get_input("Upper Right").get_vector_value_default(float4(0.0f)).xy();
|
||||
float2 upper_left = get_input("Upper Left").get_vector_value_default(float4(0.0f)).xy();
|
||||
|
||||
/* The inputs are invalid because the plane is not convex, fallback to an identity operation in
|
||||
* that case. */
|
||||
if (!is_quad_convex_v2(lower_left, lower_right, upper_right, upper_left)) {
|
||||
return float3x3::identity();
|
||||
}
|
||||
|
||||
/* Compute a 2D projection matrix that projects from the corners of the image in normalized
|
||||
* coordinates into the corners of the input plane. */
|
||||
float3x3 homography_matrix;
|
||||
float corners[4][2] = {{lower_left.x, lower_left.y},
|
||||
{lower_right.x, lower_right.y},
|
||||
{upper_right.x, upper_right.y},
|
||||
{upper_left.x, upper_left.y}};
|
||||
float identity_corners[4][2] = {{0.0f, 0.0f}, {1.0f, 0.0f}, {1.0f, 1.0f}, {0.0f, 1.0f}};
|
||||
BKE_tracking_homography_between_two_quads(corners, identity_corners, homography_matrix.ptr());
|
||||
return homography_matrix;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -66,8 +143,6 @@ void register_node_type_cmp_cornerpin()
|
||||
cmp_node_type_base(&ntype, CMP_NODE_CORNERPIN, "Corner Pin", NODE_CLASS_DISTORT);
|
||||
ntype.declare = file_ns::cmp_node_cornerpin_declare;
|
||||
ntype.get_compositor_operation = file_ns::get_compositor_operation;
|
||||
ntype.realtime_compositor_unsupported_message = N_(
|
||||
"Node not supported in the Viewport compositor");
|
||||
|
||||
nodeRegisterType(&ntype);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user