I used to use a very simple screen shader effect that worked in the built-in renderer to change palettes; the idea is taken from this Youtube Video. The tl;dr is you take the red channel value from the source image, multiply that by 3 to get an index into one of four colors stored in a 4x4 matrix. Effectively, turning lightness values in your source image to a specific color in a pre-defined palette.
I’d like to keep using this but migrating it to URP has proved a bit confusing (there’s a bit of a learning curve to shader graph). I’ve tried following some instructions for setting up a “fullscreen shader” in shader graph, added as a “renderer feature” to my URP Renderer2DData. You can see in the image below I’ve tried to get the red channel value out of the incoming screen, analogous to tex2D(_MainTex, i.uv).r;
and then I’ve tried to multiply that by 3 to get my array index. I’ve also added the ColorMatrix property, but where I’m stuck is how to do the ColorMatrix array access step and then pipe that to the fragment.
Palette Script
private void OnRenderImage(RenderTexture source, RenderTexture destination)
{
material.SetMatrix("_ColorMatrix", ColorMatrix);
Graphics.Blit(source, destination, material);
}
private Matrix4x4 ColorMatrix
{
get
{
Matrix4x4 mat = new Matrix4x4();
mat.SetRow(0, ColorToVec(activeColor0));
mat.SetRow(1, ColorToVec(activeColor1));
mat.SetRow(2, ColorToVec(activeColor2));
mat.SetRow(3, ColorToVec(activeColor3));
return mat;
}
}
private Vector4 ColorToVec(Color color)
{
return new Vector4(color.r, color.g, color.b, color.a);
}
Shader (excerpt)
sampler2D _MainTex;
half4x4 _ColorMatrix;
fixed4 frag (v2f i) : SV_Target
{
fixed x = tex2D(_MainTex, i.uv).r;
return _ColorMatrix[x * 3];
}