Skip to content

Instantly share code, notes, and snippets.

@ompuco
Last active November 1, 2024 04:01
Show Gist options
  • Save ompuco/3209f1b32213cec5b7bccf0e67caf3e9 to your computer and use it in GitHub Desktop.
Save ompuco/3209f1b32213cec5b7bccf0e67caf3e9 to your computer and use it in GitHub Desktop.
Color dither & truncation based on Sony's PlayStation (1) hardware features & limitations.
#ifdef PSXDTH
#else
#define PSXDTH
//PS1 Hardware Dithering & Color Precision Truncation Function
//by ompu co | Sam Blye (c) 2020
//PS1 dither table from PSYDEV SDK documentation
static const float4x4 psx_dither_table = float4x4
(
0, 8, 2, 10,
12, 4, 14, 6,
3, 11, 1, 9,
15, 7, 13, 5
);
//if desired, this can also be stored as an int4x4
#define useDither 1 //set to 0 to disable dithering and only truncate raw color input
//col - your high-precision color input
//p - screen position in pixel space
float3 DitherCrunch(float3 col, int2 p){
col*=255.0; //extrapolate 16bit color float to 16bit integer space
if(useDither==1)
{
int dither = psx_dither_table[p.x % 4][p.y % 4];
col += (dither / 2.0 - 4.0); //dithering process as described in PSYDEV SDK documentation
}
col = lerp((uint3(col) & 0xf8), 0xf8, step(0xf8,col));
//truncate to 5bpc precision via bitwise AND operator, and limit value max to prevent wrapping.
//PS1 colors in default color mode have a maximum integer value of 248 (0xf8)
col /= 255; //bring color back to floating point number space
return col;
}
//NOTE:
//For best results, run DitherCrunch() during initial rasterization by adding this at the end of your
//material's fragment shader, & not in post processing.
//This allows for proper high quality dithering directly from the full-fidelity vertex gradients,
//more accurate behaviors, use with lower-precision rendertextures without perceived color loss,
//and setting per-object dithering by changing the definition of useDither from 1 to 0 when needed.
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment