3D: blend translucent pixels with bottom pixels when needed.

fixes antialiasing within shadows, under translucent polygons, etc
This commit is contained in:
StapleButter
2017-08-28 22:19:49 +02:00
parent 183b8b58e0
commit c9ac08aa5b

View File

@ -941,6 +941,45 @@ u32 RenderPixel(Polygon* polygon, u8 vr, u8 vg, u8 vb, s16 s, s16 t)
return r | (g << 8) | (b << 16) | (a << 24); return r | (g << 8) | (b << 16) | (a << 24);
} }
void PlotTranslucentPixel(u32 pixeladdr, u32 color, u32 z, u32 polyattr, u32 shadow)
{
u32 dstattr = AttrBuffer[pixeladdr];
u32 attr = (polyattr & 0xE0F0) | ((polyattr >> 8) & 0xFF0000) | (1<<22) | (dstattr & 0xFF001F0F);
if (shadow)
{
// for shadows, opaque pixels are also checked
if (dstattr & (1<<22))
{
if ((dstattr & 0x007F0000) == (attr & 0x007F0000))
return;
}
else
{
if ((dstattr & 0x3F000000) == (polyattr & 0x3F000000))
return;
}
}
else
{
// skip if translucent polygon IDs are equal
if ((dstattr & 0x007F0000) == (attr & 0x007F0000))
return;
}
// fog flag
if (!(dstattr & (1<<15)))
attr &= ~(1<<15);
color = AlphaBlend(color, ColorBuffer[pixeladdr], color>>24);
if (z != -1)
DepthBuffer[pixeladdr] = z;
ColorBuffer[pixeladdr] = color;
AttrBuffer[pixeladdr] = attr;
}
void SetupPolygonLeftEdge(RendererPolygon* rp, s32 y) void SetupPolygonLeftEdge(RendererPolygon* rp, s32 y)
{ {
Polygon* polygon = rp->PolyData; Polygon* polygon = rp->PolyData;
@ -1386,7 +1425,6 @@ void RenderPolygonScanline(RendererPolygon* rp, s32 y)
for (; x < xlimit; x++) for (; x < xlimit; x++)
{ {
u32 pixeladdr = FirstPixelOffset + (y*ScanlineWidth) + x; u32 pixeladdr = FirstPixelOffset + (y*ScanlineWidth) + x;
u32 attr;
// check stencil buffer for shadows // check stencil buffer for shadows
if (polygon->IsShadow) if (polygon->IsShadow)
@ -1427,7 +1465,7 @@ void RenderPolygonScanline(RendererPolygon* rp, s32 y)
if (alpha == 31) if (alpha == 31)
{ {
attr = polyattr | edge; u32 attr = polyattr | edge;
if (RenderDispCnt & (1<<4)) if (RenderDispCnt & (1<<4))
{ {
@ -1455,44 +1493,18 @@ void RenderPolygonScanline(RendererPolygon* rp, s32 y)
continue; continue;
DepthBuffer[pixeladdr] = z; DepthBuffer[pixeladdr] = z;
ColorBuffer[pixeladdr] = color;
AttrBuffer[pixeladdr] = attr;
} }
else else
{ {
attr = (polyattr & 0xFFF0) | ((polyattr >> 8) & 0xFF0000) | (1<<22) | (dstattr & 0xFF00000F); if (!(polygon->Attr & (1<<11))) z = -1;
PlotTranslucentPixel(pixeladdr, color, z, polyattr, polygon->IsShadow);
if (polygon->IsShadow) // blend with bottom pixel too, if needed
{ if ((dstattr & 0x3) && (pixeladdr < BufferSize))
// for shadows, opaque pixels are also checked PlotTranslucentPixel(pixeladdr+BufferSize, color, z, polyattr, polygon->IsShadow);
if (dstattr & (1<<22))
{
if ((dstattr & 0x007F0000) == (attr & 0x007F0000))
continue;
}
else
{
if ((dstattr & 0x3F000000) == (polyattr & 0x3F000000))
continue;
}
}
else
{
// skip if polygon IDs are equal
if ((dstattr & 0x007F0000) == (attr & 0x007F0000))
continue;
}
// fog flag
if (!(dstattr & (1<<15)))
attr &= ~(1<<15);
color = AlphaBlend(color, ColorBuffer[pixeladdr], alpha);
if (polygon->Attr & (1<<11))
DepthBuffer[pixeladdr] = z;
} }
ColorBuffer[pixeladdr] = color;
AttrBuffer[pixeladdr] = attr;
} }
// part 2: polygon inside // part 2: polygon inside
@ -1502,7 +1514,6 @@ void RenderPolygonScanline(RendererPolygon* rp, s32 y)
else for (; x < xlimit; x++) else for (; x < xlimit; x++)
{ {
u32 pixeladdr = FirstPixelOffset + (y*ScanlineWidth) + x; u32 pixeladdr = FirstPixelOffset + (y*ScanlineWidth) + x;
u32 attr;
// check stencil buffer for shadows // check stencil buffer for shadows
if (polygon->IsShadow) if (polygon->IsShadow)
@ -1543,46 +1554,20 @@ void RenderPolygonScanline(RendererPolygon* rp, s32 y)
if (alpha == 31) if (alpha == 31)
{ {
attr = polyattr | edge; u32 attr = polyattr | edge;
DepthBuffer[pixeladdr] = z; DepthBuffer[pixeladdr] = z;
ColorBuffer[pixeladdr] = color;
AttrBuffer[pixeladdr] = attr;
} }
else else
{ {
attr = (polyattr & 0xFFF0) | ((polyattr >> 8) & 0xFF0000) | (1<<22) | (dstattr & 0xFF00000F); if (!(polygon->Attr & (1<<11))) z = -1;
PlotTranslucentPixel(pixeladdr, color, z, polyattr, polygon->IsShadow);
if (polygon->IsShadow) // blend with bottom pixel too, if needed
{ if ((dstattr & 0x3) && (pixeladdr < BufferSize))
// for shadows, opaque pixels are also checked PlotTranslucentPixel(pixeladdr+BufferSize, color, z, polyattr, polygon->IsShadow);
if (dstattr & (1<<22))
{
if ((dstattr & 0x007F0000) == (attr & 0x007F0000))
continue;
}
else
{
if ((dstattr & 0x3F000000) == (polyattr & 0x3F000000))
continue;
}
}
else
{
// skip if polygon IDs are equal
if ((dstattr & 0x007F0000) == (attr & 0x007F0000))
continue;
}
// fog flag
if (!(dstattr & (1<<15)))
attr &= ~(1<<15);
color = AlphaBlend(color, ColorBuffer[pixeladdr], alpha);
if (polygon->Attr & (1<<11))
DepthBuffer[pixeladdr] = z;
} }
ColorBuffer[pixeladdr] = color;
AttrBuffer[pixeladdr] = attr;
} }
// part 3: right edge // part 3: right edge
@ -1597,7 +1582,6 @@ void RenderPolygonScanline(RendererPolygon* rp, s32 y)
for (; x < xlimit; x++) for (; x < xlimit; x++)
{ {
u32 pixeladdr = FirstPixelOffset + (y*ScanlineWidth) + x; u32 pixeladdr = FirstPixelOffset + (y*ScanlineWidth) + x;
u32 attr;
// check stencil buffer for shadows // check stencil buffer for shadows
if (polygon->IsShadow) if (polygon->IsShadow)
@ -1638,7 +1622,7 @@ void RenderPolygonScanline(RendererPolygon* rp, s32 y)
if (alpha == 31) if (alpha == 31)
{ {
attr = polyattr | edge; u32 attr = polyattr | edge;
if (RenderDispCnt & (1<<4)) if (RenderDispCnt & (1<<4))
{ {
@ -1666,44 +1650,18 @@ void RenderPolygonScanline(RendererPolygon* rp, s32 y)
continue; continue;
DepthBuffer[pixeladdr] = z; DepthBuffer[pixeladdr] = z;
ColorBuffer[pixeladdr] = color;
AttrBuffer[pixeladdr] = attr;
} }
else else
{ {
attr = (polyattr & 0xFFF0) | ((polyattr >> 8) & 0xFF0000) | (1<<22) | (dstattr & 0xFF00000F); if (!(polygon->Attr & (1<<11))) z = -1;
PlotTranslucentPixel(pixeladdr, color, z, polyattr, polygon->IsShadow);
if (polygon->IsShadow) // blend with bottom pixel too, if needed
{ if ((dstattr & 0x3) && (pixeladdr < BufferSize))
// for shadows, opaque pixels are also checked PlotTranslucentPixel(pixeladdr+BufferSize, color, z, polyattr, polygon->IsShadow);
if (dstattr & (1<<22))
{
if ((dstattr & 0x007F0000) == (attr & 0x007F0000))
continue;
}
else
{
if ((dstattr & 0x3F000000) == (polyattr & 0x3F000000))
continue;
}
}
else
{
// skip if polygon IDs are equal
if ((dstattr & 0x007F0000) == (attr & 0x007F0000))
continue;
}
// fog flag
if (!(dstattr & (1<<15)))
attr &= ~(1<<15);
color = AlphaBlend(color, ColorBuffer[pixeladdr], alpha);
if (polygon->Attr & (1<<11))
DepthBuffer[pixeladdr] = z;
} }
ColorBuffer[pixeladdr] = color;
AttrBuffer[pixeladdr] = attr;
} }
rp->XL = rp->SlopeL.Step(); rp->XL = rp->SlopeL.Step();
@ -1896,7 +1854,7 @@ void ScanlineFinalPass(s32 y)
u32 pixeladdr = FirstPixelOffset + (y*ScanlineWidth) + x; u32 pixeladdr = FirstPixelOffset + (y*ScanlineWidth) + x;
u32 attr = AttrBuffer[pixeladdr]; u32 attr = AttrBuffer[pixeladdr];
if (!(attr & 0x3) || (attr & (1<<22))) continue; if (!(attr & 0x3)) continue;
u32 coverage = (attr >> 8) & 0x1F; u32 coverage = (attr >> 8) & 0x1F;
if (coverage == 0x1F) continue; if (coverage == 0x1F) continue;