Fix #124133: Compositor transforms are off by 0.5 pixels

The GPU compositor transforms are off by half a pixel in some cases.
That's because the realization shader was to perform transforms, and it
includes logic to move images by half a pixel if the domain and image
had different even/odd sizes. To fix this, we only move by half a pixel
if we are doing realization, while transforms are left as is.
This commit is contained in:
Bill Spitzak
2024-07-25 17:23:25 +03:00
committed by Omar Emara
parent 2cae187dcb
commit b3e62d3052
3 changed files with 14 additions and 5 deletions

View File

@@ -2,6 +2,8 @@
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "BLI_math_matrix.hh"
#include "COM_algorithm_realize_on_domain.hh"
#include "COM_context.hh"
#include "COM_domain.hh"
@@ -29,11 +31,19 @@ RealizeOnDomainOperation::RealizeOnDomainOperation(Context &context,
void RealizeOnDomainOperation::execute()
{
const Domain &in_domain = get_input().domain();
/* Even and odd-sized domains have different pixel locations, which produces unexpected
* filtering. If one is odd and the other is even (detected by testing the low bit of the xor of
* the sizes), shift the input by 1/2 pixel so the pixels align. */
const float2 translation(((in_domain.size[0] ^ domain_.size[0]) & 1) ? -0.5f : 0.0f,
((in_domain.size[1] ^ domain_.size[1]) & 1) ? -0.5f : 0.0f);
realize_on_domain(context(),
get_input(),
get_result(),
domain_,
get_input().domain().transformation,
math::translate(in_domain.transformation, translation),
get_input().get_realization_options());
}

View File

@@ -20,11 +20,10 @@ void main()
/* Since an input image with an identity transformation is supposed to be centered in the domain,
* we subtract the offset between the lower left corners of the input image and the domain, which
* is half the difference between their sizes, because the difference in size is on both sides of
* the centered image. Additionally, we floor the offset to retain the 0.5 offset added above in
* case the difference in sizes was odd. */
* the centered image. */
ivec2 domain_size = imageSize(domain_img);
ivec2 input_size = texture_size(input_tx);
vec2 offset = floor(vec2(domain_size - input_size) / 2.0);
vec2 offset = vec2(domain_size - input_size) / 2.0;
/* Subtract the offset and divide by the input image size to get the relevant coordinates into
* the sampler's expected [0, 1] range. */