Coloring of 2D Images- Possible to allow "Dying" of two different parts via colors?

Let’s say I have some pants or a shirt.

Right now, it is dye-able. I can take a color and put it over the image via a shader tint. This can make the clothing any color I (or the player) want.

Now, I am thinking it would be better if I could make multi-dyable areas. For instance…

Instead of pants, let’s say I have a shirt which includes a belt around it. Obviously I can make both white/grey, and allow dying. One dye would color BOTH the belt and shirt, because it’s the same image.

However… would there be a way to add a color tint to two different areas of an image, perhaps via a “find color” → “tint that color [dye tint]”?

For instance, make the shirt white/grey, but the belt a darker grey, or perhaps make the belt a bright pink? That way if someone wants to dye the belt but NOT the shirt, the shader finds the pink pixels and only tints THOSE?

Or is this just simply NOT worth it?

If the parts are separated mesh pieces, then you can script vert colors. Otherwise, a splat map might work. Here are simple, “unlit” shaders that would work with each of those approaches (second one won’t work in the Editor on Windows):

Shader "3-Colorize" {
	
Properties {
	_MainTex ("RGB = Color Masks,  A = Texture", 2D) = "" {}
	_RedColor ("Color for Red Texture Channel", Color) = (1,1,1)
	_GreenColor ("Color for Green Texture Channel", Color) = (1,1,1)
	_BlueColor ("Color for Blue Texture Channel", Color) = (1,1,1)
}

SubShader {Pass {
	GLSLPROGRAM
	varying lowp vec2 uv;
	
	#ifdef VERTEX
	void main() {
		gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
		uv = gl_MultiTexCoord0.xy;
	}
	#endif
	
	#ifdef FRAGMENT
	uniform lowp sampler2D _MainTex;
	uniform lowp vec3 _RedColor, _GreenColor, _BlueColor;
	void main() {
		lowp vec4 masks_texture = texture2D(_MainTex, uv);
		gl_FragColor = vec4(
			mat3(_RedColor, _GreenColor, _BlueColor) * masks_texture.rgb * masks_texture.a, 1
		);
	}
	#endif
	ENDGLSL
}}

}

Thank you Jessy, I will look into that!.

My apologies, but I totally forgot to mention that these are purely 2D images (a 2D game).

Thank you!

I also remember in Ultima Online, they used greyscale to dye items, while any non-gray part of the image would remain the same. So a pants with a brown tie, could be dyed any color, but the tie would always stay brown.

One alternative I have so far, if the shaders pose too complex an issue for me right now (I’m a bit of a shader newbie) is to render out the shirt, with the tie, fully. Then, render out a greyscale tie. This way the first coloring can dye the entire shirt (including the tie) and if players don’t like that, it can add the overlapping image (the same tie) which can be colored separately.

EDIT: With the Shader ‘Masked Tint’ I read and understand how to make ONLY the grayscale tintable. That is a huge deal, so thank you Jessy! However, I don’t see how to do muti-part colors based on one mask (from my understanding, I can’t do that.)

These are all on 2D planes, which I guess is part of the problem, being a purely 2D game.

I made a “texture flattening” function which will lay one texture on top of another, with color incorporated. Put in a list of textures, another list of textures to determine what colors get written over, and a list of colors, corresponding to the textures.

The reason I separated the alphaSource is because normal maps need to let underlying textures’ normal maps be shown. Some people keep their “transparency” layer on their main texture, and some keep it on the normal map. Whichever you use, use that list of textures for alphaSource.

public static Texture2D Flatten (List<Texture2D> combines, List<Texture2D> alphaSource, List<Color> colorSource) {
		
		//The new texture.
		Texture2D newTexture = new Texture2D(0,0,TextureFormat.ARGB32,true);
		
		//Resize the new texture to match the largest texture.
		foreach(Texture2D resizeTex in combines) {
			if(resizeTex != null) {
				if(resizeTex.width > newTexture.width) {
					newTexture.Resize(resizeTex.width,newTexture.height);
				}
				if(resizeTex.height > newTexture.height) {
					newTexture.Resize(newTexture.width,resizeTex.height);
				}
			}
		}
		
		//Resize each layer to match the new texture, and draw the layer onto the new texture.
		int i = 0;
		int l = combines.Count;
		while(i < l) {
			int xx = newTexture.width;
			int yy = newTexture.height;
			
			if(combines[i] != null  alphaSource[i] != null) {
				Texture2D addTex = new Texture2D(xx,yy,TextureFormat.ARGB32,true);
				addTex.SetPixels(combines[i].GetPixels(0),0);
				addTex.Resize(xx,yy,TextureFormat.ARGB32,true);
				
				int y = 0;
				while(y < yy) {
					int x = 0;
					while(x < xx) {
						Color mainPixel = newTexture.GetPixel(x,y);
						Color newPixel = addTex.GetPixel(x,y);
						Color alphaPixel = alphaSource[i].GetPixel(x,y);
						Color colorChange = colorSource[i];
						mainPixel = Color.Lerp(mainPixel,newPixel*colorChange,alphaPixel.a);
						newTexture.SetPixel(x,y,mainPixel);
						
						++x;
					}
					++y;
				}
			}
			++i;
		}
		
		newTexture.Apply();
		
		return newTexture;
	}

Addendum: This is good for keeping all your textures together, without having to rely on a specialized shader or extra polygons or what-have-you. Also, all textures used must be read/write enabled. Go to that texture’s import settings, set it to an Advanced image, and click that little read/write thing.

If the texture is going to stay a certain color for a long time, and you’re not using multiple versions of it, then you’ll get better performance by using a simpler shader. Is that the case for your project?

If you need a bunch of different colors, that will be a poor use of memory. There’s no general-purpose shader solution for what you’re talking about, but I’ll help if I can. The key to its creation will be knowing how many different parts you need per mesh. What platforms are you targeting?

I would figure a layered shader (layers incorporating the separate colors) to be worse for performance than a single texture. With the code I posted, one would simply have a plain-old single-layer shader; only one texture on it. The texture would be created out of a List of textures/colors, then instantiated, and it could simply be used as any other single texture.

The other benefit to this method is that there is no limit to the number of layers you can pile on; have a layer for socks, underwear, hearts on your underwear, pants, belt, belt buckle, undershirt, shirt; anything. They would simply be flattened into a single instantiated texture.

If you are serious about helping (besides me saying Thank you, for even considering it!) then let me be serious about putting forth the ‘problem’.

Let me get the project loaded in Unity3D, or at least the image files, and once that’s ready I’ll get in detail as to my goal, my assets, etc.
That way we all have a very clear idea of what is going on, what the goal is, and how we might come to that goal (if you want to help after being shown the assets).

It’ll take me a few days, probably, as I’m about to be done working today (need sleep, hahaha) but I’ll bring in the basics (The sprite, his shirt (to dye multiple parts) and his pants to avoid the nudity).

@Tuah-- Thank you VERY much for that. Texture flattening is actually EXACTLY what I need to do! I inevitably will have every 1 frame of a 2D character be Model + (Piece of Clothing * Equipable Slots), so being able to flatten them all into a single texture is actually quite awesome.

My biggest problem (and need for texture flattening) is actually in shadows (which have opacity). I am in need of being able to combine shadows, but have nothing behind that other texture. (Two textures which overlap, both at 50% opacity, will have 100% opacity where they overlap, and 50% opacity where they don’t, making for some weird shadows!)

I will have all of this ready (Models Shadows) next time I post here.
Thanks everyone!

I love you.

I actually just made that script two days ago for use in my Sonic the Hedgehog fangame. I had to create a way to allow for clothing to be placed on top of a character, but still account for custom character colors, and different body types. The result is an approach similar to World of Warcraft; characters’ body textures are at the bottom layers, while other clothing is layered on top. Special clothing models are then attached afterward. If it doesn’t fit the character very well (even after resizing) and the character’s body shows through, the character’s body is covered with that layered texture, and matches the body model.

Only time that function has to be called is when a part is changed, so it’s not too often.

Only downside is that everything has to share a veeery similar UV map.

The performance will be better with a non-colorized texture, like I said. But I’m talking about a splatmap, e.g. what the terrain engine uses to blend textures. Only, you’re not blending textures, you’re blending solid colors. So only two textures are needed, or in the case that your entire image will be colorized, you can use a single texture, which is what the shader I posted above does.

Like I said, that’s a perfect solution if you’re not going to be editing colors frequently, or if you’re only going to use one colorized version of the texture. It’s going to be faster to use a shader, for when the user is interacting with the color-picking interface, though. Have you had such interfaces, in whatever the code you offered, was from?

If you’re curious, here is a basic frame of a 2D animation. The layers combine for a single frame in a multi-frame animation.

Included are the actual images (requiring their own shader)
Shirt, Pants, Model.
Then a combined of all three. Then a dyed version of two different parts.

However, the actual goal would be to find a way to dye the pants and shirt differently, if they were the SAME IMAGE. So taking the single image of the shirt+pants (one image of both) and allow dying of shirt OR pants, or both.

Or, for instance, being able to dye the shirt but NOT the brown TIE on the shirt. Or to be able to pick either and dye either, separately.

Horrible example unless you combine the shirt pants into a single image. This is more along the lines of something more like…tiny details which are more noticeable (bigger) or tiny details when the character is fully enlarged (zoomed it, or in a 1024x1024 frontal view, which is what i call a “paperdoll”) but all I have ready right now is the shirt and pants.


The script I posted incorporates the color of each layer into the final texture, which doesn’t need to be colored. Quite true how the performance might be poor while actually picking the colors though. It could be limited in that the color must be picked directly, rather than transitioned-toward. Same end result, just a tad bit inconvenient.

That said, the function can surely be optimized.

EDIT for the images posted: Ah, if you’re going to be cycling through sprites, it depends on how you handle the sprites. If it’s with a sprite sheet, with all the possible pants animations on a single image, you can use my script to flatten all the sprites onto a single character’s sprite sheet.
However, if you’re going to be switching images out over and over, Jessy’s shader method would probably be better.

Yes, it is with a SpriteSheet. Hopefully when I can get it, SpriteManager2 which can condense sprite sheets better than the packer I have now.

However, each sprite sheet will probably only be a single animation. (One sheet for walking, one for idle, one for cast spell, etc.) But it should hold up.

Wow…if the sprite sheets can be compressed together (or perhaps implement the image compression INTO SpriteManager2 at the very end, so it only draws a single time) then that would be perfect. ESPECIALLY if I could inevitably compress the ENTIRE SPRITE (clothing and all, a single character) into a single set of sprite sheets, as opposed to hundreds of sprite sheets (Sprite Sheets * Animations * Additional Layered Clothing)

All of this would be done while unequipping and equipping, or dying items. This is NOT meant to be a short and simple process. (It can’t happen while the player is performing any actions). So inevitably, I could just do Idle+Walking first, and then let it handle all the rest in the background until done, and if there is any delay in creating that “final character” then the player will never notice because they won’t be able to perform the actions fast enough.