Fix issue with anti-aliasing artifacts around borders with transparent pixels.

This commit is contained in:
Jennifer Taylor 2021-06-13 03:15:03 +00:00
parent dfffe80a74
commit f8c3f75883
2 changed files with 56 additions and 19 deletions

View File

@ -427,6 +427,7 @@ def pixel_renderer(
b = 0
a = 0
count = 0
denom = 0
# Essentially what we're doing here is calculating the scale, clamping it at 1.0 as the
# minimum and then setting the AA sample swing accordingly. This has the effect of anti-aliasing
@ -442,15 +443,21 @@ def pixel_renderer(
texloc = inverse.multiply_point(Point(imgx + addx, imgy + addy))
aax, aay = texloc.as_tuple()
# If we're out of bounds, don't update.
# If we're out of bounds, don't update. Factor this in, however, so we can get partial
# transparency to the pixel that is already there.
denom += 1
if aax < 0 or aay < 0 or aax >= texwidth or aay >= texheight:
continue
# Grab the values to average, for SSAA.
# Grab the values to average, for SSAA. Make sure to factor in alpha as a poor-man's
# blend to ensure that partial transparency pixel values don't unnecessarily factor
# into average calculations.
texoff = (aax + (aay * texwidth)) * 4
r += texbytes[texoff]
g += texbytes[texoff + 1]
b += texbytes[texoff + 2]
apercent = texbytes[texoff + 3] / 255.0
r += int(texbytes[texoff] * apercent)
g += int(texbytes[texoff + 1] * apercent)
b += int(texbytes[texoff + 2] * apercent)
a += texbytes[texoff + 3]
count += 1
@ -458,8 +465,16 @@ def pixel_renderer(
# None of the samples existed in-bounds.
return imgbytes[imgoff:(imgoff + 4)]
# Average the pixels.
average = [r // count, g // count, b // count, a // count]
# Average the pixels. Make sure to divide out the alpha in preparation for blending.
alpha = a // denom
if alpha == 0:
average = [255, 255, 255, alpha]
else:
apercent = alpha / 255.0
average = [int((r / denom) / apercent), int((g / denom) / apercent), int((b / denom) / apercent), alpha]
# Finally, blend it with the destination.
return blend_point(add_color, mult_color, average, imgbytes[imgoff:(imgoff + 4)], blendfunc)
else:
# Calculate what texture pixel data goes here.

View File

@ -275,6 +275,7 @@ extern "C"
int b = 0;
int a = 0;
int count = 0;
int denom = 0;
for (float addy = 0.5 - yswing; addy <= 0.5 + yswing; addy += yswing / 2.0) {
for (float addx = 0.5 - xswing; addx <= 0.5 + xswing; addx += xswing / 2.0) {
@ -282,16 +283,22 @@ extern "C"
int aax = texloc.x;
int aay = texloc.y;
// If we're out of bounds, don't update.
// If we're out of bounds, don't update. Factor this in, however, so we can get partial
// transparency to the pixel that is already there.
denom ++;
if (aax < 0 or aay < 0 or aax >= (int)work->texwidth or aay >= (int)work->texheight) {
continue;
}
// Grab the values to average, for SSAA.
// Grab the values to average, for SSAA. Make sure to factor in alpha as a poor-man's
// blend to ensure that partial transparency pixel values don't unnecessarily factor
// into average calculations.
unsigned int texoff = aax + (aay * work->texwidth);
r += work->texdata[texoff].r;
g += work->texdata[texoff].g;
b += work->texdata[texoff].b;
float apercent = work->texdata[texoff].a / 255.0;
r += (int)(work->texdata[texoff].r * apercent);
g += (int)(work->texdata[texoff].g * apercent);
b += (int)(work->texdata[texoff].b * apercent);
a += work->texdata[texoff].a;
count ++;
}
@ -302,13 +309,28 @@ extern "C"
continue;
}
// Average the pixels.
intcolor_t average = (intcolor_t){
(unsigned char)(r / count),
(unsigned char)(g / count),
(unsigned char)(b / count),
(unsigned char)(a / count),
};
// Average the pixels. Make sure to divide out the alpha in preparation for blending.
unsigned char alpha = (unsigned char)(a / denom);
intcolor_t average;
if (alpha == 0) {
// Samples existed in bounds, but with zero alpha.
average = (intcolor_t){
255,
255,
255,
alpha,
};
} else {
// Samples existed in bounds, with some alpha component, un-premultiply it.
float apercent = alpha / 255.0;
average = (intcolor_t){
(unsigned char)((r / denom) / apercent),
(unsigned char)((g / denom) / apercent),
(unsigned char)((b / denom) / apercent),
alpha,
};
}
// Blend it.
work->imgdata[imgoff] = blend_point(work->add_color, work->mult_color, average, work->imgdata[imgoff], work->blendfunc);