Shader API to get pixel of color, then set pixel to color?

I have never dealt with shaders in my life, and am quite new to Unity (but not to programming 2D games in C++ or C#).

Normally, I’d just edit the texture to “dye” a character image, but all characters in the game use the same sprite texture. A shader just sounds simpler, easier, and better. (This, decided in another thread, thank you.) This is mainly so every individual character can ahve their own colors for certain pixels.

I have tried to google for a bit, but figure it would just be easier, given how simple the request is.

The shader I need, simply takes an image, looks at all the pixels in it, and if the pixel is pure green (Color 0,255,0) then it dyes it to a different color.

Is there a simple line of code that I can write for a shader to simply do something like…

if( getPixel(x,y) == Color.green )
setPixel(x,y, Color.Brown)

I tried browsing the forums, but shader code looks like a completely different language to me.

edit: I guess I should add that the shader’s ‘change to’ colors is different for each character.
I didn’t think about it, but I am unaware if Shaders work the same way instantiating a character would, with something like…

if( getPixel(x,y) == Color.green )
setPixel(x,y, Character.hairColor)

That way each character can have different colors of hair.

Ugh, perhaps I should just do it the way I’d do it in C++/C#, and just edit the texture after copying it to a new texture in memory.

I’d probably come up with something like this:

void surf (Input IN, inout SurfaceOutput o) {
	const float3 ColorToReplace = float3(0,1,0); // green
	const float3 NewColor = float3(1,0,1); // magenta
	
	// read pixel from texture
	half4 c = tex2D (_MainTex, IN.uv_MainTex);
	
	// check how much ColorToReplace equals c.rgb in range 0..1
	// 0=no match, 1=full match
	float weight = saturate(dot(c.rgb, ColorToReplace));
	
	// blend between both colors
	c.rgb = lerp(c.rgb, NewColor, weight);
	
	o.Albedo = c.rgb;
	o.Alpha = c.a;
}

tex2D | dot | saturate | lerp

Matching a color for its exact value is most likely causing artifacts at its borders (where it changes to another color), unless you use point-sampling. That’s why I use a weightened blend rather than a replace, but in the example above, it will also blend colors other than ColorToReplace, so it’s just a starting point and not a copy/paste solution.

Another approach I can think of, which is actually doing a color-match and replacement:

void surf (Input IN, inout SurfaceOutput o) {
	const float3 ColorToReplace = float3(0,1,0); // green
	const float3 NewColor = float3(1,0,1); // magenta
	
	// read pixel from texture
	half4 c = tex2D (_MainTex, IN.uv_MainTex);
	
	// check if pixel from texture is close to ColorToReplace
	float isColorToReplace = step(0.999, dot(c.rgb, ColorToReplace));
	
	// either use NewColor or the old color, depending whether isColorToReplace is 0 or 1
	c.rgb = isColorToReplace*NewColor + (1-isColorToReplace)*c.rgb;
	
	o.Albedo = c.rgb;
	o.Alpha = c.a;
}

tex2D | dot | step

However, this will cause artifacts when not using point-sampling.

Thank you.

While I will have to attempt a bit to understand the shader syntax so I know what’s going on, this helps greatly.

I tried to edit the texture in code (not using a shader and going in the other direction) but in the end, I almost gave up.

I switched to Unity, to make things easier on me. This is proving more difficult than simply doing it in C# in my old project. Your help in figuring out this shader stuff is a step forward toward Unity for me.

edit: For some reason, it doesn’t just turn green into magenta. It is also turning my yellow into magenta.

This is proving a bit much for me, given how I am only trying out Unity to see if it will cut down on my workload in making a simple 2D game.

Unfortunately, it is more than enough to learn Unity’s quirks and API. Let alone an entirely new shader language, coming from total ignorance dealing with shaders.

My goodness, if only Unity allowed me to update the sprite.Texture. Then I would be able to do it just like I did in my old project coding from scratch.

All I’m trying to do is get caught up to what little I had on my custom engine, and then proceed with some development to see Unity’s pacing. This is proving to be even more difficult than coding from scratch in C#. For me at least.

You can set a texture to Read/Write Enabled, which lets you change the texture content via code, see here for example.

Thank you, but that only allows me to edit the texture as I need.

However, the problem is with the sprite itself.

http://forum.unity3d.com/threads/223390-How-to-change-sprite-Texture-of-a-sprite

I’ve never worked with the 2D stuff or sprite in Unity. I assume color-tinting isn’t what you’re looking for? Like making the region in your texture you want to tint in grayscale and use the material color to tint the sprite?

Nope :\

I am basically creating sprites which are just specific colors of pixels on a game tile. So I need the ability to select 10 specific colors, and change them based on whatever the character’s specific individual color is.

I am getting closer.

I have managed to duplicate the Texture2D and successfully edit the pixels exactly as I want.

The only problem, is I am unable display the new Texture2D via sprite / spriterenderer.

I’m ending this thread with this post, for reference to a solution (using code, not a solution using a shader).

http://forum.unity3d.com/threads/223390-How-to-change-sprite-Texture-of-a-sprite

Just to inform everyone, Jinxology has made a shader that does this, and shared it with everyone.

http://forum.unity3d.com/threads/223030-Best-Easiest-way-to-change-color-of-certain-pixels-in-a-single-Sprite?p=1491019&viewfull=1#post1491019

I hope to correct the 2 problems I’m having with it, and then posting the answers in the thread.