4
\$\begingroup\$

I´m trying to build a tool inside Unity that allows our artists to create different color palettes for our characters.

The big problem is that since every single sprite is hand-drawn and hand-painted with different brushes there are no "traditional" color palettes defined for our base sprites. We use around 10-15 base colors for our characters but each character has tons of different shades and saturation variants to their base color on every frame (again, the art is brush-painted like).

Since color indexing is not really an option (unless I want to create a really big color index texture with a gazillion colors) I was wondering if there was a way to create a shader that, given a set of "base colors" and an equivalent color palette, swaps every "similar color" of the character with the color from the new palette (i.e. swap every single reddish color within a tolerance range with a newly defined color).

The goal here is to do this on a shader in real time. I could just write a script that does this and generates a new spritesheet with the swapped colors, but managing one spritesheet per character variation (we aim to have 10 variations per character) is really problematic for our workflow.

I really hope you can help me. I've been trying to find an answer for this for a week.

\$\endgroup\$
4
\$\begingroup\$

Chroma key effect used for removing colors but you can change colors Instead of removing them.

Chroma key compositing, or chroma keying, is a visual effects / post-production technique for compositing (layering) two images or video streams together based on color hues (chroma range). The technique has been used heavily in many fields to remove a background from the subject of a photo or video – particularly the newscasting, motion picture and videogame industries. https://en.wikipedia.org/wiki/Chroma_key

Here Is the Chroma Key Shader for non-pixel art sprites :

RGB ColorFul

ColorReplacement

Shader "SmkGames/ColorReplacement"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}


        [HideInInspector] _color("Color", Color) = (1.0,1.0,1.0,1.0)

        [HideInInspector]_Red("Filter Color 1", Color) = (1.0,0,0,1.0) //Red
        [HideInInspector]_Green("Filter Color 2", Color) = (0,1.0,0,1.0) //Green
        [HideInInspector]_Blue("Filter Color 3", Color) = (0,0,1.0,1.0) //Blue
        [HideInInspector]_Yellow("Filter Color 4", Color) = (1.0,1.0,0,1.0) //Yellow
        [HideInInspector]_Purple("Filter Color 5", Color) = (1.0,0,1.0,1.0) //Purple
        [HideInInspector]_Cyan("Filter Color 6", Color) = (0,1.0,1.0,1.0) //Cyan
        [HideInInspector]_White("Filter Color 7", Color) = (1.0,1.0,1.0,1.0) //Cyan


        _ColorReplacement1("Red", Color) = (1.0,0,0,1.0) //Red
        _LerpValue1("_LerpValue1",Range(0,1)) = 0
        _ColorReplacement2("Green", Color) = (0,1.0,0,1.0) //Green
        _LerpValue2("_LerpValue2",Range(0,1)) = 0
        _ColorReplacement3("Blue", Color) = (0,0,1.0,1.0) //Blue
        _LerpValue3("_LerpValue3",Range(0,1)) = 0
        _ColorReplacement4("Yellow", Color) = (1.0,1.0,0,1.0) //Yellow
        _LerpValue4("_LerpValue4",Range(0,1)) = 0
        _ColorReplacement5("Purple", Color) = (1.0,0,1.0,1.0) //Purple
        _LerpValue5("_LerpValue5",Range(0,1)) = 0
        _ColorReplacement6("Cyan", Color) = (0,1.0,1.0,1.0) //Cyan
        _LerpValue6("_LerpValue5",Range(0,1)) = 0
        _ColorReplacement7("White", Color) = (1.0,1.0,1.0,1.0) //White
        _LerpValue7("_LerpValue6",Range(0,1)) = 0
    }

    SubShader
    {
Tags {"Queue" = "Transparent"} ZWrite Off  Blend SrcAlpha OneMinusSrcAlpha
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            uniform sampler2D _MainTex;
            uniform float4 _MainTex_ST;
            fixed4 _color;

            //MainColors
            uniform float4 _Red;
            uniform float4 _Green;
            uniform float4 _Blue;
            uniform float4 _Yellow;
            uniform float4 _Purple;
            uniform float4 _Cyan;
            uniform float4 _White;

            //Colors Replacement
            uniform float4 _ColorReplacement1;
            uniform float4 _ColorReplacement2;
            uniform float4 _ColorReplacement3;
            uniform float4 _ColorReplacement4;
            uniform float4 _ColorReplacement5;
            uniform float4 _ColorReplacement6;
            uniform float4 _ColorReplacement7;



            uniform float _LerpValue1;
            uniform float _LerpValue2;
            uniform float _LerpValue3;
            uniform float _LerpValue4;
            uniform float _LerpValue5;
            uniform float _LerpValue6;
            uniform float _LerpValue7;

            float _LerpValue;


            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };



            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                return o;
            }

            half dis(float4 c){
            half result = (pow(_color.r - c.r,2.0)+pow(_color.g - c.g,2.0)+pow(_color.b - c.b,2.0));
            return result;
            }

            fixed4 frag (v2f i) : Color
            {
                 _color = tex2D(_MainTex, i.uv);

                 if(_color.a<=0.15){
                    return half4(0,0,0,0);
                }

                 float4 transparent = float4(0,0,0,0);
                   float4 Red = lerp(_ColorReplacement1,transparent,smoothstep(0,_LerpValue1,dis(_Red)));
                   float4 Green = lerp(_ColorReplacement2,transparent,smoothstep(0,_LerpValue2,dis(_Green)));
                   float4 Blue = lerp(_ColorReplacement3,transparent,smoothstep(0,_LerpValue3,dis(_Blue)));
                   float4 Yellow = lerp(_ColorReplacement4,transparent,smoothstep(0,_LerpValue4,dis(_Yellow)));
                   float4 Purple = lerp(_ColorReplacement5,transparent,smoothstep(0,_LerpValue5,dis(_Purple)));
                   float4 Cyan = lerp(_ColorReplacement6,transparent,smoothstep(0,_LerpValue6,dis(_Cyan)));
                   float4 White = lerp(_ColorReplacement7,transparent,smoothstep(0,_LerpValue7,dis(_White)));

                   return _color + (Green + Red + Blue + Yellow + Purple + Cyan + White);
            }
            ENDCG
        }
    }
}

useful links: Chroma Key Shader 2 , Chroma Key Shader 1

\$\endgroup\$
  • \$\begingroup\$ Thank you !!! I´ll give it a try in a momnent . One question though : Wouldn´t having so many if statements in the shader take a hit on performance? \$\endgroup\$ – Francisco M. Jul 9 '17 at 22:00
  • \$\begingroup\$ @FranciscoM. that's right you can use lerp instead _color = lerp(_ColorReplacement1,_color,smoothstep(_TH,1,dis(_Red))); \$\endgroup\$ – Seyed Morteza Kamali Jul 10 '17 at 1:50
4
\$\begingroup\$

It seems like you want a variation mask for each sprite.

This would entail creating a new greyscale image for each spritesheet, with the darkest values being on the parts of the sprite you want to change (here, Mario's clothing) and the lightest values on those you don't (here, his skin and eyes). In game, you can additively color the variation mask with a color of your choosing and then overlay it onto the actual sprite.

pictures of Mario I found on the internet.

There are two caveats. One, you still need an extra spritesheet per character. Two, all of the spots on the regular spritesheet that you want to change should ideally be in greyscale, to prevent the mask colors and spritesheet colors from mixing into a new color entirely.

If you want multiple, independent colors per character (ie, Mario's hat and overalls are separate), then just create multiple masks, being careful not to overlap dark areas between them unless you want colors to mix. You could fit 4 into the RGBA channels of one image if you are concerned about memory.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.