Fix #135229: Soft light blending mode for 8 bit colors is wrong
It appears that 8 bit `blend_color_softlight_byte` call used a wrong blending routing (overlay), while `blend_color_softlight_float` is correct. Seems that this was never caught. The correct fomula should be `dst = 2ab + a^2 * (1 - 2b)`. Pull Request: https://projects.blender.org/blender/blender/pulls/135382
This commit is contained in:
@@ -329,21 +329,19 @@ MINLINE void blend_color_screen_byte(uchar dst[4], const uchar src1[4], const uc
|
||||
|
||||
MINLINE void blend_color_softlight_byte(uchar dst[4], const uchar src1[4], const uchar src2[4])
|
||||
{
|
||||
const int fac = src2[3];
|
||||
const float fac = (float)(src2[3]) / 255.0f;
|
||||
if (fac != 0) {
|
||||
const int mfac = 255 - fac;
|
||||
const float mfac = 1.0f - fac;
|
||||
int i = 3;
|
||||
|
||||
while (i--) {
|
||||
int temp;
|
||||
|
||||
if (src1[i] < 127) {
|
||||
temp = ((2 * ((src2[i] / 2) + 64)) * src1[i]) / 255;
|
||||
}
|
||||
else {
|
||||
temp = 255 - (2 * (255 - ((src2[i] / 2) + 64)) * (255 - src1[i]) / 255);
|
||||
}
|
||||
dst[i] = (uchar)((temp * fac + src1[i] * mfac) / 255);
|
||||
/* Using "Pegtop" formula: dst = (1 - 2b) * a^2 + 2ab where a=bottom and b=top color.
|
||||
* See https://en.wikipedia.org/wiki/Blend_modes */
|
||||
const float src1val = (float)(src1[i]) / 255.0f;
|
||||
const float src2val = (float)(src2[i]) / 255.0f;
|
||||
float screen = 1.0f - (1.0f - src1val) * (1.0f - src2val);
|
||||
float soft_light = ((1.0f - src1val) * src2val + screen) * src1val;
|
||||
dst[i] = round_fl_to_uchar_clamp((src1val * mfac + soft_light * fac) * 255.0f);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "testing/testing.h"
|
||||
|
||||
#include "BLI_math_color.h"
|
||||
#include "BLI_math_color_blend.h"
|
||||
|
||||
TEST(math_color, RGBToHSVRoundtrip)
|
||||
{
|
||||
@@ -138,3 +139,41 @@ TEST(math_color, srgb_to_linearrgb_v3_v3)
|
||||
EXPECT_NEAR(56.2383270264f, linear_color[2], kTolerance);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(math_color, BlendModeConsistency_SoftLight)
|
||||
{
|
||||
float fdst[4];
|
||||
float fcolora[4] = {0.0f, 0.0f, 0.0f, 1.0f};
|
||||
float fcolorb[4] = {1.0f, 1.0f, 1.0f, 1.0f};
|
||||
float fcolorc[4] = {1.0f, 1.0f, 1.0f, 0.5f};
|
||||
float fcolord[4] = {0.5f, 0.5f, 0.5f, 0.5f};
|
||||
uchar bdst[4];
|
||||
uchar bcolora[4] = {0, 0, 0, 255};
|
||||
uchar bcolorb[4] = {255, 255, 255, 255};
|
||||
uchar bcolorc[4] = {255, 255, 255, 128};
|
||||
uchar bcolord[4] = {128, 128, 128, 128};
|
||||
|
||||
blend_color_softlight_float(fdst, fcolora, fcolorb);
|
||||
blend_color_softlight_byte(bdst, bcolora, bcolorb);
|
||||
EXPECT_NEAR(fdst[0] * 255.0f, bdst[0], 1.0f);
|
||||
EXPECT_NEAR(fdst[1] * 255.0f, bdst[1], 1.0f);
|
||||
EXPECT_NEAR(fdst[2] * 255.0f, bdst[2], 1.0f);
|
||||
|
||||
blend_color_softlight_float(fdst, fcolorb, fcolora);
|
||||
blend_color_softlight_byte(bdst, bcolorb, bcolora);
|
||||
EXPECT_NEAR(fdst[0] * 255.0f, bdst[0], 1.0f);
|
||||
EXPECT_NEAR(fdst[1] * 255.0f, bdst[1], 1.0f);
|
||||
EXPECT_NEAR(fdst[2] * 255.0f, bdst[2], 1.0f);
|
||||
|
||||
blend_color_softlight_float(fdst, fcolorc, fcolora);
|
||||
blend_color_softlight_byte(bdst, bcolorc, bcolora);
|
||||
EXPECT_NEAR(fdst[0] * 255.0f, bdst[0], 1.0f);
|
||||
EXPECT_NEAR(fdst[1] * 255.0f, bdst[1], 1.0f);
|
||||
EXPECT_NEAR(fdst[2] * 255.0f, bdst[2], 1.0f);
|
||||
|
||||
blend_color_softlight_float(fdst, fcolorc, fcolord);
|
||||
blend_color_softlight_byte(bdst, bcolorc, bcolord);
|
||||
EXPECT_NEAR(fdst[0] * 255.0f, bdst[0], 1.0f);
|
||||
EXPECT_NEAR(fdst[1] * 255.0f, bdst[1], 1.0f);
|
||||
EXPECT_NEAR(fdst[2] * 255.0f, bdst[2], 1.0f);
|
||||
}
|
||||
|
||||
Submodule tests/data updated: b46f393320...2de4677cbd
Reference in New Issue
Block a user