[Bf-blender-cvs] [89cecb088f2] temp-image-buffer-rasterizer: Improve quality by center pixel clamping.
Jeroen Bakker
noreply at git.blender.org
Fri Feb 18 16:43:41 CET 2022
Commit: 89cecb088f2f623b249ef774387c84e3de21e225
Author: Jeroen Bakker
Date: Fri Feb 18 16:43:38 2022 +0100
Branches: temp-image-buffer-rasterizer
https://developer.blender.org/rB89cecb088f2f623b249ef774387c84e3de21e225
Improve quality by center pixel clamping.
===================================================================
M source/blender/imbuf/IMB_rasterizer.hh
A source/blender/imbuf/intern/rasterizer_clamping.hh
M source/blender/imbuf/intern/rasterizer_test.cc
===================================================================
diff --git a/source/blender/imbuf/IMB_rasterizer.hh b/source/blender/imbuf/IMB_rasterizer.hh
index 56a2aa175ae..db1f6c6ca9e 100644
--- a/source/blender/imbuf/IMB_rasterizer.hh
+++ b/source/blender/imbuf/IMB_rasterizer.hh
@@ -70,11 +70,12 @@
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
+#include "intern/rasterizer_clamping.hh"
#include "intern/rasterizer_stats.hh"
#include <optional>
-//#define DEBUG_PRINT
+#define DEBUG_PRINT
namespace blender::imbuf::rasterizer {
@@ -257,6 +258,8 @@ class Rasterizer {
Rasterlines<RasterlineType, RasterlinesSize> rasterlines_;
ImBuf *image_buffer_;
+ const CenterPixelClampingMethod clamping_method;
+
public:
Statistics stats;
@@ -338,10 +341,9 @@ class Rasterizer {
#endif
std::array<VertexOutputType *, 3> sorted_vertices = order_triangle_vertices(vertex_out);
- // TODO: add y coordinate clamping for smoother result.
- const int min_v = sorted_vertices[0]->coord[1];
- const int mid_v = sorted_vertices[1]->coord[1];
- const int max_v = sorted_vertices[2]->coord[1];
+ const int min_v = clamping_method.scanline_for(sorted_vertices[0]->coord[1]);
+ const int mid_v = clamping_method.scanline_for(sorted_vertices[1]->coord[1]);
+ const int max_v = clamping_method.scanline_for(sorted_vertices[2]->coord[1]) - 1;
/* left and right branch. */
VertexOutputType left = *sorted_vertices[0];
@@ -366,6 +368,13 @@ class Rasterizer {
std::swap(left_add, right_add);
}
+ /* Perform a substep to make sure that the data of left and right match the data on the anchor
+ * point (center of the pixel). */
+ const float distance_to_minline_anchor_point = clamping_method.distance_to_scanline_anchor(
+ sorted_vertices[0]->coord[1]);
+ left += left_add * distance_to_minline_anchor_point;
+ right += right_add * distance_to_minline_anchor_point;
+
/* Add rasterlines from min_v to mid_v. */
int v;
for (v = min_v; v < mid_v; v++) {
@@ -381,21 +390,24 @@ class Rasterizer {
}
/* When both are the same we should the left/right branches are the same. */
- if (min_v == mid_v) {
- /* Use the x coordinate to identify which branch should be modified. */
- if (sorted_vertices[0]->coord[0] > sorted_vertices[1]->coord[0]) {
- left = *sorted_vertices[1];
- }
- else {
- right = *sorted_vertices[1];
- }
+ const float distance_to_midline_anchor_point = clamping_method.distance_to_scanline_anchor(
+ sorted_vertices[1]->coord[1]);
+ /* Use the x coordinate to identify which branch should be modified. */
+ // TODO when min_v and mid_v are on the same scanline....
+ const float distance_to_left = abs(left.coord[0] - sorted_vertices[1]->coord[0]);
+ const float distance_to_right = abs(right.coord[0] - sorted_vertices[1]->coord[0]);
+ if (distance_to_left < distance_to_right) {
+ left = *sorted_vertices[1];
+ left_target = sorted_vertices[2];
+ left_add = calc_vertex_output_data(left, *left_target);
+ left += left_add * distance_to_midline_anchor_point;
+ }
+ else {
+ right = *sorted_vertices[1];
+ right_target = sorted_vertices[2];
+ right_add = calc_vertex_output_data(right, *right_target);
+ right += right_add * distance_to_midline_anchor_point;
}
-
- /* Update the branch adders. */
- left_target = sorted_vertices[2];
- right_target = sorted_vertices[2];
- left_add = calc_vertex_output_data(left, *left_target);
- right_add = calc_vertex_output_data(right, *right_target);
/* Add rasterlines from mid_v to max_v. */
for (; v < max_v; v++) {
@@ -414,10 +426,11 @@ class Rasterizer {
VertexOutputType calc_vertex_output_data(const VertexOutputType &from,
const VertexOutputType &to)
{
- // TODO: this should be done without casting to int, but that needs a better pixel clamping
- // strategic.
- const int num_rasterlines = (((int)to.coord[1]) - ((int)from.coord[1]));
- return (to - from) / max_ii(1, num_rasterlines);
+ const float num_rasterlines = to.coord[1] - from.coord[1];
+ if (num_rasterlines == 0.0) {
+ return (to - from);
+ }
+ return (to - from) / num_rasterlines;
}
std::array<VertexOutputType *, 3> order_triangle_vertices(
@@ -471,11 +484,10 @@ class Rasterizer {
InterfaceInnerType start_data,
InterfaceInnerType end_data)
{
- BLI_assert(start_x <= end_x);
BLI_assert(y >= 0 && y < image_buffer_->y);
stats.increase_rasterlines();
- if (start_x == end_x) {
+ if (start_x >= end_x) {
stats.increase_discarded_rasterlines();
return std::nullopt;
}
@@ -489,17 +501,20 @@ class Rasterizer {
}
FragmentInputType add_x = (end_data - start_data) / (end_x - start_x);
+ /* Is created rasterline clamped and should be added to the statistics. */
bool is_clamped = false;
- uint32_t start_xi;
- if (start_x < 0.0) {
- start_data += add_x * abs(start_x);
+
+ /* Clamp the start_x to the first visible column anchor. */
+ int32_t start_xi = clamping_method.column_for(start_x);
+ float delta_to_anchor = clamping_method.distance_to_column_anchor(start_x);
+ if (start_xi < 0) {
+ delta_to_anchor += -start_xi;
start_xi = 0;
is_clamped = true;
}
- else {
- start_xi = ceil(start_x);
- }
- uint32_t end_xi = ceil(end_x);
+ start_data += add_x * delta_to_anchor;
+
+ uint32_t end_xi = clamping_method.column_for(end_x);
if (end_xi > image_buffer_->x) {
end_xi = image_buffer_->x;
is_clamped = true;
@@ -509,7 +524,11 @@ class Rasterizer {
stats.increase_clamped_rasterlines();
}
- return RasterlineType(y, start_xi, end_xi, start_data, add_x);
+#ifdef DEBUG_PRINT
+ printf("%s y(%d) x(%d-%u)\n", __func__, y, start_xi, end_xi);
+#endif
+
+ return RasterlineType(y, (uint32_t)start_xi, end_xi, start_data, add_x);
}
void render_rasterline(const RasterlineType &rasterline)
diff --git a/source/blender/imbuf/intern/rasterizer_clamping.hh b/source/blender/imbuf/intern/rasterizer_clamping.hh
new file mode 100644
index 00000000000..30aa9daec36
--- /dev/null
+++ b/source/blender/imbuf/intern/rasterizer_clamping.hh
@@ -0,0 +1,82 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2022 Blender Foundation. All rights reserved. */
+
+#pragma once
+
+/** \file
+ * \ingroup imbuf
+ *
+ * Pixel clamping determines how the edges of geometry is clamped to pixels.
+ */
+
+#include "BLI_sys_types.h"
+
+namespace blender::imbuf::rasterizer {
+
+class AbstractPixelClampingMethod {
+ public:
+ virtual float distance_to_scanline_anchor(float y) const = 0;
+ virtual float distance_to_column_anchor(float y) const = 0;
+ virtual int scanline_for(float y) const = 0;
+ virtual int column_for(float x) const = 0;
+};
+
+class CenterPixelClampingMethod : public AbstractPixelClampingMethod {
+ public:
+ float distance_to_scanline_anchor(float y) const override
+ {
+ return distance_to_anchor(y);
+ }
+ float distance_to_column_anchor(float x) const override
+ {
+ return distance_to_anchor(x);
+ }
+
+ int scanline_for(float y) const override
+ {
+ return this->round(y);
+ }
+
+ int column_for(float x) const override
+ {
+ return this->round(x);
+ }
+
+ private:
+ float distance_to_anchor(float value) const
+ {
+ float fract = to_fract(value);
+ float result;
+ if (fract <= 0.5f) {
+ result = 0.5f - fract;
+ }
+ else {
+ result = 1.5f - fract;
+ }
+ BLI_assert(result >= 0.0f);
+ BLI_assert(result < 1.0f);
+ return result;
+ }
+
+ int round(float value) const
+ {
+ /* Cannot use std::round as it rounds away from 0. */
+ float fract = to_fract(value);
+ int result;
+
+ if (fract > 0.5f) {
+ result = ceilf(value);
+ }
+ else {
+ result = floorf(value);
+ }
+ return result;
+ }
+
+ float to_fract(float value) const
+ {
+ return value - floor(value);
+ }
+};
+
+} // namespace blender::imbuf::rasterizer
diff --git a/source/blender/imbuf/intern/rasterizer_test.cc b/source/blender/imbuf/intern/rasterizer_test.cc
index 3cd9aa11b1a..b54aa1e5579 100644
--- a/source/blender/imbuf/intern/rasterizer_test.cc
+++ b/source/blender/imbuf/intern/rasterizer_test.cc
@@ -84,4 +84,194 @@ TEST(imbuf_rasterizer, draw_triangle)
imb_freerectImbuf_all(&image_buffer);
}
+TEST(imbuf_rasterizer, center_pixel_clamper_scanline_for)
+{
+ CenterPixelClampingMethod clamper;
+
+ EXPECT_EQ(clamper.scanline_for(-2.0f), -2);
+ EXPECT_EQ(clamper.scanline_for(-1.9f), -2);
+ EXPECT_EQ(clamper.scanline_for(-1.8f), -2);
+ EXPECT_EQ(clamper.scanline_for(-1.7f), -2);
+ EXPECT_EQ(clamper.scanline_for(-1.6f), -2);
+ EXPECT_EQ(clamper.scanline_for(-1.5f), -2);
+ EXPECT_EQ(clamper.scanline_for(-1.4f), -1);
+ EXPECT_EQ(clamper.scanline_for(-1.3f), -1);
+ EXPECT_EQ(clamper.scanline_for(-1.2f), -1);
+ EXPECT_EQ(clamper.scanline_for(-1.1f), -1);
+ EXPECT_EQ(clamper.scanline_for(-1.0f), -1);
+ EXPECT_EQ(clamper.scanline_for(-0.9f), -1);
+ EXPECT_EQ(clamper.scanline_for(-0.8f), -1);
+ EXPECT_EQ(clamper.scanline_for(-0.7f), -1);
+ EXPECT_EQ(clamper.scanline_for(-0.6f), -1);
+ EXPECT_EQ(clamper.scanline_for(-0.5f), -1);
+ EXPECT_EQ(clamper.scanline_for(-0.4f), 0);
+ EXPECT_EQ(clamper.scanline_for(-0.3f), 0);
+ EXPECT_EQ(clamper.scanline_for(-0.2f), 0);
+ EXPECT_EQ(clamper.scanline_for(-0.1f), 0);
+ EXPECT_EQ(clamper.scanline_for(0.0f), 0);
+ EXPECT_EQ(clamper.scanline_for(0.1f), 0);
+ EXPECT_EQ(clamper.scanline_for(0.2f), 0);
+ EXPECT_EQ(clamper.scanline_for(0.3f), 0);
+ EXPECT_EQ(clamper.scanline_for(0.4f), 0);
+ EXPECT_EQ(clamper.scanline_for(0.5f), 0);
+ EXPECT_EQ(clamper.scanline_for(0.6f), 1);
+ EXPECT_EQ(clamper.scanline_for(0.7f), 1);
+ EXPECT_EQ(clamper.scanline_for(0.8f), 1);
+ EXPECT_EQ(clamper.scanline_for(0.9f), 1);
+ EXPECT_EQ(clamper.scanline_for(1.0f), 1);
+ EXPECT_EQ(clamper.scanline_for(1.0f), 1);
+ EXPECT_EQ(clamper.scanline_for(1.1f), 1);
+ EXPECT_EQ(clamper.scanline_for(1
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-blender-cvs
mailing list