Files
test/source/blender/blenkernel/BKE_image_wrappers.hh
T0MIS0N 416b9990c8 Fix: Artifacting in experimental texture paint on non-manifold meshes
When texture painting a non-manifold mesh, various artifacts are created
on the image texture.

To add seams to the edges of non-manifold UV islands, the texture
painting system reads and writes pixels near the edge of the UV islands.

The offset calculations used to find pixel positions for reading and
writing were not accounting for color channels (RGBA) in the pixel data.
Because of this, the reading function corrupted the color data for the
seams, and the writing function caused the seams to be scaled down and
repeated.

Pull Request: https://projects.blender.org/blender/blender/pulls/146110
2025-09-16 10:05:24 +02:00

92 lines
2.3 KiB
C++

/* SPDX-FileCopyrightText: 2022 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup imbuf
*/
#pragma once
#include "DNA_image_types.h"
#include "BLI_math_color.h"
#include "BLI_math_vector.h"
#include "BLI_math_vector_types.hh"
#include "BLI_memory_utils.hh"
#include "IMB_imbuf_types.hh"
namespace blender::bke::image {
/** Type to use for UDIM tile numbers (1001). */
using TileNumber = int32_t;
struct ImageTileWrapper {
ImageTile *image_tile;
ImageTileWrapper(ImageTile *image_tile) : image_tile(image_tile) {}
TileNumber get_tile_number() const
{
return image_tile->tile_number;
}
int2 get_tile_offset() const
{
return int2(get_tile_x_offset(), get_tile_y_offset());
}
int get_tile_x_offset() const
{
TileNumber tile_number = get_tile_number();
return (tile_number - 1001) % 10;
}
int get_tile_y_offset() const
{
TileNumber tile_number = get_tile_number();
return (tile_number - 1001) / 10;
}
};
template<typename T, int Channels = 4> struct ImageBufferAccessor {
static_assert(is_same_any_v<T, int, float4>);
ImBuf &image_buffer;
ImageBufferAccessor(ImBuf &image_buffer) : image_buffer(image_buffer) {}
float4 read_pixel(const int2 coordinate)
{
if constexpr ((std::is_same_v<T, float4>)) {
int offset = (coordinate.y * image_buffer.x + coordinate.x) * Channels;
return float4(&image_buffer.float_buffer.data[offset]);
}
if constexpr ((std::is_same_v<T, int>)) {
int offset = (coordinate.y * image_buffer.x + coordinate.x) * Channels;
float4 result;
rgba_uchar_to_float(
result,
static_cast<uchar *>(static_cast<void *>(&image_buffer.byte_buffer.data[offset])));
return result;
}
return float4();
}
void write_pixel(const int2 coordinate, float4 new_value)
{
if constexpr ((std::is_same_v<T, float>)) {
int offset = (coordinate.y * image_buffer.x + coordinate.x) * Channels;
copy_v4_v4(&image_buffer.float_buffer.data[offset], new_value);
}
if constexpr ((std::is_same_v<T, int>)) {
int offset = (coordinate.y * image_buffer.x + coordinate.x) * Channels;
rgba_float_to_uchar(
static_cast<uchar *>(static_cast<void *>(&image_buffer.byte_buffer.data[offset])),
new_value);
}
}
};
} // namespace blender::bke::image