Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source/blender/blenlib/BLI_float3x3.hh16
-rw-r--r--source/blender/blenlib/BLI_math_matrix.h2
-rw-r--r--source/blender/blenlib/intern/math_matrix.c6
-rw-r--r--source/blender/blenlib/tests/BLI_float3x3_test.cc16
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_pixelate.cc29
5 files changed, 69 insertions, 0 deletions
diff --git a/source/blender/blenlib/BLI_float3x3.hh b/source/blender/blenlib/BLI_float3x3.hh
index 6a9e7dd04f0..178973c155d 100644
--- a/source/blender/blenlib/BLI_float3x3.hh
+++ b/source/blender/blenlib/BLI_float3x3.hh
@@ -63,6 +63,15 @@ struct float3x3 {
return result;
}
+ static float3x3 from_scale(const float2 scale)
+ {
+ float3x3 result = zero();
+ result.values[0][0] = scale.x;
+ result.values[1][1] = scale.y;
+ result.values[2][2] = 1.0f;
+ return result;
+ }
+
static float3x3 from_translation_rotation_scale(const float2 translation,
float rotation,
const float2 scale)
@@ -190,6 +199,13 @@ struct float3x3 {
return result;
}
+ float2 scale_2d() const
+ {
+ float2 scale;
+ mat3_to_size_2d(scale, values);
+ return scale;
+ }
+
friend bool operator==(const float3x3 &a, const float3x3 &b)
{
return equals_m3m3(a.values, b.values);
diff --git a/source/blender/blenlib/BLI_math_matrix.h b/source/blender/blenlib/BLI_math_matrix.h
index 467e6db4805..19943614881 100644
--- a/source/blender/blenlib/BLI_math_matrix.h
+++ b/source/blender/blenlib/BLI_math_matrix.h
@@ -410,6 +410,8 @@ float mat4_to_xy_scale(const float mat[4][4]);
void size_to_mat3(float R[3][3], const float size[3]);
void size_to_mat4(float R[4][4], const float size[3]);
+/** Return 2D size assuming the given matrix is a 2D affine matrix. */
+void mat3_to_size_2d(float size[2], const float M[3][3]);
void mat3_to_size(float size[3], const float M[3][3]);
void mat4_to_size(float size[3], const float M[4][4]);
diff --git a/source/blender/blenlib/intern/math_matrix.c b/source/blender/blenlib/intern/math_matrix.c
index e96b12033a9..221ae84e74d 100644
--- a/source/blender/blenlib/intern/math_matrix.c
+++ b/source/blender/blenlib/intern/math_matrix.c
@@ -2127,6 +2127,12 @@ void size_to_mat4(float R[4][4], const float size[3])
R[3][3] = 1.0f;
}
+void mat3_to_size_2d(float size[2], const float M[3][3])
+{
+ size[0] = len_v2(M[0]);
+ size[1] = len_v2(M[1]);
+}
+
void mat3_to_size(float size[3], const float M[3][3])
{
size[0] = len_v3(M[0]);
diff --git a/source/blender/blenlib/tests/BLI_float3x3_test.cc b/source/blender/blenlib/tests/BLI_float3x3_test.cc
index d22993ee69e..cd823b6e368 100644
--- a/source/blender/blenlib/tests/BLI_float3x3_test.cc
+++ b/source/blender/blenlib/tests/BLI_float3x3_test.cc
@@ -34,6 +34,15 @@ TEST(float3x3, Rotation)
EXPECT_FLOAT_EQ(result[1], 1.0f);
}
+TEST(float3x3, Scale)
+{
+ float2 point(1.0f, 2.0f);
+ float3x3 transformation = float3x3::from_scale(float2(2.0f, 3.0f));
+ float2 result = transformation * point;
+ EXPECT_FLOAT_EQ(result[0], 2.0f);
+ EXPECT_FLOAT_EQ(result[1], 6.0f);
+}
+
TEST(float3x3, TranslationRotationScale)
{
float2 point(1.0f, 2.0f);
@@ -116,4 +125,11 @@ TEST(float3x3, Origin)
EXPECT_FLOAT_EQ(result[1], 3.0f);
}
+TEST(float3x3, GetScale2D)
+{
+ float2 scale(2.0f, 3.0f);
+ float3x3 transformation = float3x3::from_scale(scale);
+ EXPECT_EQ(scale, transformation.scale_2d());
+}
+
} // namespace blender::tests
diff --git a/source/blender/nodes/composite/nodes/node_composite_pixelate.cc b/source/blender/nodes/composite/nodes/node_composite_pixelate.cc
index 4567464a547..c4e42f8247d 100644
--- a/source/blender/nodes/composite/nodes/node_composite_pixelate.cc
+++ b/source/blender/nodes/composite/nodes/node_composite_pixelate.cc
@@ -5,6 +5,9 @@
* \ingroup cmpnodes
*/
+#include "BLI_math_vec_types.hh"
+#include "BLI_math_vector.hh"
+
#include "COM_node_operation.hh"
#include "node_composite_util.hh"
@@ -27,8 +30,34 @@ class PixelateOperation : public NodeOperation {
void execute() override
{
+ /* It might seems strange that the input is passed through without any processing, but note
+ * that the actual processing happens inside the domain realization input processor of the
+ * input. Indeed, the pixelate node merely realizes its input on a smaller-sized domain that
+ * matches its apparent size, that is, its size after the domain transformation. The pixelate
+ * node has no effect if the input is scaled-up. See the compute_domain method for more
+ * information. */
get_input("Color").pass_through(get_result("Color"));
}
+
+ /* Compute a smaller-sized domain that matches the apparent size of the input while having a unit
+ * scale transformation, see the execute method for more information. */
+ Domain compute_domain() override
+ {
+ Domain domain = get_input("Color").domain();
+
+ /* Get the scaling component of the domain transformation, but make sure it doesn't exceed 1,
+ * because pixelation should only happen if the input is scaled down. */
+ const float2 scale = math::min(float2(1.0f), domain.transformation.scale_2d());
+
+ /* Multiply the size of the domain by its scale to match its apparent size, but make sure it is
+ * at least 1 pixel in both axis. */
+ domain.size = math::max(int2(float2(domain.size) * scale), int2(1));
+
+ /* Reset the scale of the transformation by transforming it with the inverse of the scale. */
+ domain.transformation *= float3x3::from_scale(math::safe_divide(float2(1.0f), scale));
+
+ return domain;
+ }
};
static NodeOperation *get_compositor_operation(Context &context, DNode node)