From 6a22de3927a7596d110eed1b72b377862d0dd92e Mon Sep 17 00:00:00 2001 From: Omar Emara Date: Thu, 7 Apr 2022 10:25:43 +0200 Subject: Viewport Compositor: Add domain repetition support --- source/blender/nodes/NOD_compositor_execute.hh | 50 ++++++++++++++++------ .../nodes/composite/nodes/node_composite_rotate.cc | 2 +- .../composite/nodes/node_composite_transform.cc | 2 +- .../nodes/intern/node_compositor_execute.cc | 25 +++++++---- 4 files changed, 56 insertions(+), 23 deletions(-) diff --git a/source/blender/nodes/NOD_compositor_execute.hh b/source/blender/nodes/NOD_compositor_execute.hh index 5709dc9b4cf..4463db979cc 100644 --- a/source/blender/nodes/NOD_compositor_execute.hh +++ b/source/blender/nodes/NOD_compositor_execute.hh @@ -110,17 +110,41 @@ class Context { }; /* -------------------------------------------------------------------- - * Domain. + * Realization Options. */ -/* Possible interpolations to use when realizing an input of some domain on another domain. See the - * Domain class for more information. */ +/* Possible interpolations to use when realizing an input result of some domain on another domain. + * See the RealizationOptions class for more information. */ enum class Interpolation : uint8_t { Nearest, Bilinear, Bicubic, }; +/* The options that describe how an input result prefer to be realized on some other domain. This + * is used by the RealizeOnDomainProcessorOperation to identify the appropriate method of + * realization. See the Domain class for more information. */ +class RealizationOptions { + public: + /* The interpolation method that should be used when performing realization. Since realizing a + * result involves projecting it on a different domain, which in turn, involves sampling the + * result at arbitrary locations, the interpolation identifies the method used for computing the + * value at those arbitrary locations. */ + Interpolation interpolation = Interpolation::Nearest; + /* If true, the result will be repeated infinitely along the horizontal axis when realizing the + * result. If false, regions outside of bounds of the result along the horizontal axis will be + * filled with zeros. */ + bool repeat_x = false; + /* If true, the result will be repeated infinitely along the vertical axis when realizing the + * result. If false, regions outside of bounds of the result along the vertical axis will be + * filled with zeros. */ + bool repeat_y = false; +}; + +/* -------------------------------------------------------------------- + * Domain. + */ + /* A domain is a rectangular area of a certain size in pixels that is transformed by a certain * transformation in pixel space relative to some reference space. * @@ -138,10 +162,11 @@ enum class Interpolation : uint8_t { * RealizeOnDomainProcessorOperation, except inputs whose descriptor sets skip_realization or * expects_single_value, see InputDescriptor for more information. The realization process simply * projects the input domain on the operation domain, copies the area of input that intersects the - * operation domain, and fill the rest with zeros. The realization happens using the interpolation - * method defined set in the realization_interpolation member. This process is illustrated below. - * It follows that operations should expect all their inputs to have the same domain and - * consequently size, except for inputs that explicitly skip realization. + * operation domain, and fill the rest with zeros or repetitions of the input domain; depending on + * the realization_options, see the RealizationOptions class for more information. This process is + * illustrated below, assuming no repetition in either directions. It follows that operations + * should expect all their inputs to have the same domain and consequently size, except for inputs + * that explicitly skip realization. * * Realized Result * +-------------+ +-------------+ @@ -187,9 +212,9 @@ class Domain { /* The 2D transformation of the domain defining its translation in pixels, rotation, and scale in * 2D space. */ Transformation2D transformation; - /* The interpolation method that should be used when realizing the input whose domain is this - * one. */ - Interpolation realization_interpolation = Interpolation::Nearest; + /* The options that describe how this domain prefer to be realized on some other domain. See the + * RealizationOptions for more information. */ + RealizationOptions realization_options; public: /* A size only constructor that sets the transformation to identity. */ @@ -302,8 +327,9 @@ class Result { * transformation by the current transformation of the domain of the result. */ void transform(const Transformation2D &transformation); - /* Set the interpolation method that will be used when realizing this result if needed. */ - void set_realization_interpolation(Interpolation interpolation); + /* Get a reference to the realization options of this result. See the RealizationOptions class + * for more information. */ + RealizationOptions &get_realization_options(); /* If the result is a single value result of type float, return its float value. Otherwise, an * uninitialized value is returned. */ diff --git a/source/blender/nodes/composite/nodes/node_composite_rotate.cc b/source/blender/nodes/composite/nodes/node_composite_rotate.cc index efa74b7fe72..f261acbaaf3 100644 --- a/source/blender/nodes/composite/nodes/node_composite_rotate.cc +++ b/source/blender/nodes/composite/nodes/node_composite_rotate.cc @@ -76,7 +76,7 @@ class RotateOperation : public NodeOperation { const Transformation2D transformation = Transformation2D::from_rotation(rotation); result.transform(transformation); - result.set_realization_interpolation(get_interpolation()); + result.get_realization_options().interpolation = get_interpolation(); } Interpolation get_interpolation() diff --git a/source/blender/nodes/composite/nodes/node_composite_transform.cc b/source/blender/nodes/composite/nodes/node_composite_transform.cc index 001ad932fbc..befc44f4676 100644 --- a/source/blender/nodes/composite/nodes/node_composite_transform.cc +++ b/source/blender/nodes/composite/nodes/node_composite_transform.cc @@ -91,7 +91,7 @@ class TransformOperation : public NodeOperation { translation, rotation, scale); result.transform(transformation); - result.set_realization_interpolation(get_interpolation()); + result.get_realization_options().interpolation = get_interpolation(); } Interpolation get_interpolation() diff --git a/source/blender/nodes/intern/node_compositor_execute.cc b/source/blender/nodes/intern/node_compositor_execute.cc index f2753e3e9fb..3d1cb671486 100644 --- a/source/blender/nodes/intern/node_compositor_execute.cc +++ b/source/blender/nodes/intern/node_compositor_execute.cc @@ -129,8 +129,8 @@ Domain Domain::identity() return Domain(int2(1), Transformation2D::identity()); } -/* Only compare the size and transformation members, as other members only describe the method of - * realization on another domain, which is not technically a proprty of the domain. */ +/* Do not compare realization_options as it only describe the method of realization on another + * domain, which is not technically a proprty of the domain itself. */ bool operator==(const Domain &a, const Domain &b) { return a.size == b.size && a.transformation == b.transformation; @@ -225,9 +225,9 @@ void Result::transform(const Transformation2D &transformation) domain_.transform(transformation); } -void Result::set_realization_interpolation(Interpolation interpolation) +RealizationOptions &Result::get_realization_options() { - domain_.realization_interpolation = interpolation; + return domain_.realization_options; } float Result::get_float_value() const @@ -988,13 +988,20 @@ void RealizeOnDomainProcessorOperation::execute() /* Set the inverse of the transform to the shader. */ GPU_shader_uniform_mat3(shader, "inverse_transformation", inverse_transformation.matrix()); - /* Make out-of-bound texture access return zero. */ - GPU_texture_wrap_mode(input.texture(), false, false); - - /* Set the approperiate sampler interpolation. */ - const bool use_bilinear = input.domain().realization_interpolation != Interpolation::Nearest; + /* 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 bool use_bilinear = ELEM(input.get_realization_options().interpolation, + Interpolation::Bilinear, + Interpolation::Bicubic); GPU_texture_filter_mode(input.texture(), use_bilinear); + /* Make out-of-bound texture access return zero by clamping to border color. And make texture + * wrap appropriately if the input repeats. */ + const bool repeats = input.get_realization_options().repeat_x || + input.get_realization_options().repeat_y; + GPU_texture_wrap_mode(input.texture(), repeats, false); + input.bind_as_texture(shader, "input_sampler"); result.bind_as_image(shader, "domain"); -- cgit v1.2.3