Blender V4.3
node_composite_cornerpin.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2013 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include "BLI_math_geom.h"
12
13#include "GPU_shader.hh"
14#include "GPU_texture.hh"
15
16#include "BKE_tracking.h"
17
18#include "COM_algorithm_smaa.hh"
19#include "COM_node_operation.hh"
20#include "COM_utilities.hh"
21
23
25
27{
28 b.add_input<decl::Color>("Image")
29 .default_value({1.0f, 1.0f, 1.0f, 1.0f})
30 .compositor_domain_priority(0);
31 b.add_input<decl::Vector>("Upper Left")
32 .default_value({0.0f, 1.0f, 0.0f})
33 .min(0.0f)
34 .max(1.0f)
36 b.add_input<decl::Vector>("Upper Right")
37 .default_value({1.0f, 1.0f, 0.0f})
38 .min(0.0f)
39 .max(1.0f)
41 b.add_input<decl::Vector>("Lower Left")
42 .default_value({0.0f, 0.0f, 0.0f})
43 .min(0.0f)
44 .max(1.0f)
46 b.add_input<decl::Vector>("Lower Right")
47 .default_value({1.0f, 0.0f, 0.0f})
48 .min(0.0f)
49 .max(1.0f)
51 b.add_output<decl::Color>("Image");
52 b.add_output<decl::Float>("Plane");
53}
54
55using namespace blender::realtime_compositor;
56
58 public:
60
61 void execute() override
62 {
63 const float3x3 homography_matrix = compute_homography_matrix();
64
65 Result &input_image = get_input("Image");
66 Result &output_image = get_result("Image");
67 Result &output_mask = get_result("Plane");
68 if (input_image.is_single_value() || homography_matrix == float3x3::identity()) {
69 if (output_image.should_compute()) {
70 input_image.pass_through(output_image);
71 }
72 if (output_mask.should_compute()) {
73 output_mask.allocate_single_value();
74 output_mask.set_float_value(1.0f);
75 }
76 return;
77 }
78
79 Result plane_mask = compute_plane_mask(homography_matrix);
80 Result anti_aliased_plane_mask = context().create_result(ResultType::Float);
81 smaa(context(), plane_mask, anti_aliased_plane_mask);
82 plane_mask.release();
83
84 if (output_image.should_compute()) {
85 compute_plane(homography_matrix, anti_aliased_plane_mask);
86 }
87
88 if (output_mask.should_compute()) {
89 output_mask.steal_data(anti_aliased_plane_mask);
90 }
91 else {
92 anti_aliased_plane_mask.release();
93 }
94 }
95
96 void compute_plane(const float3x3 &homography_matrix, Result &plane_mask)
97 {
98 GPUShader *shader = context().get_shader("compositor_plane_deform");
99 GPU_shader_bind(shader);
100
101 GPU_shader_uniform_mat3_as_mat4(shader, "homography_matrix", homography_matrix.ptr());
102
103 Result &input_image = get_input("Image");
104 GPU_texture_mipmap_mode(input_image, true, true);
105 GPU_texture_anisotropic_filter(input_image, true);
107 input_image.bind_as_texture(shader, "input_tx");
108
109 plane_mask.bind_as_texture(shader, "mask_tx");
110
111 const Domain domain = compute_domain();
112 Result &output_image = get_result("Image");
113 output_image.allocate_texture(domain);
114 output_image.bind_as_image(shader, "output_img");
115
116 compute_dispatch_threads_at_least(shader, domain.size);
117
118 input_image.unbind_as_texture();
119 plane_mask.unbind_as_texture();
120 output_image.unbind_as_image();
122 }
123
124 Result compute_plane_mask(const float3x3 &homography_matrix)
125 {
126 GPUShader *shader = context().get_shader("compositor_plane_deform_mask");
127 GPU_shader_bind(shader);
128
129 GPU_shader_uniform_mat3_as_mat4(shader, "homography_matrix", homography_matrix.ptr());
130
131 const Domain domain = compute_domain();
132 Result plane_mask = context().create_result(ResultType::Float);
133 plane_mask.allocate_texture(domain);
134 plane_mask.bind_as_image(shader, "mask_img");
135
136 compute_dispatch_threads_at_least(shader, domain.size);
137
138 plane_mask.unbind_as_image();
140
141 return plane_mask;
142 }
143
145 {
146 float2 lower_left = get_input("Lower Left").get_vector_value_default(float4(0.0f)).xy();
147 float2 lower_right = get_input("Lower Right").get_vector_value_default(float4(0.0f)).xy();
148 float2 upper_right = get_input("Upper Right").get_vector_value_default(float4(0.0f)).xy();
149 float2 upper_left = get_input("Upper Left").get_vector_value_default(float4(0.0f)).xy();
150
151 /* The inputs are invalid because the plane is not convex, fallback to an identity operation in
152 * that case. */
153 if (!is_quad_convex_v2(lower_left, lower_right, upper_right, upper_left)) {
154 return float3x3::identity();
155 }
156
157 /* Compute a 2D projection matrix that projects from the corners of the image in normalized
158 * coordinates into the corners of the input plane. */
159 float3x3 homography_matrix;
160 float corners[4][2] = {{lower_left.x, lower_left.y},
161 {lower_right.x, lower_right.y},
162 {upper_right.x, upper_right.y},
163 {upper_left.x, upper_left.y}};
164 float identity_corners[4][2] = {{0.0f, 0.0f}, {1.0f, 0.0f}, {1.0f, 1.0f}, {0.0f, 1.0f}};
165 BKE_tracking_homography_between_two_quads(corners, identity_corners, homography_matrix.ptr());
166 return homography_matrix;
167 }
168};
169
171{
172 return new CornerPinOperation(context, node);
173}
174
175} // namespace blender::nodes::node_composite_cornerpin_cc
176
178{
180
181 static blender::bke::bNodeType ntype;
182
183 cmp_node_type_base(&ntype, CMP_NODE_CORNERPIN, "Corner Pin", NODE_CLASS_DISTORT);
184 ntype.declare = file_ns::cmp_node_cornerpin_declare;
185 ntype.get_compositor_operation = file_ns::get_compositor_operation;
186
188}
#define NODE_CLASS_DISTORT
Definition BKE_node.hh:412
void BKE_tracking_homography_between_two_quads(float reference_corners[4][2], float corners[4][2], float H[3][3])
bool is_quad_convex_v2(const float v1[2], const float v2[2], const float v3[2], const float v4[2])
void GPU_shader_uniform_mat3_as_mat4(GPUShader *sh, const char *name, const float data[3][3])
void GPU_shader_bind(GPUShader *shader)
void GPU_shader_unbind()
void GPU_texture_anisotropic_filter(GPUTexture *texture, bool use_aniso)
void GPU_texture_extend_mode(GPUTexture *texture, GPUSamplerExtendMode extend_mode)
@ GPU_SAMPLER_EXTEND_MODE_EXTEND
void GPU_texture_mipmap_mode(GPUTexture *texture, bool use_mipmap, bool use_filter)
struct GPUShader GPUShader
void compute_plane(const float3x3 &homography_matrix, Result &plane_mask)
GPUShader * get_shader(const char *info_name, ResultPrecision precision)
Result create_result(ResultType type, ResultPrecision precision)
NodeOperation(Context &context, DNode node)
Result & get_input(StringRef identifier) const
Definition operation.cc:144
Result & get_result(StringRef identifier)
Definition operation.cc:46
void bind_as_image(GPUShader *shader, const char *image_name, bool read=false) const
Definition result.cc:264
void pass_through(Result &target)
Definition result.cc:289
float4 get_vector_value_default(const float4 &default_value) const
Definition result.cc:422
void set_float_value(float value)
Definition result.cc:467
void allocate_texture(Domain domain, bool from_pool=true)
Definition result.cc:204
void steal_data(Result &source)
Definition result.cc:304
void bind_as_texture(GPUShader *shader, const char *texture_name) const
Definition result.cc:253
local_group_size(16, 16) .push_constant(Type b
void node_register_type(bNodeType *ntype)
Definition node.cc:1708
static NodeOperation * get_compositor_operation(Context &context, DNode node)
static void cmp_node_cornerpin_declare(NodeDeclarationBuilder &b)
void smaa(Context &context, Result &input, Result &output, float threshold=0.1f, float local_contrast_adaptation_factor=2.0f, int corner_rounding=25)
Definition smaa.cc:160
void compute_dispatch_threads_at_least(GPUShader *shader, int2 threads_range, int2 local_size=int2(16))
Definition utilities.cc:131
VecBase< float, 4 > float4
void register_node_type_cmp_cornerpin()
void cmp_node_type_base(blender::bke::bNodeType *ntype, int type, const char *name, short nclass)
#define min(a, b)
Definition sort.c:32
const c_style_mat & ptr() const
VecBase< T, 2 > xy() const
Defines a node type.
Definition BKE_node.hh:218
NodeGetCompositorOperationFunction get_compositor_operation
Definition BKE_node.hh:324
NodeDeclareFunction declare
Definition BKE_node.hh:347