This should work. It might not be the most efficient for large amounts of colors, but it works well. I did find that unless the sprites were set to Point filter there would be artifacts.
Shader "Hidden/PaletteSwap"
{
Properties {
_MainTex ("", 2D) = "" {}
}
SubShader {
Pass{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct v2f {
float4 pos : POSITION;
half2 uv : TEXCOORD0;
};
v2f vert(appdata_img v)
{
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
o.uv = MultiplyUV(UNITY_MATRIX_TEXTURE0, v.texcoord.xy);
return o;
}
sampler2D _MainTex;
uniform float4 _InColorA;
uniform float4 _InColorB;
uniform float4 _InColorC;
uniform float4 _InColorD;
uniform float4 _OutColorA;
uniform float4 _OutColorB;
uniform float4 _OutColorC;
uniform float4 _OutColorD;
fixed4 frag(v2f i) : COLOR
{
float4 start = tex2D(_MainTex, i.uv);
float4 final = start;
float testA = saturate(abs(start.x - _InColorA.x) + abs(start.y - _InColorA.y) + abs(start.z - _InColorA.z));
final = lerp(final, _OutColorA, 1-testA);
float testB = saturate(abs(start.x - _InColorB.x) + abs(start.y - _InColorB.y) + abs(start.z - _InColorB.z));
final = lerp(final, _OutColorB, 1 - testB);
float testC = saturate(abs(start.x - _InColorC.x) + abs(start.y - _InColorC.y) + abs(start.z - _InColorC.z));
final = lerp(final, _OutColorC, 1 - testC);
float testD = saturate(abs(start.x - _InColorD.x) + abs(start.y - _InColorD.y) + abs(start.z - _InColorD.z));
final = lerp(final, _OutColorD, 1 - testD);
return final;
}
ENDCG
}
}
}
And this is an example of a script that would go on the camera, you can set this up how you would like:
using UnityEngine;
using System.Collections;
[ExecuteInEditMode]
[RequireComponent(typeof(Camera))]
public class PaletteSwap : MonoBehaviour
{
[SerializeField]
private Color[] input;
[SerializeField]
private Color[] output;
private Material paletteswapmat;
public bool reset = false;
void Init()
{
paletteswapmat = new Material(Shader.Find("Hidden/PaletteSwap"));
}
void Awake()
{
Init();
SetColors();
}
public void SetColors()
{
paletteswapmat.SetColor("_InColorA", input[0]);
paletteswapmat.SetColor("_InColorB", input[1]);
paletteswapmat.SetColor("_InColorC", input[2]);
paletteswapmat.SetColor("_InColorD", input[3]);
paletteswapmat.SetColor("_OutColorA", output[0]);
paletteswapmat.SetColor("_OutColorB", output[1]);
paletteswapmat.SetColor("_OutColorC", output[2]);
paletteswapmat.SetColor("_OutColorD", output[3]);
}
void Update()
{
if(reset)
{
SetColors();
reset = false;
}
}
void OnRenderImage(RenderTexture source, RenderTexture destination)
{
Graphics.Blit(source, destination, paletteswapmat);
}
}
This only does 4 colors, to add more you’ll have to manually add more colors to the shader and script.
I actually think this is kind of a poor way to accomplish this, however, since there is a cap on the number of colors you can use depending on your platform this way.