31 .default_value({1.0f, 1.0f, 1.0f, 1.0f})
32 .compositor_domain_priority(0);
37 .compositor_expects_single_value();
68 flooded_boundary, filled_region, distance_to_boundary, smoothing_radius);
87 if (this->
context().use_gpu()) {
101 input.bind_as_texture(shader,
"input_tx");
110 input.unbind_as_texture();
114 return inpainting_boundary;
135 bool has_transparent_neighbors = false;
136 for (int j = -1; j <= 1; j++) {
137 for (int i = -1; i <= 1; i++) {
138 int2 offset = int2(i, j);
141 if (offset != int2(0)) {
142 if (input.load_pixel_extended<float4>(texel + offset).w < 1.0f) {
143 has_transparent_neighbors = true;
151 bool is_opaque =
input.load_pixel<
float4>(texel).w == 1.0f;
152 bool is_boundary_pixel = is_opaque && has_transparent_neighbors;
167 Result &distance_to_boundary,
170 if (this->
context().use_gpu()) {
172 flooded_boundary, filled_region, distance_to_boundary, smoothing_radius);
176 flooded_boundary, filled_region, distance_to_boundary, smoothing_radius);
182 Result &distance_to_boundary,
185 GPUShader *shader =
context().get_shader(
"compositor_inpaint_fill_region");
191 input.bind_as_texture(shader,
"input_tx");
200 distance_to_boundary.
bind_as_image(shader,
"distance_to_boundary_img");
203 smoothing_radius.
bind_as_image(shader,
"smoothing_radius_img");
207 input.unbind_as_texture();
217 Result &distance_to_boundary_image,
218 Result &smoothing_radius_image)
233 float4 color = input.load_pixel<float4>(texel);
236 if (color.w == 1.0f) {
237 filled_region.store_pixel(texel, color);
238 smoothing_radius_image.store_pixel(texel, 0.0f);
239 distance_to_boundary_image.store_pixel(texel, 0.0f);
245 distance_to_boundary_image.
store_pixel(texel, distance_to_boundary);
255 float blur_window_size =
math::min(
float(max_distance), distance_to_boundary) /
257 bool skip_smoothing = distance_to_boundary > (max_distance * 2.0f);
258 float smoothing_radius = skip_smoothing ? 0.0f : blur_window_size;
259 smoothing_radius_image.
store_pixel(texel, smoothing_radius);
271 const Result &distance_to_boundary)
273 if (this->
context().use_gpu()) {
282 const Result &distance_to_boundary)
284 GPUShader *shader =
context().get_shader(
"compositor_inpaint_compute_region");
290 input.bind_as_texture(shader,
"input_tx");
293 distance_to_boundary.
bind_as_texture(shader,
"distance_to_boundary_tx");
297 output.allocate_texture(domain);
298 output.bind_as_image(shader,
"output_img");
302 input.unbind_as_texture();
310 const Result &distance_to_boundary_image)
318 output.allocate_texture(domain);
321 float4 color = input.load_pixel<float4>(texel);
324 if (color.w == 1.0f) {
325 output.store_pixel(texel, color);
329 float distance_to_boundary = distance_to_boundary_image.
load_pixel<
float>(texel);
333 if (distance_to_boundary > max_distance) {
367 ntype.
ui_description =
"Extend borders of an image into transparent or masked regions";
370 ntype.
declare = file_ns::cmp_node_inpaint_declare;
#define NODE_CLASS_OP_FILTER
void GPU_shader_uniform_1i(GPUShader *sh, const char *name, int value)
void GPU_shader_bind(GPUShader *shader, const blender::gpu::shader::SpecializationConstants *constants_state=nullptr)
#define NOD_REGISTER_NODE(REGISTER_FUNC)
Result create_result(ResultType type, ResultPrecision precision)
GPUShader * get_shader(const char *info_name, ResultPrecision precision)
NodeOperation(Context &context, DNode node)
Result & get_result(StringRef identifier)
Context & context() const
Result & get_input(StringRef identifier) const
virtual Domain compute_domain()
void share_data(const Result &source)
void allocate_texture(Domain domain, bool from_pool=true)
void store_pixel(const int2 &texel, const T &pixel_value)
void unbind_as_texture() const
void bind_as_texture(GPUShader *shader, const char *texture_name) const
T load_pixel(const int2 &texel) const
void bind_as_image(GPUShader *shader, const char *image_name, bool read=false) const
void unbind_as_image() const
bool is_single_value() const
void fill_inpainting_region(const Result &flooded_boundary, Result &filled_region, Result &distance_to_boundary, Result &smoothing_radius)
Result compute_inpainting_boundary()
void compute_inpainting_region_gpu(const Result &inpainted_region, const Result &distance_to_boundary)
void compute_inpainting_region_cpu(const Result &inpainted_region, const Result &distance_to_boundary_image)
void fill_inpainting_region_cpu(const Result &flooded_boundary, Result &filled_region, Result &distance_to_boundary_image, Result &smoothing_radius_image)
void fill_inpainting_region_gpu(const Result &flooded_boundary, Result &filled_region, Result &distance_to_boundary, Result &smoothing_radius)
Result compute_inpainting_boundary_gpu()
void compute_inpainting_region(const Result &inpainted_region, const Result &distance_to_boundary)
NodeOperation(Context &context, DNode node)
Result compute_inpainting_boundary_cpu()
VecBase< float, 4 > float4
void node_register_type(bNodeType &ntype)
void compute_dispatch_threads_at_least(GPUShader *shader, int2 threads_range, int2 local_size=int2(16))
int2 initialize_jump_flooding_value(const int2 &texel, const bool is_seed)
void symmetric_separable_blur_variable_size(Context &context, const Result &input, const Result &radius, Result &output, const int weights_resolution=128, const int filter_type=R_FILTER_GAUSS)
void jump_flooding(Context &context, Result &input, Result &output)
void parallel_for(const int2 range, const Function &function)
T distance(const T &a, const T &b)
T min(const T &a, const T &b)
T interpolate(const T &a, const T &b, const FactorT &t)
T max(const T &a, const T &b)
static void cmp_node_inpaint_declare(NodeDeclarationBuilder &b)
static NodeOperation * get_compositor_operation(Context &context, DNode node)
VecBase< float, 4 > float4
VecBase< int32_t, 2 > int2
VecBase< float, 2 > float2
static void register_node_type_cmp_inpaint()
void cmp_node_type_base(blender::bke::bNodeType *ntype, std::string idname, const std::optional< int16_t > legacy_type)
VecBase< T, 3 > xyz() const
std::string ui_description
NodeGetCompositorOperationFunction get_compositor_operation
const char * enum_name_legacy
NodeDeclareFunction declare
static pxr::UsdShadeInput get_input(const pxr::UsdShadeShader &usd_shader, const pxr::TfToken &input_name)