Unity用两张贴图解决N种换色的排列组合shader

发表于2017-05-02
评论1 6.9k浏览
一、 换色Shader能得到的效果和准备工作;

      1.  变色效果

      简单描述一下这个Shader的功能,简单来说就是结合两张贴图,动态改变两至三个颜色,通过利用Alpha通道对主贴图进行三个不同区域的颜色改变,下面的示例中是可任意改变两个区域颜色,一直固定第三个区域的形状颜色,下面图示变色效果:

     

(默认两个颜色都为白色时是原始灰度图颜色效果)

     

(分别改变两个颜色后的变色效果,根据shader中颜色的改变可以看到三个区域不同的颜色)

(圈起的这两块是本示例中始终保持最原始图片的颜色)

 

    2.    准备工作

     a)    首先作图的工具得有吧(Photo Shop,如果你有美术当然可以省了这些美术工作;

     b)    一张原始图片,自己想好需要在这张图片上更改那两个部分,以便后面做另外一张Alpha通道的遮罩贴图;

     c)    最后就是回归到Unity里面写shader程序了,这个就没什么特别需要的了;

 

二、       换色shader的工作原理;

三、       根据原理实现的步;

       1.   编程前的美术工作,将准备好的需要更改的纹理贴图在PS中进行灰度处理,并把logo部分区分出来放在alpha通道中;

      

 

》》》为什么logo的地方颜色没有变灰?

因为我这次设定的示例是想要logo一直保留固有的颜色,后面的程序中也并没去改变logo的颜色,如果需要改变当然也得把logo变成灰度图。

 

》》》灰度图的亮度不同会达到怎样的效果?

    这个灰度图的亮度当然可以根据色阶工具来自行调整,根据游戏风格来调一下深浅,灰度的深浅与叠加色重合过后的颜色的鲜明程度是成正比关系的。

 

      2.   做遮罩贴图,为了区分纹理贴图里面衣服和皮肤的区域,需要做一张Alpha通道的贴图;

(把这张遮罩贴图对应上面一张纹理贴图来看,明显可以看出已经区分出两个不同的区域了)

 

      3.   接下来当然是把这两张贴图丢到工程里面,编写shader来实现了,下面把三个部分的上色代码分别列出来;

      a      需要更改的衣服颜色(衣服区域除去logo的部分)

1
2
3
4
//得到纹理贴图的颜色
fixed4 clothcolor = fixed4( mainColor.rgb * _Color, 1-mainColor.a);
//纹理贴图rgb值*更改后的alpha值(通过遮罩找到需要更改的区域)
clothcolor.rgb *= (mask.a * clothcolor.a);
 

      b)需要更改的皮肤颜色


1
2
fixed4 skincolor = fixed4( mainColor.rgb*_SkinColor, 1-mainColor.a);
skincolor.rgb *= ((1-mask.a)* skincolor.a);

    c)保持logo颜色不变

1
2
fixed4 logocolor = fixed4( mainColor.rgb, mainColor.a);
logocolor.rgb *= (mask.a *logocolor.a);

        注:这里可以看出logo颜色上也并没有乘以其他的颜色,所以logo就保留了原始纹理图片上的原始色。如果需要logo的颜色也改变,那么也得把logo处理成灰度图,并且把logorgb值乘以一个你想要改变的颜色值就可以了;

 

     4.   最后当然上代码了;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
Shader "Doraemon/ChangeColor"
 
     
     
    Properties
 
    
         
        _MainTex ("MainTex", 2D) = "white" {}
 
        _Mask ("MaskTex", 2D) = "white" {} 
 
        _Color ("MainColor", Color) = (1,1,1,1)
 
        _SkinColor ("SkinColor", Color) = (1,1,1,1)
 
    }
 
 
 
    SubShader
 
    {
 
        Tags
 
        {
 
            "Queue"="Transparent"
 
            "IgnoreProjector"="True"
 
            "RenderType"="Transparent"
 
            "PreviewType"="Plane"
 
            "CanUseSpriteAtlas"="True"
 
        }
 
        Cull Off
 
        Lighting Off
 
        ZWrite on
 
        Blend SrcAlpha OneMinusSrcAlpha
 
        Pass
 
        {        
 
            CGPROGRAM
 
            #pragma vertex vert
 
            #pragma fragment frag
 
 
 
            #include "UnityCG.cginc"
 
            #include "UnityUI.cginc"
 
            sampler2D _MainTex;
            sampler2D _Mask; 
            fixed4 _Color;
            fixed4 _SkinColor;
 
            struct a2v
 
            {
 
                fixed2 uv : TEXCOORD0;
 
                half4 vertex : POSITION;
 
            };
 
            struct v2f
 
            {
 
                fixed2 uv : TEXCOORD0;
 
                half4 vertex : SV_POSITION;
 
            };
 
            v2f vert (a2v i)
 
            {
 
                v2f o;
 
                o.vertex = mul(UNITY_MATRIX_MVP, i.vertex);
 
                o.uv = i.uv;
 
                return o;
 
            }
 
 
 
            fixed4 frag (v2f i) : COLOR
 
            {
 
               //得到纹理贴图的纹理
               fixed4 mainColor = tex2D(_MainTex, i.uv);
               fixed realpha = 1-mainColor.a;
               //得到遮罩图的纹理
               half4 mask = tex2D(_Mask, i.uv);
 
               //得到纹理贴图的颜色
               fixed4 clothcolor = fixed4( mainColor.rgb * _Color, realpha);
               //纹理贴图rgb值*更改后的alpha值(通过遮罩找到需要更改的区域)
               clothcolor.rgb *= (mask.a * clothcolor.a);
 
               fixed4 logocolor = fixed4( mainColor.rgb, mainColor.a);
               logocolor.rgb *= (mask.a *logocolor.a);
 
               fixed4 skincolor = fixed4( mainColor.rgb*_SkinColor, realpha);
               skincolor.rgb *= ((1-mask.a)* skincolor.a);
 
               return fixed4(clothcolor.rgb+logocolor.rgb+skincolor.rgb,1.0);
 
            }
 
            ENDCG
 
        
   }  
 
}


四、       使用总结;

            这个shader主要是利用alpha通道,颜色叠加的原理来做的改变,在很多换色的功能中都能稍为变换一下方法就能利用,这样也可以直接绕过换整张贴图的方法,可以为我们的程序提升一些性能。

             如果有什么不太清楚的地方,或者一些延伸的问题都可以留言大家互相学习讨论!


如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引