Pixel color replacement - in a pixel art context -.

Hi,

Imagine a basket-ball game made in pixel-art style. I want to give the possibility to change shirts colors on the fly. If the team’ shirt is blue and player wants to play with a pink shirt, I want every blue pixels to be changed by a pink one.

I immediately thought to an algorithm using GetPixels / SetPixels on the sprite texture. I’ve implemented it and it works fine.

BUT, I was wondering if such effect couldn’t be done using shaders (I suck at shaders)? And if so, do you guys think using the shader technique would be more efficient / fast / smart than using the GetPixels / SetPixels one?

A simple demo:

Shader "Custom/MyCharacter" {
	Properties {
		_MainTex ("Base (RGB)", 2D) = "white" {}
		_ShirtTex ("ShirtTex(RGB)", 2D) = "white" {}
		_ShirtColor ("ShirtColor", Color) = (1,1,1,1)
		_NameColor ("NameColor", Color) = (1,0,0,1)
		_NumColor ("NumColor", Color) = (0,1,0,1)
	}
	SubShader {
		Tags { "RenderType"="Opaque" }
		LOD 200
		
		CGPROGRAM
		#pragma surface surf Lambert

		sampler2D _MainTex;
		sampler2D _ShirtTex;
		float4 _ShirtColor;
		float4 _NameColor;
		float4 _NumColor;

		struct Input {
			float2 uv_MainTex;
		};

		void surf (Input IN, inout SurfaceOutput o) {
			half4 c1 = tex2D (_MainTex, IN.uv_MainTex);
			half4 c2 = tex2D (_ShirtTex, IN.uv_MainTex);
			o.Albedo = lerp(c1.rgb, _ShirtColor, c2.r);
			o.Albedo = lerp(o.Albedo, _NameColor, c2.g);
			o.Albedo = lerp(o.Albedo, _NumColor, c2.b);
			o.Alpha = c1.a;
		}
		ENDCG
	} 
	FallBack "Diffuse"
}

The shader is very similar to Terrain Shader.(Add an tex and record colorArea in R/G/B/A layers)

The MainTex is useless in this shader, change code in “void surf ()” to show colors in MainTex.

A shader would definitely be the way to go in terms of efficiency and ease of use. Only having to change a color value instead of setting every pixel by hand.

Here is a single color shader provided by @Eric5h5 in this thread:

Shader "Unlit Color Only" {

Properties {

    _Color ("Color", Color) = (1,1,1)
}

SubShader {
    Color [_Color]

    Pass {}
} 
}

This will color the entire object with the color provided and you can change it in code by doing renderer.material.color = Color.red;

If your team has a logo on their shirt and you only want to color the background you can use this AlphaMask Color shader (provided by TeddyDief in this thread) which color the alpha part of the texture with a specific color:

Shader "Custom/VertexLitAlphaColoring" { 
Properties {
   _AlphaColor ("Alpha Color", Color) = (1,1,1,1) 
   _MainTex ("Base (RGB)", 2D) = "white" {}
}

SubShader {
    Tags { "RenderType"="Opaque" }
    LOD 80
 
    Pass {
       Tags { "LightMode" = "Vertex" }
 
       // Setup Basic
       Material {
         Diffuse (1,1,1,1)
         Ambient (1,1,1,1)
       } 
       Lighting On
       // Lerp between AlphaColor and the basic vertex lighting color
       SetTexture [_MainTex] {
         constantColor [_AlphaColor]
               combine previous lerp(texture) constant DOUBLE, previous lerp(texture) constant
       }
       // Multiply in texture
                SetTexture [_MainTex] {
         combine texture * previous
               }
    }
}
}