Fix #138157: Image Editor Fill tool slight color inaccuracy

`ImagePaintMode` `paint_bucket_fill` does a double colorspace conversion
atm. (which is a lossy process).

Since this is lossy, painting with the same color as was used for
filling can give slight differences (very noticable though if painting
e.g. bump maps).

For comparison, `ProjectionPaintMode` `paint_bucket_fill` (so in the 3D
viewport) does not suffer the same issue (it keeps track of both sRGB
brush color and a linear version of such color).

Currently `paint_2d_bucket_fill` expects linear space color values, so
for filling byte images, we first convert the brush color to linear
(`srgb_to_linearrgb_v3_v3`) then inside `paint_2d_bucket_fill`, we
convert back (`linearrgb_to_srgb_v3_v3`).

We can avoid the double conversion though, make `paint_2d_bucket_fill`
expect sRGB space color values and only convert to linear if we a
filling float images.

Pull Request: https://projects.blender.org/blender/blender/pulls/138540
This commit is contained in:
Philipp Oeser
2025-05-08 08:07:22 +02:00
committed by Philipp Oeser
parent 9afae799e4
commit a5db664d61
4 changed files with 9 additions and 10 deletions

View File

@@ -2390,8 +2390,8 @@ static wmOperatorStatus drop_color_invoke(bContext *C, wmOperator *op, const wmE
}
}
else {
if (gamma) {
srgb_to_linearrgb_v3_v3(color, color);
if (!gamma) {
linearrgb_to_srgb_v3_v3(color, color);
}
ED_imapaint_bucket_fill(C, color, op, event->mval);

View File

@@ -1839,15 +1839,14 @@ void paint_2d_bucket_fill(const bContext *C,
}
do_float = (ibuf->float_buffer.data != nullptr);
/* first check if our image is float. If it is not we should correct the color to
* be in gamma space. strictly speaking this is not correct, but blender does not paint
* byte images in linear space */
/* First check if our image is float. If it is we should correct the color to be in linear space.
*/
if (!do_float) {
linearrgb_to_srgb_uchar3((uchar *)&color_b, color);
rgb_float_to_uchar((uchar *)&color_b, color);
*(((char *)&color_b) + 3) = strength * 255;
}
else {
copy_v3_v3(color_f, color);
srgb_to_linearrgb_v3_v3(color_f, color);
color_f[3] = strength;
}

View File

@@ -130,10 +130,10 @@ class ImagePaintMode : public AbstractPaintMode {
{
float color[3];
if (paint_stroke_inverted(stroke)) {
srgb_to_linearrgb_v3_v3(color, BKE_brush_secondary_color_get(scene, paint, brush));
copy_v3_v3(color, BKE_brush_secondary_color_get(scene, paint, brush));
}
else {
srgb_to_linearrgb_v3_v3(color, BKE_brush_color_get(scene, paint, brush));
copy_v3_v3(color, BKE_brush_color_get(scene, paint, brush));
}
paint_2d_bucket_fill(C, color, brush, mouse_start, mouse_end, stroke_handle);
}

View File

@@ -316,7 +316,7 @@ void paint_2d_stroke(void *ps,
float distance,
float base_size);
/**
* This function expects linear space color values.
* This function expects sRGB space color values.
*/
void paint_2d_bucket_fill(const bContext *C,
const float color[3],