Kav/Effects/HLSL/Dither.fxh

90 lines
2.5 KiB
Plaintext
Raw Permalink Normal View History

#include "Conversion.fxh"
// technique from http://alex-charlton.com/posts/Dithering_on_the_GPU/
uniform float3 palette[8];
static const int paletteSize = 8;
static const int indexMatrix4x4[16] =
{
0, 8, 2, 10,
12, 4, 14, 6,
3, 11, 1, 9,
15, 7, 13, 5
};
float indexValue(float2 screenCoords)
{
int x = int(screenCoords.x % 4);
int y = int(screenCoords.y % 4);
return indexMatrix4x4[(x + y * 4)] / 16.0;
}
float hueDistance(float h1, float h2)
{
float diff = abs(h1 - h2);
return min(abs(1.0 - diff), diff);
}
void closestColors(float hue, out float3 ret[2])
{
float3 closest = float3(-2, 0, 0);
float3 secondClosest = float3(-2, 0, 0);
float3 temp;
for (int i = 0; i < paletteSize; i++)
{
temp = palette[i];
float tempDistance = hueDistance(temp.x, hue);
if (tempDistance < hueDistance(closest.x, hue))
{
secondClosest = closest;
closest = temp;
}
else
{
if (tempDistance < hueDistance(secondClosest.x, hue))
{
secondClosest = temp;
}
}
}
ret[0] = closest;
ret[1] = secondClosest;
}
float3 dither(float3 color, float2 screenCoords)
{
float3 colors[2];
float3 hsl = RGBtoHSL(color);
closestColors(hsl.x, colors);
float3 closestColor = colors[0];
float3 secondClosestColor = colors[1];
float d = indexValue(screenCoords);
float hueDiff = hueDistance(hsl.x, closestColor.x) / hueDistance(secondClosestColor.x, secondClosestColor.x);
return HSLtoRGB(hueDiff < d ? closestColor : secondClosestColor);
}
// brightColor refers to undithered max color
// float3 dither(float3 color, float3 brightColor, float2 screenCoords)
// {
// float brightHue = RGBtoHSL(brightColor.x);
// float colorHue = RGBtoHSL(color.x);
// float halfDistance = hueDistance(0.0, brightHue) / 2.0;
// float3 closestColor = (colorHue < halfDistance) ? float3(0.0, 0.0, 0.0) : brightColor;
// float3 secondClosestColor = brightColor - closestColor;
// float d = indexValue(screenCoords);
// float distance = abs(closestColor - color);
// return (distance < d) ? closestColor : secondClosestColor;
// }
float3 dither(float color, float2 screenCoords) {
float closestColor = (color < 0.5) ? 0 : 1;
float secondClosestColor = 1 - closestColor;
float d = indexValue(screenCoords);
float distance = abs(closestColor - color);
return (distance < d) ? closestColor : secondClosestColor;
}