VSE: Fix various "off by half a pixel" issues in image transform #116628

Merged
Aras Pranckevicius merged 2 commits from aras_p/blender:vse-fix-filter into main 2024-01-08 16:51:45 +01:00
1 changed files with 16 additions and 7 deletions
Showing only changes of commit ba8e0e0ea2 - Show all commits

View File

@ -98,7 +98,7 @@ struct TransformUserData {
for (int y : IndexRange(0, num_subsamples)) {
for (int x : IndexRange(0, num_subsamples)) {
double2 delta_uv = -offset_x - offset_y;
double2 delta_uv = offset_x + offset_y;
delta_uv += x * subsample_add_x;
delta_uv += y * subsample_add_y;
subsampling.delta_uvs.append(delta_uv);
@ -309,6 +309,13 @@ class Sampler {
u = wrap_uv(u, source->x);
v = wrap_uv(v, source->y);
}
/* BLI_bilinear_interpolation functions use `floor(uv)` and `floor(uv)+1`
* texels. For proper mapping between pixel and texel spaces, need to
* subtract 0.5. */
if constexpr (Filter == IMB_FILTER_BILINEAR) {
u -= 0.5f;
v -= 0.5f;
}
if constexpr (Filter == IMB_FILTER_BILINEAR && std::is_same_v<StorageType, float> &&
NumChannels == 4)
{
@ -501,9 +508,10 @@ class ScanlineProcessor {
private:
void process_one_sample_per_pixel(const TransformUserData *user_data, int scanline)
{
double2 uv = user_data->start_uv +
user_data->destination_region.x_range.first() * user_data->add_x +
user_data->add_y * scanline;
/* Note: sample at pixel center for proper filtering. */
double pixel_x = user_data->destination_region.x_range.first() + 0.5;
double pixel_y = scanline + 0.5;
double2 uv = user_data->start_uv + user_data->add_x * pixel_x + user_data->add_y * pixel_y;
output.init_pixel_pointer(user_data->dst,
int2(user_data->destination_region.x_range.first(), scanline));
@ -522,9 +530,10 @@ class ScanlineProcessor {
void process_with_subsampling(const TransformUserData *user_data, int scanline)
{
double2 uv = user_data->start_uv +
user_data->destination_region.x_range.first() * user_data->add_x +
user_data->add_y * scanline;
/* Note: sample at pixel center for proper filtering. */
double pixel_x = user_data->destination_region.x_range.first() + 0.5;
double pixel_y = scanline + 0.5;
double2 uv = user_data->start_uv + user_data->add_x * pixel_x + user_data->add_y * pixel_y;
output.init_pixel_pointer(user_data->dst,
int2(user_data->destination_region.x_range.first(), scanline));