[Bf-blender-cvs] [64a1b02bdad] compositor-full-frame: Compositor: Add sampling methods for full frame

Manuel Castilla noreply at git.blender.org
Tue Jul 27 23:26:03 CEST 2021


Commit: 64a1b02bdad85629a55140745a2deccb04d14d3d
Author: Manuel Castilla
Date:   Tue Jul 27 16:26:24 2021 +0200
Branches: compositor-full-frame
https://developer.blender.org/rB64a1b02bdad85629a55140745a2deccb04d14d3d

Compositor: Add sampling methods for full frame

Current sampling methods do not take into account area offsets
and have some off by 1 issues on full frame. For example on bilinear
bottom and left image border pixel is not fully sampled and
creates edges.
Other issue is they use `wrap_pixel` when most of the time is not
needed.

In order to not affect tiled implementation, this commit creates
specific sampling methods for full frame needs.

===================================================================

M	source/blender/compositor/intern/COM_MemoryBuffer.cc
M	source/blender/compositor/intern/COM_MemoryBuffer.h

===================================================================

diff --git a/source/blender/compositor/intern/COM_MemoryBuffer.cc b/source/blender/compositor/intern/COM_MemoryBuffer.cc
index 6b954072a9a..fd5cfadceef 100644
--- a/source/blender/compositor/intern/COM_MemoryBuffer.cc
+++ b/source/blender/compositor/intern/COM_MemoryBuffer.cc
@@ -405,12 +405,53 @@ void MemoryBuffer::addPixel(int x, int y, const float color[4])
   }
 }
 
+static void read_ewa_elem(void *userdata, int x, int y, float result[4])
+{
+  MemoryBuffer *buffer = (MemoryBuffer *)userdata;
+  buffer->read_elem_checked(x, y, result);
+}
+
+void MemoryBuffer::read_elem_filtered(
+    const float x, const float y, float dx[2], float dy[2], float *out)
+{
+  BLI_assert(this->m_datatype == DataType::Color);
+  if (m_is_a_single_elem) {
+    read_elem_checked(x, y, out);
+  }
+  else {
+    const float uv[2] = {get_relative_x(x), get_relative_y(y)};
+    const float deriv[2][2] = {{dx[0], dx[1]}, {dy[0], dy[1]}};
+
+    float inv_width = 1.0f / (float)this->getWidth(), inv_height = 1.0f / (float)this->getHeight();
+    /* TODO(sergey): Render pipeline uses normalized coordinates and derivatives,
+     * but compositor uses pixel space. For now let's just divide the values and
+     * switch compositor to normalized space for EWA later.
+     */
+    float uv_normal[2] = {x * inv_width, y * inv_height};
+    float du_normal[2] = {deriv[0][0] * inv_width, deriv[0][1] * inv_height};
+    float dv_normal[2] = {deriv[1][0] * inv_width, deriv[1][1] * inv_height};
+
+    BLI_ewa_filter(this->getWidth(),
+                   this->getHeight(),
+                   false,
+                   true,
+                   uv_normal,
+                   du_normal,
+                   dv_normal,
+                   read_ewa_elem,
+                   this,
+                   out);
+  }
+}
+
+/* TODO(manzanilla): To be removed with tiled implementation. */
 static void read_ewa_pixel_sampled(void *userdata, int x, int y, float result[4])
 {
   MemoryBuffer *buffer = (MemoryBuffer *)userdata;
   buffer->read(result, x, y);
 }
 
+/* TODO(manzanilla): To be removed with tiled implementation. */
 void MemoryBuffer::readEWA(float *result, const float uv[2], const float derivatives[2][2])
 {
   if (m_is_a_single_elem) {
diff --git a/source/blender/compositor/intern/COM_MemoryBuffer.h b/source/blender/compositor/intern/COM_MemoryBuffer.h
index ae12c444dc1..0488adfd26c 100644
--- a/source/blender/compositor/intern/COM_MemoryBuffer.h
+++ b/source/blender/compositor/intern/COM_MemoryBuffer.h
@@ -194,20 +194,64 @@ class MemoryBuffer {
     memcpy(out, get_elem(x, y), m_num_channels * sizeof(float));
   }
 
+  void read_elem_checked(int x, int y, float *out) const
+  {
+    if (x < m_rect.xmin || x >= m_rect.xmax || y < m_rect.ymin || y >= m_rect.ymax) {
+      clear_elem(out);
+    }
+    else {
+      read_elem(x, y, out);
+    }
+  }
+
+  void read_elem_checked(float x, float y, float *out) const
+  {
+    if (x < m_rect.xmin || x >= m_rect.xmax || y < m_rect.ymin || y >= m_rect.ymax) {
+      clear_elem(out);
+    }
+    else {
+      read_elem(floor(x), floor(y), out);
+    }
+  }
+
+  void read_elem_bilinear(float x, float y, float *out) const
+  {
+    if (x <= m_rect.xmin - 1.0f || x >= m_rect.xmax || y <= m_rect.ymin - 1.0f ||
+        y >= m_rect.ymax) {
+      clear_elem(out);
+      return;
+    }
+
+    if (m_is_a_single_elem) {
+      read_elem_checked(x, y, out);
+    }
+    else {
+      BLI_bilinear_interpolation_fl(m_buffer,
+                                    out,
+                                    getWidth(),
+                                    getHeight(),
+                                    m_num_channels,
+                                    get_relative_x(x),
+                                    get_relative_y(y));
+    }
+  }
+
   void read_elem_sampled(float x, float y, PixelSampler sampler, float *out) const
   {
     switch (sampler) {
       case PixelSampler::Nearest:
-        this->read_elem(x, y, out);
+        read_elem_checked(x, y, out);
         break;
       case PixelSampler::Bilinear:
       case PixelSampler::Bicubic:
         /* No bicubic. Current implementation produces fuzzy results. */
-        this->readBilinear(out, x, y);
+        read_elem_bilinear(x, y, out);
         break;
     }
   }
 
+  void read_elem_filtered(const float x, const float y, float dx[2], float dy[2], float *out);
+
   /**
    * Get channel value at given coordinates.
    */
@@ -398,6 +442,8 @@ class MemoryBuffer {
     y = y + m_rect.ymin;
   }
 
+  /* TODO(manzanilla): To be removed with tiled implementation. For applying `MemoryBufferExtend`
+   * use `wrap_pixel`. */
   inline void read(float *result,
                    int x,
                    int y,
@@ -420,6 +466,7 @@ class MemoryBuffer {
     }
   }
 
+  /* TODO(manzanilla): To be removed with tiled implementation. */
   inline void readNoCheck(float *result,
                           int x,
                           int y,
@@ -577,6 +624,21 @@ class MemoryBuffer {
     return get_memory_width() * get_memory_height();
   }
 
+  void clear_elem(float *out) const
+  {
+    memset(out, 0, this->m_num_channels * sizeof(float));
+  }
+
+  template<typename T> T get_relative_x(T x) const
+  {
+    return x - m_rect.xmin;
+  }
+
+  template<typename T> T get_relative_y(T y) const
+  {
+    return y - m_rect.ymin;
+  }
+
   void copy_single_elem_from(const MemoryBuffer *src,
                              int channel_offset,
                              int elem_size,



More information about the Bf-blender-cvs mailing list